From 67867c663593e60108d09310752e5758b291e6ce Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 20 Mar 2017 13:11:58 -0600 Subject: [PATCH 001/905] Update docs for std::str --- src/libcollections/str.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 90e54a383d62..40abc8a96f06 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -59,6 +59,27 @@ pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; +/// Unicode string slices. +/// +/// The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents +/// are borrowed and therefore cannot be moved someplace else. +/// +/// # Basic Usage +/// A basic string declaration of `&str` type: +/// +/// ``` +/// let hello_world = "Hello, World!"; +/// ``` +/// Here we have declared a string literal, also known as a string slice. +/// String literals have a static lifetime, which means the string `hello_world` +/// is guaranteed to be valid for the duration of the entire program. We can explicitly specify +/// `hello_world`'s lifetime as well: +/// +/// ``` +/// let hello_world:&'static str = "Hello, world!"; +/// ``` +/// + #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] From 63652726c39a0c018b7897f7c3e92690c3599207 Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 20 Mar 2017 15:21:28 -0600 Subject: [PATCH 002/905] Move str docs to proper place in file. --- src/libcollections/str.rs | 41 ++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 40abc8a96f06..c87e2b086add 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,9 +10,27 @@ //! Unicode string slices. //! +//! The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents +//! are borrowed and therefore cannot be moved someplace else. +//! +//! # Basic Usage +//! A basic string declaration of `&str` type: +//! +//! ``` +//! let hello_world = "Hello, World!"; +//! ``` +//! +//! Here we have declared a string literal, also known as a string slice. +//! String literals have a static lifetime, which means the string `hello_world` +//! is guaranteed to be valid for the duration of the entire program. We can explicitly specify +//! `hello_world`'s lifetime as well: +//! +//! ``` +//! let hello_world:&'static str = "Hello, world!"; +//! ``` +//! //! *[See also the `str` primitive type](../../std/primitive.str.html).* - #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -59,27 +77,6 @@ pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; -/// Unicode string slices. -/// -/// The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents -/// are borrowed and therefore cannot be moved someplace else. -/// -/// # Basic Usage -/// A basic string declaration of `&str` type: -/// -/// ``` -/// let hello_world = "Hello, World!"; -/// ``` -/// Here we have declared a string literal, also known as a string slice. -/// String literals have a static lifetime, which means the string `hello_world` -/// is guaranteed to be valid for the duration of the entire program. We can explicitly specify -/// `hello_world`'s lifetime as well: -/// -/// ``` -/// let hello_world:&'static str = "Hello, world!"; -/// ``` -/// - #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] From f628117529dfb117d87d62803d0746bedd6e0e83 Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 20 Mar 2017 20:20:12 -0600 Subject: [PATCH 003/905] Fix Rust linting error --- src/libcollections/str.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c87e2b086add..d4480ce77d64 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,8 +10,9 @@ //! Unicode string slices. //! -//! The `&str` type is one of the two main string types, the other being `String`. Unlike its `String` counterpart, its contents -//! are borrowed and therefore cannot be moved someplace else. +//! The `&str` type is one of the two main string types, the other being `String`. +//! Unlike its `String` counterpart, its contents are borrowed and therefore +//! cannot be moved someplace else. //! //! # Basic Usage //! A basic string declaration of `&str` type: @@ -22,8 +23,8 @@ //! //! Here we have declared a string literal, also known as a string slice. //! String literals have a static lifetime, which means the string `hello_world` -//! is guaranteed to be valid for the duration of the entire program. We can explicitly specify -//! `hello_world`'s lifetime as well: +//! is guaranteed to be valid for the duration of the entire program. +//! We can explicitly specify `hello_world`'s lifetime as well: //! //! ``` //! let hello_world:&'static str = "Hello, world!"; From 27151017e987044a35ae45f8c9bd8530af9e5f47 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Mar 2017 16:23:27 +0100 Subject: [PATCH 004/905] Add missing urls in ptr docs --- src/libstd/primitive_docs.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 7d6d16f47484..ba14a3d6b47e 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -183,9 +183,9 @@ mod prim_unit { } /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. /// -/// Use the `null` function to create null pointers, and the `is_null` method +/// Use the [`null`] function to create null pointers, and the [`is_null`] method /// of the `*const T` type to check for null. The `*const T` type also defines -/// the `offset` method, for pointer math. +/// the [`offset`] method, for pointer math. /// /// # Common ways to create raw pointers /// @@ -213,7 +213,7 @@ mod prim_unit { } /// /// ## 2. Consume a box (`Box`). /// -/// The `into_raw` function consumes a box and returns +/// The [`into_raw`] function consumes a box and returns /// the raw pointer. It doesn't destroy `T` or deallocate any memory. /// /// ``` @@ -227,7 +227,7 @@ mod prim_unit { } /// } /// ``` /// -/// Note that here the call to `drop` is for clarity - it indicates +/// Note that here the call to [`drop`] is for clarity - it indicates /// that we are done with the given value and it should be destroyed. /// /// ## 3. Get it from C. @@ -255,6 +255,11 @@ mod prim_unit { } /// /// *[See also the `std::ptr` module](ptr/index.html).* /// +/// [`null`]: ../std/ptr/fn.null.html +/// [`is_null`]: ../std/primitive.pointer.html#method.is_null +/// [`offset`]: ../std/primitive.pointer.html#method.offset +/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw +/// [`drop`]: ../std/mem/fn.drop.html #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer { } From d7d4e670ed53883672d8c4458226d91dcc731569 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 22 Mar 2017 00:01:37 +0100 Subject: [PATCH 005/905] Added core::cmp::Reverse for sort_by_key reverse sorting --- src/libcore/cmp.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index cb39796eecd7..d87615ad9a2c 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -322,6 +322,40 @@ impl Ordering { } } +/// A helper struct for reverse ordering. +/// +/// This struct is a helper to be used with functions like `Vec::sort_by_key` and +/// can be used to reverse order a part of a key. +/// +/// Example usage: +/// +/// ``` +/// use std::cmp::Reverse; +/// +/// let mut v = vec![1, 2, 3, 4, 5, 6]; +/// v.sort_by_key(|&num| (num >= 3, Reverse(num))); +/// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); +/// ``` +#[derive(PartialEq, Eq, Debug)] +#[stable(feature = "rust1", since = "1.8.0")] +pub struct Reverse(pub T); + +#[stable(feature = "rust1", since = "1.8.0")] +impl PartialOrd for Reverse { + #[inline] + fn partial_cmp(&self, other: &Reverse) -> Option { + other.0.partial_cmp(&self.0) + } +} + +#[stable(feature = "rust1", since = "1.8.0")] +impl Ord for Reverse { + #[inline] + fn cmp(&self, other: &Reverse) -> Ordering { + other.0.cmp(&self.0) + } +} + /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// /// An order is a total order if it is (for all `a`, `b` and `c`): From dabff151426d0cf6f8a779c15be459f7bd457a4c Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 22 Mar 2017 09:04:42 +0100 Subject: [PATCH 006/905] Fix the test for cmp::Reverse --- src/libcore/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index d87615ad9a2c..d787a0833c7a 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -333,7 +333,7 @@ impl Ordering { /// use std::cmp::Reverse; /// /// let mut v = vec![1, 2, 3, 4, 5, 6]; -/// v.sort_by_key(|&num| (num >= 3, Reverse(num))); +/// v.sort_by_key(|&num| (num > 3, Reverse(num))); /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` #[derive(PartialEq, Eq, Debug)] From dae66e000a974dd3bea7ae10b8827a5ece2b941e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 17 Mar 2017 22:36:21 -0700 Subject: [PATCH 007/905] Specialize Vec::from_iter for vec::IntoIter It's fairly common to expose an API which takes an `IntoIterator` and immediately collects that into a vector. It's also common to buffer a bunch of items into a vector and then pass that into one of these APIs. If the iterator hasn't been advanced, we can make this `from_iter` simply reassemble the original `Vec` with no actual iteration or reallocation. --- src/libcollections/vec.rs | 29 +++++++++++++++++++++++++---- src/libcollectionstest/vec.rs | 16 ++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 7b408af13aa2..56b60a3e0034 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1563,7 +1563,7 @@ impl ops::DerefMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - >::from_iter(iter.into_iter()) + >::from_iter(iter.into_iter()) } } @@ -1631,7 +1631,7 @@ impl<'a, T> IntoIterator for &'a mut Vec { impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { - self.spec_extend(iter.into_iter()) + >::spec_extend(self, iter.into_iter()) } } @@ -1662,7 +1662,7 @@ impl SpecExtend for Vec vector } }; - vector.spec_extend(iterator); + as SpecExtend>::spec_extend(&mut vector, iterator); vector } @@ -1674,7 +1674,7 @@ impl SpecExtend for Vec impl SpecExtend for Vec where I: TrustedLen, { - fn from_iter(iterator: I) -> Self { + default fn from_iter(iterator: I) -> Self { let mut vector = Vec::new(); vector.spec_extend(iterator); vector @@ -1706,6 +1706,27 @@ impl SpecExtend for Vec } } +impl SpecExtend> for Vec { + fn from_iter(iterator: IntoIter) -> Self { + // A common case is passing a vector into a function which immediately + // re-collects into a vector. We can short circuit this if the IntoIter + // has not been advanced at all. + if *iterator.buf == iterator.ptr as *mut T { + unsafe { + let vec = Vec::from_raw_parts(*iterator.buf as *mut T, + iterator.len(), + iterator.cap); + mem::forget(iterator); + vec + } + } else { + let mut vector = Vec::new(); + vector.spec_extend(iterator); + vector + } + } +} + impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index 06d70800d392..63df0eb73050 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -680,3 +680,19 @@ fn test_placement_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]; + let ptr = vec.as_ptr(); + let vec = vec.into_iter().collect::>(); + assert_eq!(vec, [1, 2, 3]); + assert_eq!(vec.as_ptr(), ptr); + + let ptr = &vec[1] as *const _; + let mut it = vec.into_iter(); + it.next().unwrap(); + let vec = it.collect::>(); + assert_eq!(vec, [2, 3]); + assert!(ptr != vec.as_ptr()); +} From 1ae1a19ba6156479969f493c8e05871539e69b52 Mon Sep 17 00:00:00 2001 From: Adam Ransom Date: Tue, 21 Mar 2017 21:35:57 +0900 Subject: [PATCH 008/905] Refactor checking if a `Lifetime` is static Simply move the test for `keywords::StaticLifetime` into the `Lifetime` impl, to match how elision is checked. --- src/librustc/hir/mod.rs | 4 ++++ src/librustc/middle/resolve_lifetime.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index edcfcffaa03a..8239fd7d13c1 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -100,6 +100,10 @@ impl Lifetime { pub fn is_elided(&self) -> bool { self.name == keywords::Invalid.name() } + + pub fn is_static(&self) -> bool { + self.name == keywords::StaticLifetime.name() + } } /// A lifetime definition, eg `'a: 'b+'c+'d` diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 37749816eb15..10ee760a6a61 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -434,7 +434,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.resolve_elided_lifetimes(slice::ref_slice(lifetime_ref)); return; } - if lifetime_ref.name == keywords::StaticLifetime.name() { + if lifetime_ref.is_static() { self.insert_lifetime(lifetime_ref, Region::Static); return; } @@ -1434,7 +1434,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let lifetime_i = &lifetimes[i]; for lifetime in lifetimes { - if lifetime.lifetime.name == keywords::StaticLifetime.name() { + if lifetime.lifetime.is_static() { let lifetime = lifetime.lifetime; let mut err = struct_span_err!(self.sess, lifetime.span, E0262, "invalid lifetime parameter name: `{}`", lifetime.name); From d005d917783b8f753b4ee2f79f03e2212e519d01 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 22 Mar 2017 14:16:41 +0100 Subject: [PATCH 009/905] Improved bounds for cmp::Reverse --- src/libcore/cmp.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index d787a0833c7a..751932a6105a 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -337,19 +337,19 @@ impl Ordering { /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` #[derive(PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.8.0")] -pub struct Reverse(pub T); +#[stable(feature = "rust1", since = "1.18.0")] +pub struct Reverse(pub T); -#[stable(feature = "rust1", since = "1.8.0")] -impl PartialOrd for Reverse { +#[stable(feature = "rust1", since = "1.18.0")] +impl PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { other.0.partial_cmp(&self.0) } } -#[stable(feature = "rust1", since = "1.8.0")] -impl Ord for Reverse { +#[stable(feature = "rust1", since = "1.18.0")] +impl Ord for Reverse { #[inline] fn cmp(&self, other: &Reverse) -> Ordering { other.0.cmp(&self.0) From 2f0dd63bbe83938b9eda5b6076543d420bae2f2b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 18:36:43 +0200 Subject: [PATCH 010/905] Checked (and unchecked) slicing for strings? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What is this magicβ€½ --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 8 +- src/libcollections/str.rs | 110 +++++++++++- src/libcore/slice/mod.rs | 52 +++--- src/libcore/str/mod.rs | 326 +++++++++++++++++++++++++++++++++--- 5 files changed, 441 insertions(+), 56 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 72e950bc91fa..00448b6abb2c 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -60,6 +60,7 @@ #![feature(unicode)] #![feature(unique)] #![feature(untagged_unions)] +#![cfg_attr(not(test), feature(str_checked_slicing))] #![cfg_attr(test, feature(rand, test))] #![no_std] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 5233887620a9..424e175996ec 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -362,7 +362,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get(self, index) } @@ -385,7 +385,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_mut(self, index) } @@ -405,7 +405,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked(self, index) } @@ -427,7 +427,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked_mut(self, index) } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 90e54a383d62..84b73090817d 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -32,7 +32,7 @@ use borrow::{Borrow, ToOwned}; use string::String; use std_unicode; use vec::Vec; -use slice::SliceConcatExt; +use slice::{SliceConcatExt, SliceIndex}; use boxed::Box; #[stable(feature = "rust1", since = "1.0.0")] @@ -291,6 +291,114 @@ impl str { 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. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let v = "πŸ—»βˆˆπŸŒ"; + /// assert_eq!(Some("πŸ—»"), v.get(0..4)); + /// assert!(v.get(1..).is_none()); + /// assert!(v.get(..8).is_none()); + /// assert!(v.get(..42).is_none()); + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "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. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let mut v = String::from("πŸ—»βˆˆπŸŒ"); + /// assert_eq!(Some("πŸ—»"), v.get_mut(0..4).map(|v| &*v)); + /// assert!(v.get_mut(1..).is_none()); + /// assert!(v.get_mut(..8).is_none()); + /// assert!(v.get_mut(..42).is_none()); + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "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 + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let v = "πŸ—»βˆˆπŸŒ"; + /// unsafe { + /// assert_eq!("πŸ—»", v.get_unchecked(0..4)); + /// assert_eq!("∈", v.get_unchecked(4..7)); + /// assert_eq!("🌏", v.get_unchecked(7..11)); + /// } + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "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 + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// 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)); + /// } + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "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. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6f8b199f886b..4e56fa80cd9c 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -97,8 +97,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn first(&self) -> Option<&Self::Item>; @@ -113,8 +112,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_ptr(&self) -> *const Self::Item; @@ -141,8 +139,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn iter_mut(&mut self) -> IterMut; @@ -184,8 +181,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_mut_ptr(&mut self) -> *mut Self::Item; @@ -337,7 +333,7 @@ impl SliceExt for [T] { #[inline] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get(self) } @@ -365,7 +361,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked(self) } @@ -406,7 +402,7 @@ impl SliceExt for [T] { #[inline] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_mut(self) } @@ -538,7 +534,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked_mut(self) } @@ -631,7 +627,7 @@ impl SliceExt for [T] { #[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] - where I: SliceIndex + where I: SliceIndex<[T]> { type Output = I::Output; @@ -644,7 +640,7 @@ impl ops::Index for [T] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut for [T] - where I: SliceIndex + where I: SliceIndex<[T]> { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -667,37 +663,37 @@ fn slice_index_order_fail(index: usize, end: 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`"] -pub trait SliceIndex { +pub trait SliceIndex { /// The output type returned by methods. type Output: ?Sized; /// Returns a shared reference to the output at this location, if in /// bounds. - fn get(self, slice: &[T]) -> Option<&Self::Output>; + fn get(self, slice: &T) -> Option<&Self::Output>; /// Returns a mutable reference to the output at this location, if in /// bounds. - fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output>; + 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. - unsafe fn get_unchecked(self, slice: &[T]) -> &Self::Output; + unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, without /// performing any bounds checking. - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut Self::Output; + 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. - fn index(self, slice: &[T]) -> &Self::Output; + fn index(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, panicking /// if out of bounds. - fn index_mut(self, slice: &mut [T]) -> &mut Self::Output; + fn index_mut(self, slice: &mut T) -> &mut Self::Output; } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for usize { +impl SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -746,7 +742,7 @@ impl SliceIndex for usize { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::Range { +impl SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -807,7 +803,7 @@ impl SliceIndex for ops::Range { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeTo { +impl SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -842,7 +838,7 @@ impl SliceIndex for ops::RangeTo { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFrom { +impl SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -877,7 +873,7 @@ impl SliceIndex for ops::RangeFrom { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFull { +impl SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -913,7 +909,7 @@ impl SliceIndex for ops::RangeFull { #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeInclusive { +impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -976,7 +972,7 @@ impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeToInclusive { +impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index cf3e8a684dfa..aecfaa7ee023 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -22,7 +22,7 @@ use convert::TryFrom; use fmt; use iter::{Map, Cloned, FusedIterator}; use mem; -use slice; +use slice::{self, SliceIndex}; pub mod pattern; @@ -1408,6 +1408,8 @@ Section: Trait implementations mod traits { use cmp::Ordering; use ops; + use mem; + use slice::{self, SliceIndex}; use str::eq_slice; /// Implements ordering of strings. @@ -1490,14 +1492,7 @@ mod traits { type Output = str; #[inline] fn index(&self, index: ops::Range) -> &str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index(self) } } @@ -1519,14 +1514,7 @@ mod traits { impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::Range) -> &mut str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_mut_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index_mut(self) } } @@ -1694,8 +1682,276 @@ mod traits { self.index_mut(0...index.end) } } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeFull { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + Some(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + Some(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::Range { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, self.end); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] + // canot reuse `get` as above, because of NLL trouble + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeTo { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[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)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr(); + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeFrom { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, slice.len()); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.start) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, slice.len()) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_mut(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked(slice) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked_mut(slice) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index_mut(slice) + } + } + + + + #[unstable(feature = "str_checked_slicing", issue = "0")] + impl SliceIndex for ops::RangeToInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[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)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr(); + mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end + 1; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end + 1) + } + } + } + } + /// Methods for string slices #[allow(missing_docs)] #[doc(hidden)] @@ -1745,6 +2001,14 @@ pub trait StrExt { #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] #[allow(deprecated)] fn lines_any(&self) -> LinesAny; + #[unstable(feature = "str_checked_slicing", issue = "0")] + fn get>(&self, i: I) -> Option<&I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "0")] + fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "0")] + unsafe fn get_unchecked>(&self, i: I) -> &I::Output; + #[unstable(feature = "str_checked_slicing", issue = "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")] @@ -1934,18 +2198,34 @@ impl StrExt for str { 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 { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + (begin..end).get_unchecked(self) } #[inline] unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + (begin..end).get_unchecked_mut(self) } #[inline] From 99e4c0ad8b0c2e551e7ef0db60b8a2b84f35c1ee Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 18:39:41 +0200 Subject: [PATCH 011/905] Tracking issue numbers --- src/libcollections/str.rs | 8 ++++---- src/libcore/str/mod.rs | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 84b73090817d..4fe2b826c96f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -306,7 +306,7 @@ impl str { /// assert!(v.get(..8).is_none()); /// assert!(v.get(..42).is_none()); /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub fn get>(&self, i: I) -> Option<&I::Output> { core_str::StrExt::get(self, i) @@ -327,7 +327,7 @@ impl str { /// assert!(v.get_mut(..8).is_none()); /// assert!(v.get_mut(..42).is_none()); /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { core_str::StrExt::get_mut(self, i) @@ -360,7 +360,7 @@ impl str { /// assert_eq!("🌏", v.get_unchecked(7..11)); /// } /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { core_str::StrExt::get_unchecked(self, i) @@ -393,7 +393,7 @@ impl str { /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); /// } /// ``` - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { core_str::StrExt::get_unchecked_mut(self, i) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index aecfaa7ee023..b6c421ecd320 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1683,7 +1683,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeFull { type Output = str; #[inline] @@ -1712,7 +1712,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::Range { type Output = str; #[inline] @@ -1766,7 +1766,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeTo { type Output = str; #[inline] @@ -1810,7 +1810,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeFrom { type Output = str; #[inline] @@ -1856,7 +1856,7 @@ mod traits { } } - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] @@ -1905,7 +1905,7 @@ mod traits { - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] @@ -2001,13 +2001,13 @@ pub trait StrExt { #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] #[allow(deprecated)] fn lines_any(&self) -> LinesAny; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] fn get>(&self, i: I) -> Option<&I::Output>; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] unsafe fn get_unchecked>(&self, i: I) -> &I::Output; - #[unstable(feature = "str_checked_slicing", issue = "0")] + #[unstable(feature = "str_checked_slicing", issue = "39932")] 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; From 53a36923f12d6c9b7ef9cb0fe73cda50385b1f70 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 22:02:42 +0200 Subject: [PATCH 012/905] Fix the tests --- src/test/compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-indexing.rs | 8 ++++---- src/test/compile-fail/on-unimplemented/slice-index.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index 1889d76c03c0..624944f7344c 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: T) {} - [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<{integer}>` is not satisfied + [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<[{integer}]>` is not satisfied [0][0]; // should infer to be a usize diff --git a/src/test/compile-fail/integral-indexing.rs b/src/test/compile-fail/integral-indexing.rs index 1815d0e978a9..659b08b55a00 100644 --- a/src/test/compile-fail/integral-indexing.rs +++ b/src/test/compile-fail/integral-indexing.rs @@ -19,8 +19,8 @@ pub fn main() { v[3i32]; //~ERROR : std::ops::Index` is not satisfied s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex` is not satisfied - s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex` is not satisfied + s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied + s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied } diff --git a/src/test/compile-fail/on-unimplemented/slice-index.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index d28b823ddc14..1a9ed2dd6e4d 100644 --- a/src/test/compile-fail/on-unimplemented/slice-index.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -20,10 +20,10 @@ fn main() { let x = &[1, 2, 3] as &[i32]; x[1i32]; //~ ERROR E0277 //~| NOTE slice indices are of type `usize` or ranges of `usize` - //~| NOTE trait `std::slice::SliceIndex` is not implemented for `i32` + //~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32` //~| NOTE required because of the requirements on the impl of `std::ops::Index` x[..1i32]; //~ ERROR E0277 //~| NOTE slice indices are of type `usize` or ranges of `usize` - //~| NOTE trait `std::slice::SliceIndex` is not implemented for `std::ops::RangeTo` + //~| NOTE trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo` //~| NOTE requirements on the impl of `std::ops::Index>` } From c5a9f1f3f6d36d6e48586d16fdc3a69e9c75781a Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Wed, 22 Mar 2017 13:39:17 -0400 Subject: [PATCH 013/905] Basic documentation for inclusive range syntax --- src/doc/unstable-book/src/inclusive-range-syntax.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/doc/unstable-book/src/inclusive-range-syntax.md b/src/doc/unstable-book/src/inclusive-range-syntax.md index 74d85536399d..255445c318dc 100644 --- a/src/doc/unstable-book/src/inclusive-range-syntax.md +++ b/src/doc/unstable-book/src/inclusive-range-syntax.md @@ -6,5 +6,15 @@ The tracking issue for this feature is: [#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); + } +} +``` From 3ec61ea921a0090e97d3ec6a306561c8c6bacc91 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 23 Mar 2017 16:32:49 +1300 Subject: [PATCH 014/905] save-analysis: allow clients to get data directly without writing to a file --- src/librustc_driver/driver.rs | 5 +- src/librustc_driver/lib.rs | 6 +- src/librustc_save_analysis/json_dumper.rs | 50 ++++-- src/librustc_save_analysis/lib.rs | 181 +++++++++++++++------- 4 files changed, 167 insertions(+), 75 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2126a5a7c71b..10a92d8c3a5f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -250,10 +250,7 @@ fn keep_hygiene_data(sess: &Session) -> bool { } fn keep_ast(sess: &Session) -> bool { - sess.opts.debugging_opts.keep_ast || - sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv || - sess.opts.debugging_opts.save_analysis_api + sess.opts.debugging_opts.keep_ast || ::save_analysis(sess) } /// The name used for source code that doesn't originate in a file diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 62d751265572..f05bcd778099 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -66,6 +66,7 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_save_analysis as save; +use rustc_save_analysis::DumpHandler; use rustc_trans::back::link; use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS}; use rustc::dep_graph::DepGraph; @@ -506,8 +507,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { state.expanded_crate.unwrap(), state.analysis.unwrap(), state.crate_name.unwrap(), - state.out_dir, - save_analysis_format(state.session)) + DumpHandler::new(save_analysis_format(state.session), + state.out_dir, + state.crate_name.unwrap())) }); }; control.after_analysis.run_callback_on_error = true; diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index acc877d39477..2d1e12bf0a10 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -22,22 +22,52 @@ use external_data::*; use data::{self, VariableKind}; use dump::Dump; -pub struct JsonDumper<'b, W: Write + 'b> { - output: &'b mut W, +pub struct JsonDumper { result: Analysis, + output: O, } -impl<'b, W: Write> JsonDumper<'b, W> { - pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> { - JsonDumper { output: writer, result: Analysis::new() } +pub trait DumpOutput { + fn dump(&mut self, result: &Analysis); +} + +pub struct WriteOutput<'b, W: Write + 'b> { + output: &'b mut W, +} + +impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> { + fn dump(&mut self, result: &Analysis) { + if let Err(_) = write!(self.output, "{}", as_json(&result)) { + error!("Error writing output"); + } } } -impl<'b, W: Write> Drop for JsonDumper<'b, W> { +pub struct CallbackOutput<'b> { + callback: &'b mut FnMut(&Analysis), +} + +impl<'b> DumpOutput for CallbackOutput<'b> { + fn dump(&mut self, result: &Analysis) { + (self.callback)(result) + } +} + +impl<'b, W: Write> JsonDumper> { + pub fn new(writer: &'b mut W) -> JsonDumper> { + JsonDumper { output: WriteOutput { output: writer }, result: Analysis::new() } + } +} + +impl<'b> JsonDumper> { + pub fn with_callback(callback: &'b mut FnMut(&Analysis)) -> JsonDumper> { + JsonDumper { output: CallbackOutput { callback: callback }, result: Analysis::new() } + } +} + +impl Drop for JsonDumper { fn drop(&mut self) { - if let Err(_) = write!(self.output, "{}", as_json(&self.result)) { - error!("Error writing output"); - } + self.output.dump(&self.result); } } @@ -49,7 +79,7 @@ macro_rules! impl_fn { } } -impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { +impl<'b, O: DumpOutput + 'b> Dump for JsonDumper { fn crate_prelude(&mut self, data: CratePreludeData) { self.result.prelude = Some(data) } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 5e2b1df9d34f..e5c04f6b61ec 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -48,6 +48,7 @@ use rustc::hir::def::Def; use rustc::hir::map::Node; use rustc::hir::def_id::DefId; use rustc::session::config::CrateType::CrateTypeExecutable; +use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use std::env; @@ -866,56 +867,132 @@ impl Format { } } -pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, - krate: &ast::Crate, - analysis: &'l ty::CrateAnalysis, - cratename: &str, - odir: Option<&Path>, - format: Format) { +/// Defines what to do with the results of saving the analysis. +pub trait SaveHandler { + fn save<'l, 'tcx>(&mut self, + save_ctxt: SaveContext<'l, 'tcx>, + krate: &ast::Crate, + cratename: &str); +} + +/// Dump the save-analysis results to a file. +pub struct DumpHandler<'a> { + format: Format, + odir: Option<&'a Path>, + cratename: String +} + +impl<'a> DumpHandler<'a> { + pub fn new(format: Format, odir: Option<&'a Path>, cratename: &str) -> DumpHandler<'a> { + DumpHandler { + format: format, + odir: odir, + cratename: cratename.to_owned() + } + } + + fn output_file(&self, sess: &Session) -> File { + let mut root_path = match env::var_os("RUST_SAVE_ANALYSIS_FOLDER") { + Some(val) => PathBuf::from(val), + None => match self.odir { + Some(val) => val.join("save-analysis"), + None => PathBuf::from("save-analysis-temp"), + }, + }; + + if let Err(e) = std::fs::create_dir_all(&root_path) { + error!("Could not create directory {}: {}", root_path.display(), e); + } + + { + let disp = root_path.display(); + info!("Writing output to {}", disp); + } + + let executable = sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable); + let mut out_name = if executable { + "".to_owned() + } else { + "lib".to_owned() + }; + out_name.push_str(&self.cratename); + out_name.push_str(&sess.opts.cg.extra_filename); + out_name.push_str(self.format.extension()); + root_path.push(&out_name); + let output_file = File::create(&root_path).unwrap_or_else(|e| { + let disp = root_path.display(); + sess.fatal(&format!("Could not open {}: {}", disp, e)); + }); + root_path.pop(); + output_file + } +} + +impl<'a> SaveHandler for DumpHandler<'a> { + fn save<'l, 'tcx>(&mut self, + save_ctxt: SaveContext<'l, 'tcx>, + krate: &ast::Crate, + cratename: &str) { + macro_rules! dump { + ($new_dumper: expr) => {{ + let mut dumper = $new_dumper; + let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); + + visitor.dump_crate_info(cratename, krate); + visit::walk_crate(&mut visitor, krate); + }} + } + + let output = &mut self.output_file(&save_ctxt.tcx.sess); + + match self.format { + Format::Csv => dump!(CsvDumper::new(output)), + Format::Json => dump!(JsonDumper::new(output)), + Format::JsonApi => dump!(JsonApiDumper::new(output)), + } + } +} + +/// Call a callback with the results of save-analysis. +pub struct CallbackHandler<'b> { + pub callback: &'b mut FnMut(&rls_data::Analysis), +} + +impl<'b> SaveHandler for CallbackHandler<'b> { + fn save<'l, 'tcx>(&mut self, + save_ctxt: SaveContext<'l, 'tcx>, + krate: &ast::Crate, + cratename: &str) { + macro_rules! dump { + ($new_dumper: expr) => {{ + let mut dumper = $new_dumper; + let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); + + visitor.dump_crate_info(cratename, krate); + visit::walk_crate(&mut visitor, krate); + }} + } + + // We're using the JsonDumper here because it has the format of the + // save-analysis results that we will pass to the callback. IOW, we are + // using the JsonDumper to collect the save-analysis results, but not + // actually to dump them to a file. This is all a bit convoluted and + // there is certainly a simpler design here trying to get out (FIXME). + dump!(JsonDumper::with_callback(self.callback)) + } +} + +pub fn process_crate<'l, 'tcx, H: SaveHandler>(tcx: TyCtxt<'l, 'tcx, 'tcx>, + krate: &ast::Crate, + analysis: &'l ty::CrateAnalysis, + cratename: &str, + mut handler: H) { let _ignore = tcx.dep_graph.in_ignore(); assert!(analysis.glob_map.is_some()); info!("Dumping crate {}", cratename); - // find a path to dump our data to - let mut root_path = match env::var_os("RUST_SAVE_ANALYSIS_FOLDER") { - Some(val) => PathBuf::from(val), - None => match odir { - Some(val) => val.join("save-analysis"), - None => PathBuf::from("save-analysis-temp"), - }, - }; - - if let Err(e) = std::fs::create_dir_all(&root_path) { - tcx.sess.err(&format!("Could not create directory {}: {}", - root_path.display(), - e)); - } - - { - let disp = root_path.display(); - info!("Writing output to {}", disp); - } - - // Create output file. - let executable = tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateTypeExecutable); - let mut out_name = if executable { - "".to_owned() - } else { - "lib".to_owned() - }; - out_name.push_str(&cratename); - out_name.push_str(&tcx.sess.opts.cg.extra_filename); - out_name.push_str(format.extension()); - root_path.push(&out_name); - let mut output_file = File::create(&root_path).unwrap_or_else(|e| { - let disp = root_path.display(); - tcx.sess.fatal(&format!("Could not open {}: {}", disp, e)); - }); - root_path.pop(); - let output = &mut output_file; - let save_ctxt = SaveContext { tcx: tcx, tables: &ty::TypeckTables::empty(), @@ -923,21 +1000,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, span_utils: SpanUtils::new(&tcx.sess), }; - macro_rules! dump { - ($new_dumper: expr) => {{ - let mut dumper = $new_dumper; - let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper); - - visitor.dump_crate_info(cratename, krate); - visit::walk_crate(&mut visitor, krate); - }} - } - - match format { - Format::Csv => dump!(CsvDumper::new(output)), - Format::Json => dump!(JsonDumper::new(output)), - Format::JsonApi => dump!(JsonApiDumper::new(output)), - } + handler.save(save_ctxt, krate, cratename) } // Utility functions for the module. From 5ca8a735ca36219abbf601624606c41148b95210 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Mar 2017 22:27:12 -0700 Subject: [PATCH 015/905] std: Don't cache stdio handles on Windows This alters the stdio code on Windows to always call `GetStdHandle` whenever the stdio read/write functions are called as this allows us to track changes to the value over time (such as if a process calls `SetStdHandle` while it's running). Closes #40490 --- src/libstd/sys/windows/process.rs | 9 +- src/libstd/sys/windows/stdio.rs | 92 +++++++++------------ src/test/run-pass-fulldeps/switch-stdout.rs | 64 ++++++++++++++ 3 files changed, 110 insertions(+), 55 deletions(-) create mode 100644 src/test/run-pass-fulldeps/switch-stdout.rs diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 1afb3728c9d7..dfbc1b581ee5 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -257,8 +257,13 @@ impl Stdio { // INVALID_HANDLE_VALUE. Stdio::Inherit => { match stdio::get(stdio_id) { - Ok(io) => io.handle().duplicate(0, true, - c::DUPLICATE_SAME_ACCESS), + Ok(io) => { + let io = Handle::new(io.handle()); + let ret = io.duplicate(0, true, + c::DUPLICATE_SAME_ACCESS); + io.into_raw(); + return ret + } Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), } } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b1a57c349fbb..d72e4b4438b7 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -22,42 +22,43 @@ use sys::cvt; use sys::handle::Handle; use sys_common::io::read_to_end_uninitialized; -pub struct NoClose(Option); - pub enum Output { - Console(NoClose), - Pipe(NoClose), + Console(c::HANDLE), + Pipe(c::HANDLE), } pub struct Stdin { - handle: Output, utf8: Mutex>>, } -pub struct Stdout(Output); -pub struct Stderr(Output); +pub struct Stdout; +pub struct Stderr; pub fn get(handle: c::DWORD) -> io::Result { let handle = unsafe { c::GetStdHandle(handle) }; if handle == c::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else if handle.is_null() { - Err(io::Error::new(io::ErrorKind::Other, - "no stdio handle available for this process")) + Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) } else { - let ret = NoClose::new(handle); let mut out = 0; match unsafe { c::GetConsoleMode(handle, &mut out) } { - 0 => Ok(Output::Pipe(ret)), - _ => Ok(Output::Console(ret)), + 0 => Ok(Output::Pipe(handle)), + _ => Ok(Output::Console(handle)), } } } -fn write(out: &Output, data: &[u8]) -> io::Result { - let handle = match *out { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().write(data), +fn write(handle: c::DWORD, data: &[u8]) -> io::Result { + let handle = match try!(get(handle)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.write(data); + handle.into_raw(); + return ret + } }; + // As with stdin on windows, stdout often can't handle writes of large // sizes. For an example, see #14940. For this reason, don't try to // write the entire output buffer on windows. @@ -93,18 +94,20 @@ fn write(out: &Output, data: &[u8]) -> io::Result { impl Stdin { pub fn new() -> io::Result { - get(c::STD_INPUT_HANDLE).map(|handle| { - Stdin { - handle: handle, - utf8: Mutex::new(Cursor::new(Vec::new())), - } + Ok(Stdin { + utf8: Mutex::new(Cursor::new(Vec::new())), }) } pub fn read(&self, buf: &mut [u8]) -> io::Result { - let handle = match self.handle { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().read(buf), + let handle = match try!(get(c::STD_INPUT_HANDLE)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.read(buf); + handle.into_raw(); + return ret + } }; let mut utf8 = self.utf8.lock().unwrap(); // Read more if the buffer is empty @@ -125,11 +128,9 @@ impl Stdin { Ok(utf8) => utf8.into_bytes(), Err(..) => return Err(invalid_encoding()), }; - if let Output::Console(_) = self.handle { - if let Some(&last_byte) = data.last() { - if last_byte == CTRL_Z { - data.pop(); - } + if let Some(&last_byte) = data.last() { + if last_byte == CTRL_Z { + data.pop(); } } *utf8 = Cursor::new(data); @@ -158,11 +159,11 @@ impl<'a> Read for &'a Stdin { impl Stdout { pub fn new() -> io::Result { - get(c::STD_OUTPUT_HANDLE).map(Stdout) + Ok(Stdout) } pub fn write(&self, data: &[u8]) -> io::Result { - write(&self.0, data) + write(c::STD_OUTPUT_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -172,11 +173,11 @@ impl Stdout { impl Stderr { pub fn new() -> io::Result { - get(c::STD_ERROR_HANDLE).map(Stderr) + Ok(Stderr) } pub fn write(&self, data: &[u8]) -> io::Result { - write(&self.0, data) + write(c::STD_ERROR_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -197,27 +198,12 @@ impl io::Write for Stderr { } } -impl NoClose { - fn new(handle: c::HANDLE) -> NoClose { - NoClose(Some(Handle::new(handle))) - } - - fn get(&self) -> &Handle { self.0.as_ref().unwrap() } -} - -impl Drop for NoClose { - fn drop(&mut self) { - self.0.take().unwrap().into_raw(); - } -} - impl Output { - pub fn handle(&self) -> &Handle { - let nc = match *self { - Output::Console(ref c) => c, - Output::Pipe(ref c) => c, - }; - nc.0.as_ref().unwrap() + pub fn handle(&self) -> c::HANDLE { + match *self { + Output::Console(c) => c, + Output::Pipe(c) => c, + } } } diff --git a/src/test/run-pass-fulldeps/switch-stdout.rs b/src/test/run-pass-fulldeps/switch-stdout.rs new file mode 100644 index 000000000000..4542e27545a4 --- /dev/null +++ b/src/test/run-pass-fulldeps/switch-stdout.rs @@ -0,0 +1,64 @@ +// 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. + +#![feature(rustc_private)] + +extern crate rustc_back; + +use std::fs::File; +use std::io::{Read, Write}; + +use rustc_back::tempdir::TempDir; + +#[cfg(unix)] +fn switch_stdout_to(file: File) { + use std::os::unix::prelude::*; + + extern { + fn dup2(old: i32, new: i32) -> i32; + } + + unsafe { + assert_eq!(dup2(file.as_raw_fd(), 1), 1); + } +} + +#[cfg(windows)] +fn switch_stdout_to(file: File) { + use std::os::windows::prelude::*; + + extern "system" { + fn SetStdHandle(nStdHandle: u32, handle: *mut u8) -> i32; + } + + const STD_OUTPUT_HANDLE: u32 = (-11i32) as u32; + + unsafe { + let rc = SetStdHandle(STD_OUTPUT_HANDLE, + file.into_raw_handle() as *mut _); + assert!(rc != 0); + } +} + +fn main() { + let td = TempDir::new("foo").unwrap(); + let path = td.path().join("bar"); + let f = File::create(&path).unwrap(); + + println!("foo"); + std::io::stdout().flush().unwrap(); + switch_stdout_to(f); + println!("bar"); + std::io::stdout().flush().unwrap(); + + let mut contents = String::new(); + File::open(&path).unwrap().read_to_string(&mut contents).unwrap(); + assert_eq!(contents, "bar\n"); +} From 4dc122580714a5f8859e993bf56a7228b0bcd7c1 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:17:21 -0400 Subject: [PATCH 016/905] Add helpful hint on io function for beginners --- src/libstd/io/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 850885a8c0f3..dda9d6bca797 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -144,6 +144,16 @@ //! # Ok(()) //! # } //! ``` +//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main()`). +//! Instead, you can `match` on the return value to catch any possible errors: +//! +//! ``` +//! let mut input = String::new(); +//! match io::stdin().read_line(&mut input) { +//! Err(why) => panic!("Failed to read input: {}", why.description()), +//! Ok(_) => println!("You typed: {}", input.trim()), +//! } +//! ``` //! //! And a very common source of output is standard output: //! From 1a87fc2635660bbf2947c17901dbd7dec75a63cb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 16:17:45 -0400 Subject: [PATCH 017/905] convert `custom_coerce_unsized_kind` into a `coerce_unsized_info` This "on-demand" task both checks for errors and computes the custom unsized kind, if any. This task is only defined on impls of `CoerceUnsized`; invoking it on any other kind of impl results in a bug. This is just to avoid having an `Option`, could easily be changed. --- src/librustc/ty/adjustment.rs | 15 ++++++++ src/librustc/ty/maps.rs | 4 +-- src/librustc/ty/mod.rs | 4 +-- src/librustc_metadata/cstore_impl.rs | 6 ++-- src/librustc_metadata/decoder.rs | 8 ++--- src/librustc_metadata/encoder.rs | 18 +++++++--- src/librustc_metadata/schema.rs | 4 ++- src/librustc_trans/monomorphize.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 46 ++++++++++++++++-------- src/librustc_typeck/coherence/mod.rs | 3 ++ 10 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 34977822bc69..d8ca30477205 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -139,6 +139,21 @@ pub enum AutoBorrow<'tcx> { RawPtr(hir::Mutability), } +/// Information for `CoerceUnsized` impls, storing information we +/// have computed about the coercion. +/// +/// This struct can be obtained via the `coerce_impl_info` query. +/// Demanding this struct also has the side-effect of reporting errors +/// for inappropriate impls. +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub struct CoerceUnsizedInfo { + /// If this is a "custom coerce" impl, then what kind of custom + /// coercion is it? This applies to impls of `CoerceUnsized` for + /// structs, primarily, where we store a bit of info about which + /// fields need to be coerced. + pub custom_kind: Option +} + #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub enum CustomCoerceUnsized { /// Records the index of the field being coerced. diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ac8c38c7d585..d4214dc429ce 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -393,8 +393,8 @@ define_maps! { <'tcx> pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>, /// Caches CoerceUnsized kinds for impls on custom types. - pub custom_coerce_unsized_kind: ItemSignature(DefId) - -> ty::adjustment::CustomCoerceUnsized, + pub coerce_unsized_info: ItemSignature(DefId) + -> ty::adjustment::CoerceUnsizedInfo, pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36d1ae74e911..d14042699581 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2054,8 +2054,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized { - queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did) + pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo { + queries::coerce_unsized_info::get(self, DUMMY_SP, did) } pub fn associated_item(self, def_id: DefId) -> AssociatedItem { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2a67b79eaa52..7cac201f14f7 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -88,9 +88,9 @@ provide! { <'tcx> tcx, def_id, cdata } associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } - custom_coerce_unsized_kind => { - cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| { - bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id); + coerce_unsized_info => { + cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { + bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); }) } mir => { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6ccdf8092f21..3de1e3442c69 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -643,10 +643,10 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).polarity } - pub fn get_custom_coerce_unsized_kind(&self, - id: DefIndex) - -> Option { - self.get_impl_data(id).coerce_unsized_kind + pub fn get_coerce_unsized_info(&self, + id: DefIndex) + -> Option { + self.get_impl_data(id).coerce_unsized_info } pub fn get_impl_trait(&self, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 044ed529ef74..5bc84759f879 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -695,7 +695,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ImplData { polarity: hir::ImplPolarity::Positive, parent_impl: None, - coerce_unsized_kind: None, + coerce_unsized_info: None, trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), }; @@ -715,13 +715,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None }; + // if this is an impl of `CoerceUnsized`, create its + // "unsized info", else just store None + let coerce_unsized_info = + trait_ref.and_then(|t| { + if Some(t.def_id) == tcx.lang_items.coerce_unsized_trait() { + Some(ty::queries::coerce_unsized_info::get(tcx, item.span, def_id)) + } else { + None + } + }); + let data = ImplData { polarity: polarity, parent_impl: parent, - coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind - .borrow() - .get(&def_id) - .cloned(), + coerce_unsized_info: coerce_unsized_info, trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), }; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 4a20913d0b3f..abb482a50ebc 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -285,7 +285,9 @@ pub struct TraitData<'tcx> { pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, pub parent_impl: Option, - pub coerce_unsized_kind: Option, + + /// This is `Some` only for impls of `CoerceUnsized`. + pub coerce_unsized_info: Option, pub trait_ref: Option>>, } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index fcf6937d4b6d..382ca8ef0100 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -287,7 +287,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx match fulfill_obligation(scx, DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - scx.tcx().custom_coerce_unsized_kind(impl_def_id) + scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap() } vtable => { bug!("invalid CoerceUnsized vtable: {:?}", vtable); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 3cdf9fc93ae6..47b41a75cf53 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -18,6 +18,7 @@ use rustc::traits::{self, ObligationCause, Reveal}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::ParameterEnvironment; use rustc::ty::TypeFoldable; +use rustc::ty::adjustment::CoerceUnsizedInfo; use rustc::ty::subst::Subst; use rustc::ty::util::CopyImplementationError; use rustc::infer; @@ -159,11 +160,26 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - coerce_unsized_trait: DefId, + _: DefId, impl_did: DefId) { debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did); + // Just compute this for the side-effects, in particular reporting + // errors; other parts of the code may demand it for the info of + // course. + if impl_did.is_local() { + let span = tcx.def_span(impl_did); + ty::queries::coerce_unsized_info::get(tcx, span, impl_did); + } +} + +pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_did: DefId) + -> CoerceUnsizedInfo { + debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); + let coerce_unsized_trait = tcx.lang_items.coerce_unsized_trait().unwrap(); + let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) { Ok(id) => id, Err(err) => { @@ -171,16 +187,14 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let impl_node_id = if let Some(n) = tcx.hir.as_local_node_id(impl_did) { - n - } else { - debug!("visit_implementation_of_coerce_unsized(): impl not \ - in this crate"); - return; - }; + // this provider should only get invoked for local def-ids + let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| { + bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did) + }); let source = tcx.item_type(impl_did); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); + assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.substs.type_at(1); debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, @@ -192,6 +206,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let target = target.subst(tcx, ¶m_env.free_substs); assert!(!source.has_escaping_regions()); + let err_info = CoerceUnsizedInfo { custom_kind: None }; + debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); @@ -234,7 +250,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, definition; expected {}, found {}", source_path, target_path); - return; + return err_info; } let fields = &def_a.struct_variant().fields; @@ -268,7 +284,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with one field \ being coerced, none found"); - return; + return err_info; } else if diff_fields.len() > 1 { let item = tcx.hir.expect_item(impl_node_id); let span = if let ItemImpl(.., Some(ref t), _, _) = item.node { @@ -295,7 +311,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .join(", "))); err.span_label(span, &format!("requires multiple coercions")); err.emit(); - return; + return err_info; } let (i, a, b) = diff_fields[0]; @@ -309,7 +325,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, E0376, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures"); - return; + return err_info; } }; @@ -331,8 +347,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id); - if let Some(kind) = kind { - tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind); + CoerceUnsizedInfo { + custom_kind: kind } - }); + }) } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 9ecf42daeaae..6abd061e81f2 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -102,9 +102,12 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d } pub fn provide(providers: &mut Providers) { + use self::builtin::coerce_unsized_info; + *providers = Providers { coherent_trait, coherent_inherent_impls, + coerce_unsized_info, ..*providers }; } From 8e6b10a6cb349deab30fa0fb507a8c73cae6ec68 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Mar 2017 16:43:54 -0400 Subject: [PATCH 018/905] move `check` to the top of the file, where I would expect to find it Top-down, top-down! --- src/librustc_typeck/coherence/inherent.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/coherence/inherent.rs b/src/librustc_typeck/coherence/inherent.rs index e3b4ba9eb1b9..9abf233de1f9 100644 --- a/src/librustc_typeck/coherence/inherent.rs +++ b/src/librustc_typeck/coherence/inherent.rs @@ -19,6 +19,13 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; +pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, + &mut InherentCollect { tcx }); + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, + &mut InherentOverlapChecker { tcx }); +} + struct InherentCollect<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } @@ -348,9 +355,3 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { } } -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, - &mut InherentCollect { tcx }); - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, - &mut InherentOverlapChecker { tcx }); -} From 8ffe4068a6d8ff79cfccc0244a96e728387bbeb6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 23 Mar 2017 19:26:38 +0200 Subject: [PATCH 019/905] keep the AST node-id when lowering ExprKind::Range When the Range expression is the root of a constant, its node-id is used for the def-id of the body, so it has to be preserved in the AST -> HIR lowering. Fixes #40749. --- src/librustc/hir/lowering.rs | 91 +++++++++++----------------- src/test/compile-fail/issue-40749.rs | 16 +++++ 2 files changed, 50 insertions(+), 57 deletions(-) create mode 100644 src/test/compile-fail/issue-40749.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ac1a036f99e..6ca0c971ea49 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1900,57 +1900,45 @@ impl<'a> LoweringContext<'a> { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } ExprKind::Range(ref e1, ref e2, lims) => { - fn make_struct(this: &mut LoweringContext, - ast_expr: &Expr, - path: &[&str], - fields: &[(&str, &P)]) -> hir::Expr { - let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) - .collect::>(); - let unstable_span = this.allow_internal_unstable("...", ast_expr.span); - - if fields.len() == 0 { - this.expr_std_path(unstable_span, struct_path, - ast_expr.attrs.clone()) - } else { - let fields = fields.into_iter().map(|&(s, e)| { - let expr = P(this.lower_expr(&e)); - let unstable_span = this.allow_internal_unstable("...", e.span); - this.field(Symbol::intern(s), expr, unstable_span) - }).collect(); - let attrs = ast_expr.attrs.clone(); - - this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) - } - } - use syntax::ast::RangeLimits::*; - return match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(self, e, &["RangeFull"], &[]), + let (path, variant) = match (e1, e2, lims) { + (&None, &None, HalfOpen) => ("RangeFull", None), + (&Some(..), &None, HalfOpen) => ("RangeFrom", None), + (&None, &Some(..), HalfOpen) => ("RangeTo", None), + (&Some(..), &Some(..), HalfOpen) => ("Range", None), + (&None, &Some(..), Closed) => ("RangeToInclusive", None), + (&Some(..), &Some(..), Closed) => ("RangeInclusive", Some("NonEmpty")), + (_, &None, Closed) => + panic!(self.diagnostic().span_fatal( + e.span, "inclusive range with no end")), + }; - (&Some(ref e1), &None, HalfOpen) => - make_struct(self, e, &["RangeFrom"], - &[("start", e1)]), + let fields = + e1.iter().map(|e| ("start", e)).chain(e2.iter().map(|e| ("end", e))) + .map(|(s, e)| { + let expr = P(self.lower_expr(&e)); + let unstable_span = self.allow_internal_unstable("...", e.span); + self.field(Symbol::intern(s), expr, unstable_span) + }).collect::>(); - (&None, &Some(ref e2), HalfOpen) => - make_struct(self, e, &["RangeTo"], - &[("end", e2)]), + let is_unit = fields.is_empty(); + let unstable_span = self.allow_internal_unstable("...", e.span); + let struct_path = + iter::once("ops").chain(iter::once(path)).chain(variant) + .collect::>(); + let struct_path = self.std_path(unstable_span, &struct_path, is_unit); + let struct_path = hir::QPath::Resolved(None, P(struct_path)); - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(self, e, &["Range"], - &[("start", e1), ("end", e2)]), - - (&None, &Some(ref e2), Closed) => - make_struct(self, e, &["RangeToInclusive"], - &[("end", e2)]), - - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(self, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), - - _ => panic!(self.diagnostic() - .span_fatal(e.span, "inclusive range with no end")), + return hir::Expr { + id: self.lower_node_id(e.id), + node: if is_unit { + hir::ExprPath(struct_path) + } else { + hir::ExprStruct(struct_path, fields, None) + }, + span: unstable_span, + attrs: e.attrs.clone(), }; } ExprKind::Path(ref qself, ref path) => { @@ -2613,17 +2601,6 @@ impl<'a> LoweringContext<'a> { P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new())) } - fn expr_std_struct(&mut self, - span: Span, - components: &[&str], - fields: hir::HirVec, - e: Option>, - attrs: ThinVec) -> hir::Expr { - let path = self.std_path(span, components, false); - let qpath = hir::QPath::Resolved(None, P(path)); - self.expr(span, hir::ExprStruct(qpath, fields, e), attrs) - } - fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec) -> hir::Expr { hir::Expr { id: self.next_id(), diff --git a/src/test/compile-fail/issue-40749.rs b/src/test/compile-fail/issue-40749.rs new file mode 100644 index 000000000000..261ed49d10c1 --- /dev/null +++ b/src/test/compile-fail/issue-40749.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() { + [0; ..10]; + //~^ ERROR mismatched types + //~| expected type `usize` + //~| found type `std::ops::RangeTo<{integer}>` +} From a29ae3052aa9c84cecab226b9a1f1fee4e5b78d4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 20 Mar 2017 18:35:16 -0400 Subject: [PATCH 020/905] convert inherent-impl-related things to on-demand queries There are now 3 queries: - inherent_impls(def-id): for a given type, get a `Rc>` with all its inherent impls. This internally uses `crate_inherent_impls`, doing some hacks to keep the current deps (which, btw, are not clearly correct). - crate_inherent_impls(crate): gathers up a map from types to `Rc>`, touching the entire krate, possibly generating errors. - crate_inherent_impls_overlap_check(crate): performs overlap checks between the inherent impls for a given type, generating errors. --- src/librustc/dep_graph/dep_node.rs | 2 - src/librustc/dep_graph/dep_tracking_map.rs | 15 -- src/librustc/middle/cstore.rs | 2 - src/librustc/ty/maps.rs | 26 ++- src/librustc/ty/mod.rs | 43 ++--- src/librustc_metadata/cstore_impl.rs | 7 +- src/librustc_typeck/check/method/probe.rs | 11 +- .../{inherent.rs => inherent_impls.rs} | 180 +++++++----------- .../coherence/inherent_impls_overlap.rs | 102 ++++++++++ src/librustc_typeck/coherence/mod.rs | 17 +- src/librustdoc/clean/inline.rs | 8 +- 11 files changed, 227 insertions(+), 186 deletions(-) rename src/librustc_typeck/coherence/{inherent.rs => inherent_impls.rs} (71%) create mode 100644 src/librustc_typeck/coherence/inherent_impls_overlap.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 399af258e925..c4cbbc17d51d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -74,7 +74,6 @@ pub enum DepNode { CoherenceCheckImpl(D), CoherenceOverlapCheck(D), CoherenceOverlapCheckSpecial(D), - CoherenceOverlapInherentCheck(D), CoherenceOrphanCheck(D), Variance, WfCheck(D), @@ -251,7 +250,6 @@ impl DepNode { CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial), - CoherenceOverlapInherentCheck(ref d) => op(d).map(CoherenceOverlapInherentCheck), CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck), WfCheck(ref d) => op(d).map(WfCheck), TypeckItemType(ref d) => op(d).map(TypeckItemType), diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 0f3108df9a82..b6a2360211ca 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -81,21 +81,6 @@ impl DepTrackingMap { pub fn keys(&self) -> Vec { self.map.keys().cloned().collect() } - - /// Append `elem` to the vector stored for `k`, creating a new vector if needed. - /// This is considered a write to `k`. - /// - /// NOTE: Caution is required when using this method. You should - /// be sure that nobody is **reading from the vector** while you - /// are writing to it. Eventually, it'd be nice to remove this. - pub fn push(&mut self, k: M::Key, elem: E) - where M: DepTrackingMapConfig> - { - self.write(&k); - self.map.entry(k) - .or_insert(Vec::new()) - .push(elem); - } } impl MemoizationMap for RefCell> { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 225d6fc9bb2b..50ec6f26d4b8 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -176,7 +176,6 @@ pub trait CrateStore { fn item_generics_cloned(&self, def: DefId) -> ty::Generics; fn item_attrs(&self, def_id: DefId) -> Vec; fn fn_arg_names(&self, did: DefId) -> Vec; - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; // trait info fn implementations_of_trait(&self, filter: Option) -> Vec; @@ -310,7 +309,6 @@ impl CrateStore for DummyCrateStore { { bug!("item_generics_cloned") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { vec![] } // trait info fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index d4214dc429ce..87fe27d92fca 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -12,7 +12,7 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use middle::const_val::ConstVal; use mir; -use ty::{self, Ty, TyCtxt}; +use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; @@ -176,9 +176,15 @@ impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> { } } -impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> { +impl<'tcx> QueryDescription for queries::crate_inherent_impls<'tcx> { + fn describe(_: TyCtxt, k: CrateNum) -> String { + format!("all inherent impls defined in crate `{:?}`", k) + } +} + +impl<'tcx> QueryDescription for queries::crate_inherent_impls_overlap_check<'tcx> { fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("coherence checking all inherent impls") + format!("check for overlap between inherent impls defined in this crate") } } @@ -368,7 +374,7 @@ define_maps! { <'tcx> /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - pub inherent_impls: InherentImpls(DefId) -> Vec, + pub inherent_impls: InherentImpls(DefId) -> Rc>, /// Maps from the def-id of a function/method or const/static /// to its MIR. Mutation is done at an item granularity to @@ -400,7 +406,15 @@ define_maps! { <'tcx> pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), - pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (), + /// Gets a complete map from all types to their inherent impls. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + pub crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, + + /// Checks all types in the krate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (), /// Results of evaluating monomorphic constants embedded in /// other items, such as enum variant explicit discriminants. @@ -413,7 +427,7 @@ fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { DepNode::CoherenceCheckTrait(def_id) } -fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode { +fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { DepNode::Coherence } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d14042699581..d19f2ba2fadb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -31,7 +31,7 @@ use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; use util::common::MemoizationMap; -use util::nodemap::{NodeSet, FxHashMap}; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; @@ -2345,34 +2345,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) } - /// Populates the type context with all the inherent implementations for - /// the given type if necessary. - pub fn populate_inherent_implementations_for_type_if_necessary(self, - span: Span, - type_id: DefId) { - if type_id.is_local() { - // Make sure coherence of inherent impls ran already. - ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE); - return - } - - // The type is not local, hence we are reading this out of - // metadata and don't need to track edges. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_types.borrow().contains(&type_id) { - return - } - - debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", - type_id); - - let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); - - self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls); - self.populated_external_types.borrow_mut().insert(type_id); - } - /// Populates the type context with all the implementations for the given /// trait if necessary. pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) { @@ -2637,3 +2609,16 @@ pub fn provide(providers: &mut ty::maps::Providers) { ..*providers }; } + + +/// A map for the local crate mapping each type to a vector of its +/// inherent impls. This is not meant to be used outside of coherence; +/// rather, you should request the vector for a specific type via +/// `ty::queries::inherent_impls::get(def_id)` so as to minimize your +/// dependencies (constructing this map requires touching the entire +/// crate). +#[derive(Clone, Debug)] +pub struct CrateInherentImpls { + pub inherent_impls: DefIdMap>>, +} + diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 7cac201f14f7..9b781d28f88d 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -109,6 +109,7 @@ provide! { <'tcx> tcx, def_id, cdata typeck_tables => { cdata.item_body_tables(def_id.index, tcx) } closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } + inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } } impl CrateStore for cstore::CStore { @@ -162,12 +163,6 @@ impl CrateStore for cstore::CStore { self.get_crate_data(did.krate).get_fn_arg_names(did.index) } - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec - { - self.dep_graph.read(DepNode::MetaData(def_id)); - self.get_crate_data(def_id.krate).get_inherent_implementations_for_type(def_id.index) - } - fn implementations_of_trait(&self, filter: Option) -> Vec { if let Some(def_id) = filter { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index dfa7ababca0b..5b0418921563 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -479,14 +479,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { - // Read the inherent implementation candidates for this type from the - // metadata if necessary. - self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id); - - if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) { - for &impl_def_id in impl_infos.iter() { - self.assemble_inherent_impl_probe(impl_def_id); - } + let impl_def_ids = ty::queries::inherent_impls::get(self.tcx, self.span, def_id); + for &impl_def_id in impl_def_ids.iter() { + self.assemble_inherent_impl_probe(impl_def_id); } } diff --git a/src/librustc_typeck/coherence/inherent.rs b/src/librustc_typeck/coherence/inherent_impls.rs similarity index 71% rename from src/librustc_typeck/coherence/inherent.rs rename to src/librustc_typeck/coherence/inherent_impls.rs index 9abf233de1f9..3a39df505eb0 100644 --- a/src/librustc_typeck/coherence/inherent.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -8,26 +8,82 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! The code in this module gathers up all of the inherent impls in +//! the current crate and organizes them in a map. It winds up +//! touching the whole crate and thus must be recomputed completely +//! for any change, but it is very cheap to compute. In practice, most +//! code in the compiler never *directly* requests this map. Instead, +//! it requests the inherent impls specific to some type (via +//! `ty::queries::inherent_impls::get(def_id)`). That value, however, +//! is computed by selecting an idea from this table. + use rustc::dep_graph::DepNode; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::lint; -use rustc::traits::{self, Reveal}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, CrateInherentImpls, TyCtxt}; +use rustc::util::nodemap::DefIdMap; +use std::rc::Rc; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, - &mut InherentCollect { tcx }); - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, - &mut InherentOverlapChecker { tcx }); +/// On-demand query: yields a map containing all types mapped to their inherent impls. +pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + crate_num: CrateNum) + -> CrateInherentImpls { + assert_eq!(crate_num, LOCAL_CRATE); + + let krate = tcx.hir.krate(); + let mut collect = InherentCollect { + tcx, + impls_map: CrateInherentImpls { + inherent_impls: DefIdMap() + } + }; + krate.visit_all_item_likes(&mut collect); + collect.impls_map +} + +/// On-demand query: yields a vector of the inherent impls for a specific type. +pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty_def_id: DefId) + -> Rc> { + assert!(ty_def_id.is_local()); + + // NB. Until we adopt the red-green dep-tracking algorithm (see + // [the plan] for details on that), we do some hackery here to get + // the dependencies correct. Basically, we use a `with_ignore` to + // read the result we want. If we didn't have the `with_ignore`, + // we would wind up with a dependency on the entire crate, which + // we don't want. Then we go and add dependencies on all the impls + // in the result (which is what we wanted). + // + // The result is a graph with an edge from `Hir(I)` for every impl + // `I` defined on some type `T` to `CoherentInherentImpls(T)`, + // thus ensuring that if any of those impls change, the set of + // inherent impls is considered dirty. + // + // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4 + + let result = tcx.dep_graph.with_ignore(|| { + let crate_map = ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, ty_def_id.krate); + match crate_map.inherent_impls.get(&ty_def_id) { + Some(v) => v.clone(), + None => Rc::new(vec![]), + } + }); + + for &impl_def_id in &result[..] { + tcx.dep_graph.read(DepNode::Hir(impl_def_id)); + } + + result } struct InherentCollect<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> + tcx: TyCtxt<'a, 'tcx, 'tcx>, + impls_map: CrateInherentImpls, } impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { @@ -216,25 +272,19 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { } impl<'a, 'tcx> InherentCollect<'a, 'tcx> { - fn check_def_id(&self, item: &hir::Item, def_id: DefId) { + fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) { if def_id.is_local() { // Add the implementation to the mapping from implementation to base // type def ID, if there is a base type for this implementation and // the implementation does not have any associated traits. let impl_def_id = self.tcx.hir.local_def_id(item.id); + let mut rc_vec = self.impls_map.inherent_impls + .entry(def_id) + .or_insert_with(|| Rc::new(vec![])); - // Subtle: it'd be better to collect these into a local map - // and then write the vector only once all items are known, - // but that leads to degenerate dep-graphs. The problem is - // that the write of that big vector winds up having reads - // from *all* impls in the krate, since we've lost the - // precision basically. This would be ok in the firewall - // model so once we've made progess towards that we can modify - // the strategy here. In the meantime, using `push` is ok - // because we are doing this as a pre-pass before anyone - // actually reads from `inherent_impls` -- and we know this is - // true beacuse we hold the refcell lock. - self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id); + // At this point, there should not be any clones of the + // `Rc`, so we can still safely push into it in place: + Rc::get_mut(&mut rc_vec).unwrap().push(impl_def_id); } else { struct_span_err!(self.tcx.sess, item.span, @@ -273,85 +323,3 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> { } } -struct InherentOverlapChecker<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> -} - -impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { - fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { - #[derive(Copy, Clone, PartialEq)] - enum Namespace { - Type, - Value, - } - - let name_and_namespace = |def_id| { - let item = self.tcx.associated_item(def_id); - (item.name, match item.kind { - ty::AssociatedKind::Type => Namespace::Type, - ty::AssociatedKind::Const | - ty::AssociatedKind::Method => Namespace::Value, - }) - }; - - let impl_items1 = self.tcx.associated_item_def_ids(impl1); - let impl_items2 = self.tcx.associated_item_def_ids(impl2); - - for &item1 in &impl_items1[..] { - let (name, namespace) = name_and_namespace(item1); - - for &item2 in &impl_items2[..] { - if (name, namespace) == name_and_namespace(item2) { - let msg = format!("duplicate definitions with name `{}`", name); - let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); - self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, - node_id, - self.tcx.span_of_impl(item1).unwrap(), - msg); - } - } - } - } - - fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { - let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id)); - - let inherent_impls = self.tcx.maps.inherent_impls.borrow(); - let impls = match inherent_impls.get(&ty_def_id) { - Some(impls) => impls, - None => return, - }; - - for (i, &impl1_def_id) in impls.iter().enumerate() { - for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { - if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { - self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) - } - }); - } - } - } -} - -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { - fn visit_item(&mut self, item: &'v hir::Item) { - match item.node { - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemTrait(..) | - hir::ItemUnion(..) => { - let type_def_id = self.tcx.hir.local_def_id(item.id); - self.check_for_overlapping_inherent_impls(type_def_id); - } - _ => {} - } - } - - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { - } - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { - } -} - diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs new file mode 100644 index 000000000000..4b36072243c8 --- /dev/null +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -0,0 +1,102 @@ +// 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::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::hir; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::lint; +use rustc::traits::{self, Reveal}; +use rustc::ty::{self, TyCtxt}; + +use syntax_pos::DUMMY_SP; + +pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + crate_num: CrateNum) { + assert_eq!(crate_num, LOCAL_CRATE); + let krate = tcx.hir.krate(); + krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx }); +} + +struct InherentOverlapChecker<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx> +} + +impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { + fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { + #[derive(Copy, Clone, PartialEq)] + enum Namespace { + Type, + Value, + } + + let name_and_namespace = |def_id| { + let item = self.tcx.associated_item(def_id); + (item.name, match item.kind { + ty::AssociatedKind::Type => Namespace::Type, + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => Namespace::Value, + }) + }; + + let impl_items1 = self.tcx.associated_item_def_ids(impl1); + let impl_items2 = self.tcx.associated_item_def_ids(impl2); + + for &item1 in &impl_items1[..] { + let (name, namespace) = name_and_namespace(item1); + + for &item2 in &impl_items2[..] { + if (name, namespace) == name_and_namespace(item2) { + let msg = format!("duplicate definitions with name `{}`", name); + let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); + self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, + node_id, + self.tcx.span_of_impl(item1).unwrap(), + msg); + } + } + } + } + + fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { + let impls = ty::queries::inherent_impls::get(self.tcx, DUMMY_SP, ty_def_id); + + for (i, &impl1_def_id) in impls.iter().enumerate() { + for &impl2_def_id in &impls[(i + 1)..] { + self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { + self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) + } + }); + } + } + } +} + +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { + fn visit_item(&mut self, item: &'v hir::Item) { + match item.node { + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemTrait(..) | + hir::ItemUnion(..) => { + let type_def_id = self.tcx.hir.local_def_id(item.id); + self.check_for_overlapping_inherent_impls(type_def_id); + } + _ => {} + } + } + + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } +} + diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 6abd061e81f2..b3a7b612dd5b 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -24,7 +24,8 @@ use syntax::ast; use syntax_pos::DUMMY_SP; mod builtin; -mod inherent; +mod inherent_impls; +mod inherent_impls_overlap; mod orphan; mod overlap; mod unsafety; @@ -103,10 +104,14 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d pub fn provide(providers: &mut Providers) { use self::builtin::coerce_unsized_info; + use self::inherent_impls::{crate_inherent_impls, inherent_impls}; + use self::inherent_impls_overlap::crate_inherent_impls_overlap_check; *providers = Providers { coherent_trait, - coherent_inherent_impls, + crate_inherent_impls, + inherent_impls, + crate_inherent_impls_overlap_check, coerce_unsized_info, ..*providers }; @@ -126,10 +131,6 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, builtin::check_trait(tcx, def_id); } -fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) { - inherent::check(tcx); -} - pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::Coherence); for &trait_def_id in tcx.hir.krate().trait_impls.keys() { @@ -140,5 +141,7 @@ pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { orphan::check(tcx); overlap::check_default_impls(tcx); - ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); + // these queries are executed for side-effects (error reporting): + ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); + ty::queries::crate_inherent_impls_overlap_check::get(tcx, DUMMY_SP, LOCAL_CRATE); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c4476483186c..cc30fdf56fc3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -232,14 +232,12 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { let tcx = cx.tcx; - tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did); let mut impls = Vec::new(); - if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) { - for &did in i.iter() { - build_impl(cx, did, &mut impls); - } + for &did in ty::queries::inherent_impls::get(tcx, DUMMY_SP, did).iter() { + build_impl(cx, did, &mut impls); } + // If this is the first time we've inlined something from another crate, then // we inline *all* impls from all the crates into this crate. Note that there's // currently no way for us to filter this based on type, and we likely need From 425c1a3a052d072dd53719a27454e905af8e954c Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:29:04 -0400 Subject: [PATCH 021/905] Add contribution instructions to stdlib docs --- src/libstd/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 064144dcd681..c6b6d3ab5b0d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -94,6 +94,12 @@ //! compiler - but they are documented here the same). Like the prelude, the //! standard macros are imported by default into all crates. //! +//! # Contributing changes to the documentation +//! +//! The source for this documentation can be found on [github](https://github.com/rust-lang/rust/tree/master/src/libstd). +//! To contribute changes, you can search for nearby strings in github to find +//! relevant files, then submit pull-requests with your suggested changes. +//! //! # A Tour of The Rust Standard Library //! //! The rest of this crate documentation is dedicated to pointing out notable From 53d5082a2d08060ebca869cb8ee97c3ed3cf4ce9 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:42:39 -0400 Subject: [PATCH 022/905] requested changes --- src/libstd/io/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index dda9d6bca797..60b211a746ff 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -144,7 +144,8 @@ //! # Ok(()) //! # } //! ``` -//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main()`). +//! +//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main`). //! Instead, you can `match` on the return value to catch any possible errors: //! //! ``` From 04fbec1a0cb7467834bd264b80350b1cade8b4ca Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:43:09 -0400 Subject: [PATCH 023/905] newline for breathing room --- src/libstd/io/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 60b211a746ff..773b0964b426 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -150,6 +150,7 @@ //! //! ``` //! let mut input = String::new(); +//! //! match io::stdin().read_line(&mut input) { //! Err(why) => panic!("Failed to read input: {}", why.description()), //! Ok(_) => println!("You typed: {}", input.trim()), From 7665991e3e502a534803bd1ac94c16ffd557ed95 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 23 Mar 2017 13:48:32 -0400 Subject: [PATCH 024/905] add link to contribution guidelines and IRC room --- src/libstd/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c6b6d3ab5b0d..ab1167e20b1d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -96,9 +96,13 @@ //! //! # Contributing changes to the documentation //! -//! The source for this documentation can be found on [github](https://github.com/rust-lang/rust/tree/master/src/libstd). -//! To contribute changes, you can search for nearby strings in github to find -//! relevant files, then submit pull-requests with your suggested changes. +//! Check out the rust contribution guidelines [here](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). +//! The source for this documentation can be found on [Github](https://github.com/rust-lang/rust/tree/master/src/libstd). +//! To contribute changes, make sure you read the guidelines first, then submit +//! pull-requests for your suggested changes. +//! +//! Contributions are appreciated! If you see a part of the docs that can be +//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust. //! //! # A Tour of The Rust Standard Library //! From a3a5ff98eba2f81ec76b18cce50f113f59181cce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Mar 2017 14:18:25 -0400 Subject: [PATCH 025/905] move `export_map` into the tcx --- src/librustc/middle/cstore.rs | 12 ++++++------ src/librustc/ty/context.rs | 6 +++++- src/librustc/ty/mod.rs | 2 +- src/librustc_driver/driver.rs | 6 +++--- src/librustc_metadata/cstore_impl.rs | 6 +++--- src/librustc_metadata/encoder.rs | 6 +----- src/librustc_privacy/lib.rs | 10 +++------- src/librustc_trans/base.rs | 4 +--- src/librustc_trans/context.rs | 12 ------------ src/librustdoc/core.rs | 6 ++---- src/librustdoc/visit_ast.rs | 2 +- 11 files changed, 26 insertions(+), 46 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 225d6fc9bb2b..56bbc0480c30 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -255,8 +255,8 @@ pub trait CrateStore { fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>; fn used_crate_source(&self, cnum: CrateNum) -> CrateSource; fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, reachable: &NodeSet) -> Vec; fn metadata_encoding_version(&self) -> &[u8]; @@ -412,10 +412,10 @@ impl CrateStore for DummyCrateStore { { vec![] } fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") } fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, - link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec { vec![] } + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + link_meta: &LinkMeta, + reachable: &NodeSet) -> Vec { vec![] } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5543223105b4..da56514ea82f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -15,7 +15,7 @@ use session::Session; use lint; use middle; use hir::TraitMap; -use hir::def::Def; +use hir::def::{Def, ExportMap}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::DisambiguatedDefPathData; @@ -416,6 +416,9 @@ pub struct GlobalCtxt<'tcx> { /// is relevant; generated by resolve. pub trait_map: TraitMap, + /// Export map produced by name resolution. + pub export_map: ExportMap, + pub named_region_map: resolve_lifetime::NamedRegionMap, pub region_maps: RegionMaps, @@ -698,6 +701,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { region_maps: region_maps, variance_computed: Cell::new(false), trait_map: resolutions.trait_map, + export_map: resolutions.export_map, fulfilled_predicates: RefCell::new(fulfilled_predicates), hir: hir, maps: maps::Maps::new(dep_graph, providers), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36d1ae74e911..0bcfae1e54a6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -110,7 +110,6 @@ mod sty; /// produced by the driver and fed to trans and later passes. #[derive(Clone)] pub struct CrateAnalysis { - pub export_map: ExportMap, pub access_levels: middle::privacy::AccessLevels, pub reachable: NodeSet, pub name: String, @@ -122,6 +121,7 @@ pub struct Resolutions { pub freevars: FreevarMap, pub trait_map: TraitMap, pub maybe_unused_trait_imports: NodeSet, + pub export_map: ExportMap, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d37553d7d660..4947cafb52b3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -807,7 +807,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, expanded_crate: krate, defs: resolver.definitions, analysis: ty::CrateAnalysis { - export_map: resolver.export_map, access_levels: AccessLevels::default(), reachable: NodeSet(), name: crate_name.to_string(), @@ -815,10 +814,11 @@ pub fn phase_2_configure_and_expand(sess: &Session, }, resolutions: Resolutions { freevars: resolver.freevars, + export_map: resolver.export_map, trait_map: resolver.trait_map, maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, }, - hir_forest: hir_forest + hir_forest: hir_forest, }) } @@ -932,7 +932,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, analysis.access_levels = time(time_passes, "privacy checking", || { - rustc_privacy::check_crate(tcx, &analysis.export_map) + rustc_privacy::check_crate(tcx) }); time(time_passes, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2a67b79eaa52..17484138ad3a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -496,12 +496,12 @@ impl CrateStore for cstore::CStore { self.do_extern_mod_stmt_cnum(emod_id) } - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, reachable: &NodeSet) -> Vec { - encoder::encode_metadata(tcx, self, reexports, link_meta, reachable) + encoder::encode_metadata(tcx, self, link_meta, reachable) } fn metadata_encoding_version(&self) -> &[u8] diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 044ed529ef74..a324c166e738 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -13,7 +13,6 @@ use index::Index; use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; -use rustc::hir::def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; use rustc::middle::dependency_format::Linkage; @@ -48,7 +47,6 @@ use super::index_builder::{FromId, IndexBuilder, Untracked}; pub struct EncodeContext<'a, 'tcx: 'a> { opaque: opaque::Encoder<'a>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &'a def::ExportMap, link_meta: &'a LinkMeta, cstore: &'a cstore::CStore, exported_symbols: &'a NodeSet, @@ -306,7 +304,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = tcx.hir.local_def_id(id); let data = ModData { - reexports: match self.reexports.get(&id) { + reexports: match tcx.export_map.get(&id) { Some(exports) if *vis == hir::Public => self.lazy_seq_ref(exports), _ => LazySeq::empty(), }, @@ -1423,7 +1421,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, - reexports: &def::ExportMap, link_meta: &LinkMeta, exported_symbols: &NodeSet) -> Vec { @@ -1437,7 +1434,6 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut ecx = EncodeContext { opaque: opaque::Encoder::new(&mut cursor), tcx: tcx, - reexports: reexports, link_meta: link_meta, cstore: cstore, exported_symbols: exported_symbols, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index e32ec25a7e8f..6b33c7b7816f 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -27,7 +27,7 @@ extern crate syntax_pos; use rustc::dep_graph::DepNode; use rustc::hir::{self, PatKind}; -use rustc::hir::def::{self, Def}; +use rustc::hir::def::Def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; @@ -71,7 +71,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> { struct EmbargoVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - export_map: &'a def::ExportMap, // Accessibility levels for reachable nodes access_levels: AccessLevels, @@ -324,7 +323,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { // This code is here instead of in visit_item so that the // crate module gets processed as well. if self.prev_level.is_some() { - if let Some(exports) = self.export_map.get(&id) { + if let Some(exports) = self.tcx.export_map.get(&id) { for export in exports { if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) { self.update(node_id, Some(AccessLevel::Exported)); @@ -1204,9 +1203,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> fn visit_pat(&mut self, _: &'tcx hir::Pat) {} } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - export_map: &def::ExportMap) - -> AccessLevels { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> AccessLevels { let _task = tcx.dep_graph.in_task(DepNode::Privacy); let krate = tcx.hir.krate(); @@ -1226,7 +1223,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // items which are reachable from external crates based on visibility. let mut visitor = EmbargoVisitor { tcx: tcx, - export_map: export_map, access_levels: Default::default(), prev_level: Some(AccessLevel::Public), changed: false, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 80b563729f5c..f7ca468fddae 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -755,7 +755,6 @@ fn write_metadata(cx: &SharedCrateContext, let cstore = &cx.tcx().sess.cstore; let metadata = cstore.encode_metadata(cx.tcx(), - cx.export_map(), cx.link_meta(), exported_symbols); if kind == MetadataKind::Uncompressed { @@ -1056,7 +1055,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // particular items that will be processed. let krate = tcx.hir.krate(); - let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis; + let ty::CrateAnalysis { reachable, name, .. } = analysis; let exported_symbols = find_exported_symbols(tcx, reachable); let check_overflow = tcx.sess.overflow_checks(); @@ -1064,7 +1063,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let link_meta = link::build_link_meta(incremental_hashes_map, &name); let shared_ccx = SharedCrateContext::new(tcx, - export_map, link_meta.clone(), exported_symbols, check_overflow); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1c1395f1b776..73602dc420b3 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -14,7 +14,6 @@ use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir; -use rustc::hir::def::ExportMap; use rustc::hir::def_id::DefId; use rustc::traits; use debuginfo; @@ -68,7 +67,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { metadata_llmod: ModuleRef, metadata_llcx: ContextRef, - export_map: ExportMap, exported_symbols: NodeSet, link_meta: LinkMeta, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -402,7 +400,6 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, - export_map: ExportMap, link_meta: LinkMeta, exported_symbols: NodeSet, check_overflow: bool) @@ -459,7 +456,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { SharedCrateContext { metadata_llmod: metadata_llmod, metadata_llcx: metadata_llcx, - export_map: export_map, exported_symbols: exported_symbols, link_meta: link_meta, empty_param_env: tcx.empty_parameter_environment(), @@ -499,10 +495,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { self.metadata_llcx } - pub fn export_map<'a>(&'a self) -> &'a ExportMap { - &self.export_map - } - pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { &self.exported_symbols } @@ -702,10 +694,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } - pub fn export_map<'a>(&'a self) -> &'a ExportMap { - &self.shared.export_map - } - pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { &self.shared.exported_symbols } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0a9db2c26464..92aba1fc61de 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,7 @@ use rustc_driver::{driver, target_features, abort_on_err}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; use rustc::hir::def_id::DefId; -use rustc::hir::def::{Def, ExportMap}; +use rustc::hir::def::Def; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt, GlobalArenas}; use rustc::hir::map as hir_map; @@ -64,7 +64,6 @@ pub struct DocContext<'a, 'tcx: 'a> { pub ty_substs: RefCell>, /// Table node id of lifetime parameter definition -> substituted lifetime pub lt_substs: RefCell>, - pub export_map: ExportMap, } impl<'a, 'tcx> DocContext<'a, 'tcx> { @@ -180,7 +179,7 @@ pub fn run_core(search_paths: SearchPaths, sess.fatal("Compilation failed, aborting rustdoc"); } - let ty::CrateAnalysis { access_levels, export_map, .. } = analysis; + let ty::CrateAnalysis { access_levels, .. } = analysis; // Convert from a NodeId set to a DefId set since we don't always have easy access // to the map from defid -> nodeid @@ -198,7 +197,6 @@ pub fn run_core(search_paths: SearchPaths, renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), - export_map: export_map, }; debug!("crate: {:?}", tcx.hir.krate()); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4a909f8e2a97..279330769785 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -198,7 +198,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.visit_item(item, None, &mut om); } self.inside_public_path = orig_inside_public_path; - if let Some(exports) = self.cx.export_map.get(&id) { + if let Some(exports) = self.cx.tcx.export_map.get(&id) { for export in exports { if let Def::Macro(def_id, ..) = export.def { if def_id.krate == LOCAL_CRATE { From e341d603fe7c35ce174bd2e54e47ed6941ea4b03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Feb 2017 07:57:59 -0800 Subject: [PATCH 026/905] Remove internal liblog This commit deletes the internal liblog in favor of the implementation that lives on crates.io. Similarly it's also setting a convention for adding crates to the compiler. The main restriction right now is that we want compiler implementation details to be unreachable from normal Rust code (e.g. requires a feature), and by default everything in the sysroot is reachable via `extern crate`. The proposal here is to require that crates pulled in have these lines in their `src/lib.rs`: #![cfg_attr(rustbuild, feature(staged_api, rustc_private))] #![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] This'll mean that by default they're not using these attributes but when compiled as part of the compiler they do a few things: * Mark themselves as entirely unstable via the `staged_api` feature and the `#![unstable]` attribute. * Allow usage of other unstable crates via `feature(rustc_private)` which is required if the crate relies on any other crates to compile (other than std). --- src/Cargo.lock | 53 +- src/liblog/Cargo.toml | 9 - src/liblog/directive.rs | 193 ------- src/liblog/lib.rs | 506 ------------------ src/liblog/macros.rs | 205 ------- src/librustc/Cargo.toml | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/ty/item_path.rs | 3 +- src/librustc_back/Cargo.toml | 2 +- src/librustc_borrowck/Cargo.toml | 2 +- src/librustc_const_eval/Cargo.toml | 2 +- src/librustc_data_structures/Cargo.toml | 2 +- src/librustc_driver/Cargo.toml | 3 +- src/librustc_driver/driver.rs | 4 +- src/librustc_driver/lib.rs | 2 + src/librustc_incremental/Cargo.toml | 2 +- src/librustc_lint/Cargo.toml | 2 +- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_mir/Cargo.toml | 2 +- src/librustc_passes/Cargo.toml | 4 +- src/librustc_resolve/Cargo.toml | 2 +- src/librustc_save_analysis/Cargo.toml | 2 +- src/librustc_trans/Cargo.toml | 2 +- src/librustc_typeck/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 5 +- src/librustdoc/lib.rs | 2 + src/libsyntax/Cargo.toml | 2 +- src/libsyntax_ext/Cargo.toml | 2 +- .../auxiliary/logging_right_crate.rs | 18 - .../conditional-debug-macro-off.rs | 23 - .../logging-enabled-debug.rs | 24 - src/test/run-pass-fulldeps/logging-enabled.rs | 27 - .../run-pass-fulldeps/logging-right-crate.rs | 31 -- .../logging-separate-lines.rs | 40 -- src/test/run-pass-fulldeps/rust-log-filter.rs | 58 -- .../run-pass/conditional-debug-macro-on.rs | 2 - src/tools/compiletest/Cargo.toml | 2 +- 38 files changed, 54 insertions(+), 1194 deletions(-) delete mode 100644 src/liblog/Cargo.toml delete mode 100644 src/liblog/directive.rs delete mode 100644 src/liblog/lib.rs delete mode 100644 src/liblog/macros.rs delete mode 100644 src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs delete mode 100644 src/test/run-pass-fulldeps/conditional-debug-macro-off.rs delete mode 100644 src/test/run-pass-fulldeps/logging-enabled-debug.rs delete mode 100644 src/test/run-pass-fulldeps/logging-enabled.rs delete mode 100644 src/test/run-pass-fulldeps/logging-right-crate.rs delete mode 100644 src/test/run-pass-fulldeps/logging-separate-lines.rs delete mode 100644 src/test/run-pass-fulldeps/rust-log-filter.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index 9ae894061a67..a0b47f4f0b2b 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -147,7 +147,7 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -162,14 +162,6 @@ name = "dtoa" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "env_logger" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" version = "0.4.2" @@ -270,10 +262,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "linkchecker" version = "0.1.0" -[[package]] -name = "log" -version = "0.0.0" - [[package]] name = "log" version = "0.3.7" @@ -439,7 +427,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -479,7 +467,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -493,7 +481,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -508,7 +496,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -530,7 +518,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -539,8 +527,9 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "arena 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -579,7 +568,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -591,7 +580,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -623,7 +612,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -642,7 +631,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -666,7 +655,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", @@ -705,7 +694,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -716,7 +705,7 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -730,7 +719,7 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", @@ -762,7 +751,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -780,8 +769,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -857,7 +847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "syntax" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -870,7 +860,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -996,7 +986,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" diff --git a/src/liblog/Cargo.toml b/src/liblog/Cargo.toml deleted file mode 100644 index 31a862478d03..000000000000 --- a/src/liblog/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "log" -version = "0.0.0" - -[lib] -name = "log" -path = "lib.rs" -crate-type = ["dylib", "rlib"] diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs deleted file mode 100644 index eb50d6e6135e..000000000000 --- a/src/liblog/directive.rs +++ /dev/null @@ -1,193 +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. - -use std::ascii::AsciiExt; -use std::cmp; - -#[derive(Debug, Clone)] -pub struct LogDirective { - pub name: Option, - pub level: u32, -} - -pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; - -/// Parse an individual log level that is either a number or a symbolic log level -fn parse_log_level(level: &str) -> Option { - level.parse::() - .ok() - .or_else(|| { - let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); - pos.map(|p| p as u32 + 1) - }) - .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) -} - -/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") -/// and return a vector with log directives. -/// -/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in -/// std::). Also supports string log levels of error, warn, info, and debug -pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { - let mut dirs = Vec::new(); - - let mut parts = spec.split('/'); - let mods = parts.next(); - let filter = parts.next(); - if parts.next().is_some() { - println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)", - spec); - return (dirs, None); - } - if let Some(m) = mods { - for s in m.split(',') { - if s.is_empty() { - continue; - } - let mut parts = s.split('='); - let (log_level, name) = - match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { - (Some(part0), None, None) => { - // if the single argument is a log-level string or number, - // treat that as a global fallback - match parse_log_level(part0) { - Some(num) => (num, None), - None => (::MAX_LOG_LEVEL, Some(part0)), - } - } - (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), - (Some(part0), Some(part1), None) => { - match parse_log_level(part1) { - Some(num) => (num, Some(part0)), - _ => { - println!("warning: invalid logging spec '{}', ignoring it", part1); - continue; - } - } - } - _ => { - println!("warning: invalid logging spec '{}', ignoring it", s); - continue; - } - }; - dirs.push(LogDirective { - name: name.map(str::to_owned), - level: log_level, - }); - } - } - - (dirs, filter.map(str::to_owned)) -} - -#[cfg(test)] -mod tests { - use super::parse_logging_spec; - - #[test] - fn parse_logging_spec_valid() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_crate() { - // test parse_logging_spec with multiple = in specification - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_log_level() { - // test parse_logging_spec with 'noNumber' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_string_log_level() { - // test parse_logging_spec with 'warn' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::WARN); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_empty_log_level() { - // test parse_logging_spec with '' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_global() { - // test parse_logging_spec with no crate - let (dirs, filter) = parse_logging_spec("warn,crate2=4"); - assert_eq!(dirs.len(), 2); - assert_eq!(dirs[0].name, None); - assert_eq!(dirs[0].level, 2); - assert_eq!(dirs[1].name, Some("crate2".to_owned())); - assert_eq!(dirs[1].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_valid_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "abc"); - } - - #[test] - fn parse_logging_spec_invalid_crate_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c"); - } - - #[test] - fn parse_logging_spec_empty_with_filter() { - let (dirs, filter) = parse_logging_spec("crate1/a*c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate1".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c"); - } -} diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs deleted file mode 100644 index 057df647c725..000000000000 --- a/src/liblog/lib.rs +++ /dev/null @@ -1,506 +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. - -//! Utilities for program-wide and customizable logging -//! -//! # Examples -//! -//! ``` -//! # #![feature(rustc_private)] -//! #[macro_use] extern crate log; -//! -//! fn main() { -//! debug!("this is a debug {:?}", "message"); -//! error!("this is printed by default"); -//! -//! if log_enabled!(log::INFO) { -//! let x = 3 * 4; // expensive computation -//! info!("the answer was: {:?}", x); -//! } -//! } -//! ``` -//! -//! Assumes the binary is `main`: -//! -//! ```{.bash} -//! $ RUST_LOG=error ./main -//! ERROR:main: this is printed by default -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=debug ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! You can also set the log level on a per module basis: -//! -//! ```{.bash} -//! $ RUST_LOG=main=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! And enable all logging: -//! -//! ```{.bash} -//! $ RUST_LOG=main ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! # Logging Macros -//! -//! There are five macros that the logging subsystem uses: -//! -//! * `log!(level, ...)` - the generic logging macro, takes a level as a u32 and any -//! related `format!` arguments -//! * `debug!(...)` - a macro hard-wired to the log level of `DEBUG` -//! * `info!(...)` - a macro hard-wired to the log level of `INFO` -//! * `warn!(...)` - a macro hard-wired to the log level of `WARN` -//! * `error!(...)` - a macro hard-wired to the log level of `ERROR` -//! -//! All of these macros use the same style of syntax as the `format!` syntax -//! extension. Details about the syntax can be found in the documentation of -//! `std::fmt` along with the Rust tutorial/manual. -//! -//! If you want to check at runtime if a given logging level is enabled (e.g. if the -//! information you would want to log is expensive to produce), you can use the -//! following macro: -//! -//! * `log_enabled!(level)` - returns true if logging of the given level is enabled -//! -//! # Enabling logging -//! -//! Log levels are controlled on a per-module basis, and by default all logging is -//! disabled except for `error!` (a log level of 1). Logging is controlled via the -//! `RUST_LOG` environment variable. The value of this environment variable is a -//! comma-separated list of logging directives. A logging directive is of the form: -//! -//! ```text -//! path::to::module=log_level -//! ``` -//! -//! The path to the module is rooted in the name of the crate it was compiled for, -//! so if your program is contained in a file `hello.rs`, for example, to turn on -//! logging for this file you would use a value of `RUST_LOG=hello`. -//! Furthermore, this path is a prefix-search, so all modules nested in the -//! specified module will also have logging enabled. -//! -//! The actual `log_level` is optional to specify. If omitted, all logging will be -//! enabled. If specified, the it must be either a numeric in the range of 1-255, or -//! it must be one of the strings `debug`, `error`, `info`, or `warn`. If a numeric -//! is specified, then all logging less than or equal to that numeral is enabled. -//! For example, if logging level 3 is active, error, warn, and info logs will be -//! printed, but debug will be omitted. -//! -//! As the log level for a module is optional, the module to enable logging for is -//! also optional. If only a `log_level` is provided, then the global log level for -//! all modules is set to this value. -//! -//! Some examples of valid values of `RUST_LOG` are: -//! -//! * `hello` turns on all logging for the 'hello' module -//! * `info` turns on all info logging -//! * `hello=debug` turns on debug logging for 'hello' -//! * `hello=3` turns on info logging for 'hello' -//! * `hello,std::option` turns on hello, and std's option logging -//! * `error,hello=warn` turn on global error logging and also warn for hello -//! -//! # Filtering results -//! -//! A RUST_LOG directive may include a string filter. The syntax is to append -//! `/` followed by a string. Each message is checked against the string and is -//! only logged if it contains the string. Note that the matching is done after -//! formatting the log string but before adding any logging meta-data. There is -//! a single filter for all modules. -//! -//! Some examples: -//! -//! * `hello/foo` turns on all logging for the 'hello' module where the log message -//! includes 'foo'. -//! * `info/f.o` turns on all info logging where the log message includes 'foo', -//! 'f1o', 'fao', etc. -//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log -//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. -//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also warn for -//! hello. In both cases the log message must include a single digit number -//! followed by 'scopes' -//! -//! # Performance and Side Effects -//! -//! Each of these macros will expand to code similar to: -//! -//! ```rust,ignore -//! if log_level <= my_module_log_level() { -//! ::log::log(log_level, format!(...)); -//! } -//! ``` -//! -//! What this means is that each of these macros are very cheap at runtime if -//! they're turned off (just a load and an integer comparison). This also means that -//! if logging is disabled, none of the components of the log will be executed. - -#![crate_name = "log"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `log` library instead", - issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![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/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] -#![deny(missing_docs)] -#![deny(warnings)] - -#![feature(staged_api)] - -use std::cell::RefCell; -use std::fmt; -use std::io::{self, Stderr}; -use std::io::prelude::*; -use std::mem; -use std::env; -use std::slice; -use std::sync::{Mutex, ONCE_INIT, Once}; - -use directive::LOG_LEVEL_NAMES; - -#[macro_use] -pub mod macros; - -mod directive; - -/// Maximum logging level of a module that can be specified. Common logging -/// levels are found in the DEBUG/INFO/WARN/ERROR constants. -pub const MAX_LOG_LEVEL: u32 = 255; - -/// The default logging level of a crate if no other is specified. -const DEFAULT_LOG_LEVEL: u32 = 1; - -static mut LOCK: *mut Mutex<(Vec, Option)> = 0 as *mut _; - -/// An unsafe constant that is the maximum logging level of any module -/// specified. This is the first line of defense to determining whether a -/// logging statement should be run. -static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; - -/// Debug log level -pub const DEBUG: u32 = 4; -/// Info log level -pub const INFO: u32 = 3; -/// Warn log level -pub const WARN: u32 = 2; -/// Error log level -pub const ERROR: u32 = 1; - -thread_local! { - static LOCAL_LOGGER: RefCell>> = { - RefCell::new(None) - } -} - -/// A trait used to represent an interface to a thread-local logger. Each thread -/// can have its own custom logger which can respond to logging messages -/// however it likes. -pub trait Logger { - /// Logs a single message described by the `record`. - fn log(&mut self, record: &LogRecord); -} - -struct DefaultLogger { - handle: Stderr, -} - -/// Wraps the log level with fmt implementations. -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -pub struct LogLevel(pub u32); - -impl fmt::Display for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - match LOG_LEVEL_NAMES.get(level as usize - 1) { - Some(ref name) => fmt::Display::fmt(name, fmt), - None => fmt::Display::fmt(&level, fmt), - } - } -} - -impl Logger for DefaultLogger { - fn log(&mut self, record: &LogRecord) { - match writeln!(&mut self.handle, - "{}:{}: {}", - record.level, - record.module_path, - record.args) { - Err(e) => panic!("failed to log: {:?}", e), - Ok(()) => {} - } - } -} - -impl Drop for DefaultLogger { - fn drop(&mut self) { - // FIXME(#12628): is panicking the right thing to do? - match self.handle.flush() { - Err(e) => panic!("failed to flush a logger: {:?}", e), - Ok(()) => {} - } - } -} - -/// This function is called directly by the compiler when using the logging -/// macros. This function does not take into account whether the log level -/// specified is active or not, it will always log something if this method is -/// called. -/// -/// It is not recommended to call this function directly, rather it should be -/// invoked through the logging family of macros. -#[doc(hidden)] -pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { - // Test the literal string from args against the current filter, if there - // is one. - unsafe { - let filter = (*LOCK).lock().unwrap(); - if let Some(ref filter) = filter.1 { - if !args.to_string().contains(filter) { - return; - } - } - } - - // Completely remove the local logger from TLS in case anyone attempts to - // frob the slot while we're doing the logging. This will destroy any logger - // set during logging. - let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); - let mut logger = logger.unwrap_or_else(|| Box::new(DefaultLogger { handle: io::stderr() })); - logger.log(&LogRecord { - level: LogLevel(level), - args: args, - file: loc.file, - module_path: loc.module_path, - line: loc.line, - }); - set_logger(logger); -} - -/// Getter for the global log level. This is a function so that it can be called -/// safely -#[doc(hidden)] -#[inline(always)] -pub fn log_level() -> u32 { - unsafe { LOG_LEVEL } -} - -/// Replaces the thread-local logger with the specified logger, returning the old -/// logger. -pub fn set_logger(logger: Box) -> Option> { - LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger))) -} - -/// A LogRecord is created by the logging macros, and passed as the only -/// argument to Loggers. -#[derive(Debug)] -pub struct LogRecord<'a> { - /// The module path of where the LogRecord originated. - pub module_path: &'a str, - - /// The LogLevel of this record. - pub level: LogLevel, - - /// The arguments from the log line. - pub args: fmt::Arguments<'a>, - - /// The file of where the LogRecord originated. - pub file: &'a str, - - /// The line number of where the LogRecord originated. - pub line: u32, -} - -#[doc(hidden)] -#[derive(Copy, Clone)] -pub struct LogLocation { - pub module_path: &'static str, - pub file: &'static str, - pub line: u32, -} - -/// Tests whether a given module's name is enabled for a particular level of -/// logging. This is the second layer of defense about determining whether a -/// module's log statement should be emitted or not. -#[doc(hidden)] -pub fn mod_enabled(level: u32, module: &str) -> bool { - static INIT: Once = ONCE_INIT; - INIT.call_once(init); - - // It's possible for many threads are in this function, only one of them - // will perform the global initialization, but all of them will need to check - // again to whether they should really be here or not. Hence, despite this - // check being expanded manually in the logging macro, this function checks - // the log level again. - if level > unsafe { LOG_LEVEL } { - return false; - } - - // This assertion should never get tripped unless we're in an at_exit - // handler after logging has been torn down and a logging attempt was made. - - unsafe { - let directives = (*LOCK).lock().unwrap(); - enabled(level, module, directives.0.iter()) - } -} - -fn enabled(level: u32, module: &str, iter: slice::Iter) -> bool { - // Search for the longest match, the vector is assumed to be pre-sorted. - for directive in iter.rev() { - match directive.name { - Some(ref name) if !module.starts_with(&name[..]) => {} - Some(..) | None => return level <= directive.level, - } - } - level <= DEFAULT_LOG_LEVEL -} - -/// Initialize logging for the current process. -/// -/// This is not threadsafe at all, so initialization is performed through a -/// `Once` primitive (and this function is called from that primitive). -fn init() { - let (mut directives, filter) = match env::var("RUST_LOG") { - Ok(spec) => directive::parse_logging_spec(&spec[..]), - Err(..) => (Vec::new(), None), - }; - - // Sort the provided directives by length of their name, this allows a - // little more efficient lookup at runtime. - directives.sort_by(|a, b| { - let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); - let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); - alen.cmp(&blen) - }); - - let max_level = { - let max = directives.iter().max_by_key(|d| d.level); - max.map(|d| d.level).unwrap_or(DEFAULT_LOG_LEVEL) - }; - - unsafe { - LOG_LEVEL = max_level; - - assert!(LOCK.is_null()); - LOCK = Box::into_raw(Box::new(Mutex::new((directives, filter)))); - } -} - -#[cfg(test)] -mod tests { - use super::enabled; - use directive::LogDirective; - - #[test] - fn match_full_path() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(!enabled(3, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn no_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(!enabled(2, "crate3", dirs.iter())); - } - - #[test] - fn match_beginning() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(3, "crate2::mod1", dirs.iter())); - } - - #[test] - fn match_beginning_longest_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate2::mod".to_string()), - level: 4, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(4, "crate2::mod1", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn match_default() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } - - #[test] - fn zero_level() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 0, - }]; - assert!(!enabled(1, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } -} diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs deleted file mode 100644 index 803a2df9ccc8..000000000000 --- a/src/liblog/macros.rs +++ /dev/null @@ -1,205 +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. - -//! Logging macros - -/// The standard logging macro -/// -/// This macro will generically log over a provided level (of type u32) with a -/// format!-based argument list. See documentation in `std::fmt` for details on -/// how to use the syntax. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// log!(log::WARN, "this is a warning {}", "message"); -/// log!(log::DEBUG, "this is a debug message"); -/// log!(6, "this is a custom logging level: {level}", level=6); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=6 ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// 6:main: this is a custom logging level: 6 -/// ``` -#[macro_export] -macro_rules! log { - ($lvl:expr, $($arg:tt)+) => ({ - static LOC: ::log::LogLocation = ::log::LogLocation { - line: line!(), - file: file!(), - module_path: module_path!(), - }; - let lvl = $lvl; - if log_enabled!(lvl) { - ::log::log(lvl, &LOC, format_args!($($arg)+)) - } - }) -} - -/// A convenience macro for logging at the error log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let error = 3; -/// error!("the build has failed with error code: {}", error); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ERROR:main: the build has failed with error code: 3 -/// ``` -/// -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => (log!(::log::ERROR, $($arg)*)) -} - -/// A convenience macro for logging at the warning log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let code = 3; -/// warn!("you may like to know that a process exited with: {}", code); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: you may like to know that a process exited with: 3 -/// ``` -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => (log!(::log::WARN, $($arg)*)) -} - -/// A convenience macro for logging at the info log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let ret = 3; -/// info!("this function is about to return: {}", ret); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=info ./main -/// INFO:main: this function is about to return: 3 -/// ``` -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => (log!(::log::INFO, $($arg)*)) -} - -/// A convenience macro for logging at the debug log level. This macro will -/// be omitted at compile time in an optimized build unless `-C debug-assertions` -/// is passed to the compiler. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// debug!("x = {x}, y = {y}", x=10, y=20); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x = 10, y = 20 -/// ``` -#[macro_export] -macro_rules! debug { - ($($arg:tt)*) => (if cfg!(debug_assertions) { log!(::log::DEBUG, $($arg)*) }) -} - -/// A macro to test whether a log level is enabled for the current module. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// struct Point { x: i32, y: i32 } -/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } } -/// -/// fn main() { -/// if log_enabled!(log::DEBUG) { -/// let x = some_expensive_computation(); -/// debug!("x.x = {}, x.y = {}", x.x, x.y); -/// } -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x.x = 1, x.y = 2 -/// ``` -#[macro_export] -macro_rules! log_enabled { - ($lvl:expr) => ({ - let lvl = $lvl; - (lvl != ::log::DEBUG || cfg!(debug_assertions)) && - lvl <= ::log::log_level() && - ::log::mod_enabled(lvl, module_path!()) - }) -} diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 5d53c60ad7fd..fa217acd9f9b 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 583b3b848f30..d7aa36b24f94 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -948,7 +948,7 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, intravisit::walk_crate(&mut collector, &forest.krate); let map = collector.map; - if log_enabled!(::log::DEBUG) { + if log_enabled!(::log::LogLevel::Debug) { // This only makes sense for ordered stores; note the // enumerate to count the number of entries. let (entries_less_1, _) = map.iter().filter(|&x| { diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 874e032bc464..386991052905 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -202,7 +202,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } else { // for local crates, check whether type info is // available; typeck might not have completed yet - self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) + self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) && + self.maps.ty.borrow().contains_key(&impl_def_id) }; if !use_types { diff --git a/src/librustc_back/Cargo.toml b/src/librustc_back/Cargo.toml index 85e861b405a9..730abc54568e 100644 --- a/src/librustc_back/Cargo.toml +++ b/src/librustc_back/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" [features] jemalloc = [] diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index d53318f17684..af99c0e93872 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 780b2c16a32e..907410f74dca 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d987..343b1ed68b80 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" serialize = { path = "../libserialize" } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index caa5c8b7e005..5b5113caa8e8 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = { version = "0.3", features = ["release_max_level_info"] } +env_logger = { version = "0.4", default-features = false } proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 5d600270626c..91f9a803f4a3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -198,13 +198,13 @@ pub fn compile_input(sess: &Session, result?; - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Pre-trans"); tcx.print_debug_stats(); } let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); tcx.print_debug_stats(); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 62d751265572..68b9f85721ad 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,6 +35,7 @@ extern crate arena; extern crate getopts; extern crate graphviz; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_back; @@ -1127,6 +1128,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry { } pub fn main() { + env_logger::init().unwrap(); let result = run(|| run_compiler(&env::args().collect::>(), &mut RustcDefaultCalls, None, diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index e3ee75275450..7bf2efa4b885 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -13,6 +13,6 @@ graphviz = { path = "../libgraphviz" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0ae..c3c5461ff7c5 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 6f7f03ca216b..e8b906092730 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index fcdb968dc061..e1255110a83d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1058,7 +1058,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { self.inject_allocator_crate(); self.inject_panic_runtime(krate); - if log_enabled!(log::INFO) { + if log_enabled!(log::LogLevel::Info) { dump_crates(&self.cstore); } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 531be0b6ae9f..6e42e02d5109 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index cc710e0ac356..d2560c2f8203 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -9,10 +9,10 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file +rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 5ce4c74e735f..0968ea31b754 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } arena = { path = "../libarena" } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 06c5150fd13a..07a5c266fc02 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index b5c67ad998b6..07dcb2fc29dc 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -11,7 +11,7 @@ test = false [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index f08d26373e50..07998aa4a30e 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 93c0bd6d6d83..1c479ce1d015 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,11 +11,13 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } +env_logger = { version = "0.4", default-features = false } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } -rustc_driver = { path = "../librustc_driver" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_driver = { path = "../librustc_driver" } rustc_errors = { path = "../librustc_errors" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } @@ -24,7 +26,6 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -log = { path = "../liblog" } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 84f69cd35045..8dd03f6edc4d 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -30,6 +30,7 @@ extern crate arena; extern crate getopts; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_const_eval; @@ -99,6 +100,7 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32_000_000; // 32MB + env_logger::init().unwrap(); let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b63..97d37266130a 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 960db792a623..bdcec26cb838 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } diff --git a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs b/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs deleted file mode 100644 index db26b10fc67c..000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs +++ /dev/null @@ -1,18 +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. - -#![feature(rustc_private)] - -#[macro_use] extern crate log; - -pub fn foo() { - fn death() -> isize { panic!() } - debug!("{}", (||{ death() })()); -} diff --git a/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs b/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs deleted file mode 100644 index c6beb5ba3587..000000000000 --- a/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs +++ /dev/null @@ -1,23 +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. - -// compile-flags: -C debug-assertions=no -// exec-env:RUST_LOG=conditional-debug-macro-off=4 - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - // only panics if println! evaluates its argument. - debug!("{:?}", { if true { panic!() } }); -} diff --git a/src/test/run-pass-fulldeps/logging-enabled-debug.rs b/src/test/run-pass-fulldeps/logging-enabled-debug.rs deleted file mode 100644 index 3ae4884ce47f..000000000000 --- a/src/test/run-pass-fulldeps/logging-enabled-debug.rs +++ /dev/null @@ -1,24 +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. - -// compile-flags:-C debug-assertions=no -// exec-env:RUST_LOG=logging-enabled-debug=debug - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - if log_enabled!(log::DEBUG) { - panic!("what?! debugging?"); - } -} diff --git a/src/test/run-pass-fulldeps/logging-enabled.rs b/src/test/run-pass-fulldeps/logging-enabled.rs deleted file mode 100644 index 26261348020f..000000000000 --- a/src/test/run-pass-fulldeps/logging-enabled.rs +++ /dev/null @@ -1,27 +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. - -// exec-env:RUST_LOG=logging_enabled=info -// ignore-emscripten: FIXME(#31622) - - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -pub fn main() { - if log_enabled!(log::DEBUG) { - panic!("what?! debugging?"); - } - if !log_enabled!(log::INFO) { - panic!("what?! no info?"); - } -} diff --git a/src/test/run-pass-fulldeps/logging-right-crate.rs b/src/test/run-pass-fulldeps/logging-right-crate.rs deleted file mode 100644 index 7caeeb401244..000000000000 --- a/src/test/run-pass-fulldeps/logging-right-crate.rs +++ /dev/null @@ -1,31 +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. - -// aux-build:logging_right_crate.rs -// exec-env:RUST_LOG=logging-right-crate=debug - -// This is a test for issue #3046 to make sure that when we monomorphize a -// function from one crate to another the right top-level logging name is -// preserved. -// -// It used to be the case that if logging were turned on for this crate, all -// monomorphized functions from other crates had logging turned on (their -// logging module names were all incorrect). This test ensures that this no -// longer happens by enabling logging for *this* crate and then invoking a -// function in an external crate which will panic when logging is enabled. - -// pretty-expanded FIXME #23616 - -extern crate logging_right_crate; - -pub fn main() { - // this function panicks if logging is turned on - logging_right_crate::foo::(); -} diff --git a/src/test/run-pass-fulldeps/logging-separate-lines.rs b/src/test/run-pass-fulldeps/logging-separate-lines.rs deleted file mode 100644 index 183a522bba74..000000000000 --- a/src/test/run-pass-fulldeps/logging-separate-lines.rs +++ /dev/null @@ -1,40 +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. - -// ignore-windows -// exec-env:RUST_LOG=debug -// compile-flags:-C debug-assertions=y -// ignore-emscripten: FIXME(#31622) - -#![feature(rustc_private)] - -#[macro_use] -extern crate log; - -use std::process::Command; -use std::env; -use std::str; - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "child" { - debug!("foo"); - debug!("bar"); - return - } - - let p = Command::new(&args[0]) - .arg("child") - .output().unwrap(); - assert!(p.status.success()); - let mut lines = str::from_utf8(&p.stderr).unwrap().lines(); - assert!(lines.next().unwrap().contains("foo")); - assert!(lines.next().unwrap().contains("bar")); -} diff --git a/src/test/run-pass-fulldeps/rust-log-filter.rs b/src/test/run-pass-fulldeps/rust-log-filter.rs deleted file mode 100644 index 306d24e31775..000000000000 --- a/src/test/run-pass-fulldeps/rust-log-filter.rs +++ /dev/null @@ -1,58 +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. - -// exec-env:RUST_LOG=rust_log_filter/foo -// ignore-emscripten no threads support - -#![allow(unknown_features)] -#![feature(box_syntax, std_misc, rustc_private)] - -#[macro_use] -extern crate log; - -use std::sync::mpsc::{channel, Sender, Receiver}; -use std::thread; - -pub struct ChannelLogger { - tx: Sender -} - -impl ChannelLogger { - pub fn new() -> (Box, Receiver) { - let (tx, rx) = channel(); - (box ChannelLogger { tx: tx }, rx) - } -} - -impl log::Logger for ChannelLogger { - fn log(&mut self, record: &log::LogRecord) { - self.tx.send(format!("{}", record.args)).unwrap(); - } -} - -pub fn main() { - let (logger, rx) = ChannelLogger::new(); - - let t = thread::spawn(move|| { - log::set_logger(logger); - - info!("foo"); - info!("bar"); - info!("foo bar"); - info!("bar foo"); - }); - - assert_eq!(rx.recv().unwrap(), "foo"); - assert_eq!(rx.recv().unwrap(), "foo bar"); - assert_eq!(rx.recv().unwrap(), "bar foo"); - assert!(rx.recv().is_err()); - - t.join(); -} diff --git a/src/test/run-pass/conditional-debug-macro-on.rs b/src/test/run-pass/conditional-debug-macro-on.rs index b335e20f91d9..7da33be7a57d 100644 --- a/src/test/run-pass/conditional-debug-macro-on.rs +++ b/src/test/run-pass/conditional-debug-macro-on.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// exec-env:RUST_LOG=conditional-debug-macro-on=4 - pub fn main() { // exits early if println! evaluates its arguments, otherwise it // will hit the panic. diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 1fc98a78a7c4..7530b65a9b7c 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -5,6 +5,6 @@ version = "0.0.0" [dependencies] log = "0.3" -env_logger = { version = "0.3.5", default-features = false } +env_logger = { version = "0.4", default-features = false } rustc-serialize = "0.3" filetime = "0.1" From 69c9d9b3b806148846459cd0e4e30f300686dd97 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Mar 2017 16:45:21 -0400 Subject: [PATCH 027/905] ignore reads of tracked state when there is no current task I realized that, even in the current system, such reads can't really do any harm. Because they are not part of a task, they will occur no matter what (only tasks can be skipped). If you leak the data you read into a task, that is bad, but that is equally bad if you are in a task. *Writes* to tracked state, on the other hand, should never occur except from within a task (and the task then records what things you read to compute it). Once we complete the shift to on-demand, these properties will hold by construction (because the on-demand struct enforces stateless tasks where leaks are impossible -- except by having shared mutable state in the tcx). --- src/librustc/dep_graph/edges.rs | 12 ++++++++---- src/librustc/dep_graph/shadow.rs | 10 ++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 8657a3e5a587..5dbabcc92304 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -101,11 +101,15 @@ impl DepGraphEdges { } /// Indicates that the current task `C` reads `v` by adding an - /// edge from `v` to `C`. If there is no current task, panics. If - /// you want to suppress this edge, use `ignore`. + /// edge from `v` to `C`. If there is no current task, has no + /// effect. Note that *reading* from tracked state is harmless if + /// you are not in a task; what is bad is *writing* to tracked + /// state (and leaking data that you read into a tracked task). pub fn read(&mut self, v: DepNode) { - let source = self.make_node(v); - self.add_edge_from_current_node(|current| (source, current)) + if self.current_node().is_some() { + let source = self.make_node(v); + self.add_edge_from_current_node(|current| (source, current)) + } } /// Indicates that the current task `C` writes `v` by adding an diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index 5d4190a8ae1a..bedb6ff2771f 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -80,7 +80,13 @@ impl ShadowGraph { let mut stack = self.stack.borrow_mut(); match *message { - DepMessage::Read(ref n) => self.check_edge(Some(Some(n)), top(&stack)), + // It is ok to READ shared state outside of a + // task. That can't do any harm (at least, the only + // way it can do harm is by leaking that data into a + // query or task, which would be a problem + // anyway). What would be bad is WRITING to that + // state. + DepMessage::Read(_) => { } DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))), DepMessage::PushTask(ref n) => stack.push(Some(n.clone())), DepMessage::PushIgnore => stack.push(None), @@ -116,7 +122,7 @@ impl ShadowGraph { (None, None) => unreachable!(), // nothing on top of the stack - (None, Some(n)) | (Some(n), None) => bug!("read/write of {:?} but no current task", n), + (None, Some(n)) | (Some(n), None) => bug!("write of {:?} but no current task", n), // this corresponds to an Ignore being top of the stack (Some(None), _) | (_, Some(None)) => (), From a9f6babcda1479f4e5566d1aadbf9a0d99aa3182 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 23 Mar 2017 15:13:29 -0400 Subject: [PATCH 028/905] convert privacy access levels into a query --- src/librustc/dep_graph/dep_node.rs | 5 +++-- src/librustc/lint/context.rs | 8 +++++--- src/librustc/middle/dead.rs | 7 ++++--- src/librustc/middle/reachable.rs | 8 +++++--- src/librustc/middle/stability.rs | 5 +++-- src/librustc/ty/maps.rs | 10 ++++++++++ src/librustc/ty/mod.rs | 7 +++++-- src/librustc_driver/driver.rs | 20 ++++++++------------ src/librustc_privacy/lib.rs | 29 +++++++++++++++++++++++------ src/librustdoc/core.rs | 4 ++-- 10 files changed, 68 insertions(+), 35 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 399af258e925..5ee9258852b0 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::def_id::CrateNum; use std::fmt::Debug; use std::sync::Arc; @@ -81,7 +82,7 @@ pub enum DepNode { TypeckItemType(D), UnusedTraitCheck, CheckConst(D), - Privacy, + PrivacyAccessLevels(CrateNum), IntrinsicCheck(D), MatchCheck(D), @@ -230,7 +231,7 @@ impl DepNode { CheckEntryFn => Some(CheckEntryFn), Variance => Some(Variance), UnusedTraitCheck => Some(UnusedTraitCheck), - Privacy => Some(Privacy), + PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)), Reachability => Some(Reachability), DeadCheck => Some(DeadCheck), LateLintCheck => Some(LateLintCheck), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 843f3a53f33e..d35f965e2ffd 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -44,9 +44,10 @@ use std::ops::Deref; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; -use syntax_pos::{MultiSpan, Span}; +use syntax_pos::{DUMMY_SP, MultiSpan, Span}; use errors::{self, Diagnostic, DiagnosticBuilder}; use hir; +use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; @@ -1231,10 +1232,11 @@ fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, /// Perform lint checking on a crate. /// /// Consumes the `lint_store` field of the `Session`. -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &AccessLevels) { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck); + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let krate = tcx.hir.krate(); // We want to own the lint store, so move it out of the session. diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index cc6d6e88dee4..8926ff5c1fbb 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -21,12 +21,13 @@ use hir::itemlikevisit::ItemLikeVisitor; use middle::privacy; use ty::{self, TyCtxt}; use hir::def::Def; -use hir::def_id::{DefId}; +use hir::def_id::{DefId, LOCAL_CRATE}; use lint; use util::nodemap::FxHashSet; use syntax::{ast, codemap}; use syntax::attr; +use syntax::codemap::DUMMY_SP; use syntax_pos; // Any local node that may call something in its body block should be @@ -592,9 +593,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels) { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::DeadCheck); + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); let krate = tcx.hir.krate(); let live_symbols = find_live(tcx, access_levels, krate); let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 4ec43e368a60..b0e39442af98 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -27,7 +27,9 @@ use util::nodemap::{NodeSet, FxHashSet}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; +use syntax::codemap::DUMMY_SP; use hir; +use hir::def_id::LOCAL_CRATE; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::itemlikevisit::ItemLikeVisitor; use hir::intravisit; @@ -359,11 +361,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels) - -> NodeSet { +pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { let _task = tcx.dep_graph.in_task(DepNode::Reachability); + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || *ty == config::CrateTypeProcMacro diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 1fb537140257..4115b4669f4b 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -656,10 +656,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Given the list of enabled features that were not language features (i.e. that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. -pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &AccessLevels) { +pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let sess = &tcx.sess; + let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api { let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); let krate = tcx.hir.krate(); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ac8c38c7d585..da4e58addd71 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -11,6 +11,7 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use middle::const_val::ConstVal; +use middle::privacy::AccessLevels; use mir; use ty::{self, Ty, TyCtxt}; @@ -189,6 +190,12 @@ impl<'tcx> QueryDescription for queries::mir_shims<'tcx> { } } +impl<'tcx> QueryDescription for queries::privacy_access_levels<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("privacy access levels") + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -406,6 +413,9 @@ define_maps! { <'tcx> /// other items, such as enum variant explicit discriminants. pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result, ()>, + /// Performs the privacy check and computes "access levels". + pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, + pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0bcfae1e54a6..4283b10ec624 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -17,11 +17,11 @@ pub use self::fold::TypeFoldable; use dep_graph::{self, DepNode}; use hir::{map as hir_map, FreevarMap, TraitMap}; -use middle; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; +use middle::privacy::AccessLevels; use middle::region::{CodeExtent, ROOT_CODE_EXTENT}; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; @@ -108,9 +108,12 @@ mod sty; /// The complete set of all analyses described in this module. This is /// produced by the driver and fed to trans and later passes. +/// +/// NB: These contents are being migrated into queries using the +/// *on-demand* infrastructure. #[derive(Clone)] pub struct CrateAnalysis { - pub access_levels: middle::privacy::AccessLevels, + pub access_levels: Rc, pub reachable: NodeSet, pub name: String, pub glob_map: Option, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4947cafb52b3..e8b9be4a903c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -48,6 +48,7 @@ use std::fs; use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; +use std::rc::Rc; use syntax::{ast, diagnostics, visit}; use syntax::attr; use syntax::ext::base::ExtCtxt; @@ -807,7 +808,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, expanded_crate: krate, defs: resolver.definitions, analysis: ty::CrateAnalysis { - access_levels: AccessLevels::default(), + access_levels: Rc::new(AccessLevels::default()), reachable: NodeSet(), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, @@ -888,6 +889,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut local_providers = ty::maps::Providers::default(); mir::provide(&mut local_providers); + rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); @@ -931,9 +933,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, || consts::check_crate(tcx)); analysis.access_levels = - time(time_passes, "privacy checking", || { - rustc_privacy::check_crate(tcx) - }); + time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx)); time(time_passes, "intrinsic checking", @@ -1000,19 +1000,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, analysis.reachable = time(time_passes, "reachability checking", - || reachable::find_reachable(tcx, &analysis.access_levels)); + || reachable::find_reachable(tcx)); - time(time_passes, "death checking", || { - middle::dead::check_crate(tcx, &analysis.access_levels); - }); + time(time_passes, "death checking", || middle::dead::check_crate(tcx)); time(time_passes, "unused lib feature checking", || { - stability::check_unused_or_stable_features(tcx, &analysis.access_levels) + stability::check_unused_or_stable_features(tcx) }); - time(time_passes, - "lint checking", - || lint::check_crate(tcx, &analysis.access_levels)); + time(time_passes, "lint checking", || lint::check_crate(tcx)); // The above three passes generate errors w/o aborting if sess.err_count() > 0 { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 6b33c7b7816f..64821f5d44bf 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,6 +17,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] +#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -25,10 +26,9 @@ extern crate rustc; #[macro_use] extern crate syntax; extern crate syntax_pos; -use rustc::dep_graph::DepNode; use rustc::hir::{self, PatKind}; use rustc::hir::def::Def; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -36,12 +36,14 @@ use rustc::lint; use rustc::middle::privacy::{AccessLevel, AccessLevels}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::fold::TypeVisitor; +use rustc::ty::maps::Providers; use rustc::util::nodemap::NodeSet; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; use std::cmp; use std::mem::replace; +use std::rc::Rc; pub mod diagnostics; @@ -1203,8 +1205,23 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> fn visit_pat(&mut self, _: &'tcx hir::Pat) {} } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> AccessLevels { - let _task = tcx.dep_graph.in_task(DepNode::Privacy); +pub fn provide(providers: &mut Providers) { + *providers = Providers { + privacy_access_levels, + ..*providers + }; +} + +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { + tcx.dep_graph.with_ignore(|| { // FIXME + ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE) + }) +} + +fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + krate: CrateNum) + -> Rc { + assert_eq!(krate, LOCAL_CRATE); let krate = tcx.hir.krate(); @@ -1266,7 +1283,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> AccessLevels { krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); } - visitor.access_levels + Rc::new(visitor.access_levels) } __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 92aba1fc61de..a47d5f9937a0 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -184,8 +184,8 @@ pub fn run_core(search_paths: SearchPaths, // Convert from a NodeId set to a DefId set since we don't always have easy access // to the map from defid -> nodeid let access_levels = AccessLevels { - map: access_levels.map.into_iter() - .map(|(k, v)| (tcx.hir.local_def_id(k), v)) + map: access_levels.map.iter() + .map(|(&k, &v)| (tcx.hir.local_def_id(k), v)) .collect() }; From b47035460f89fec11b9ab1348717e5ab61b16a67 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Mar 2017 16:22:29 -0700 Subject: [PATCH 029/905] Update cargo submodule I'm not really sure what we want the cadence here to be. We'll at the very least update the Cargo submodule right before all releases, but otherwise I figured we could just do it whenever needed or otherwise weekly (or something like that). In any case, I don't have a super strong particular reason to do this, it's just been a week or so since the release! --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index c995e9eb5acf..4e95c6b41eca 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c995e9eb5acf3976ae8674a0dc6d9e958053d9fd +Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 From 8a91e4d1238b40200724826cc7ef3f7893c6152b Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 24 Mar 2017 05:05:34 +0300 Subject: [PATCH 030/905] Document Cursor::new position is 0 ... even if contained `Vec` is not empty. E. g. for ``` let v = vec![10u8, 20]; let mut c = io::Cursor::new(v); c.write_all(b"aaaa").unwrap(); println!("{:?}", c.into_inner()); ``` result is ``` [97, 97, 97, 97] ``` and not ``` [10, 20, 97, 97, 97, 97] ``` --- src/libstd/io/cursor.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 60767ea47866..53347eb14db0 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -89,6 +89,10 @@ pub struct Cursor { impl Cursor { /// Creates a new cursor wrapping the provided underlying I/O object. /// + /// Cursor initial position is `0` even if underlying object (e. + /// g. `Vec`) is not empty. So writing to cursor starts with + /// overwriting `Vec` content, not with appending to it. + /// /// # Examples /// /// ``` From 8fba638b08eb85cda1bd2a4e855f7f76727dfc52 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 18 Mar 2017 10:37:52 -0400 Subject: [PATCH 031/905] Rewrite `io::BufRead` doc examples to better demonstrate behaviors. Prior to this commit, most of the `BufRead` examples used `StdinLock` to demonstrate how certain `BufRead` methods worked. Using `StdinLock` is not ideal since: * Relying on run-time data means we can't show concrete examples of how these methods work up-front. The user is required to run them in order to see how they behave. * If the user tries to run an example in the playpen, it won't work because the playpen doesn't support user input to stdin. --- src/libstd/io/mod.rs | 129 +++++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 49 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 850885a8c0f3..5b628d51d151 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1290,28 +1290,42 @@ pub trait BufRead: Read { /// If an I/O error is encountered then all bytes read so far will be /// present in `buf` and its length will have been adjusted appropriately. /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read from standard input until we see an `a` byte. - /// /// [`fill_buf`]: #tymethod.fill_buf /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the bytes in a byte slice + /// in hyphen delimited segments: + /// + /// [`Cursor`]: struct.Cursor.html + /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// fn foo() -> io::Result<()> { - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = Vec::new(); + /// let mut cursor = io::Cursor::new(b"lorem-ipsum"); + /// let mut buf = vec![]; /// - /// stdin.read_until(b'a', &mut buffer)?; + /// // cursor is at 'l' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 6); + /// assert_eq!(buf, b"lorem-"); + /// buf.clear(); /// - /// println!("{:?}", buffer); - /// # Ok(()) - /// # } + /// // cursor is at 'i' + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 5); + /// assert_eq!(buf, b"ipsum"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_until(b'-', &mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, b""); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { @@ -1337,28 +1351,36 @@ pub trait BufRead: Read { /// /// # Examples /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read all of the lines from standard input. If we were to do this in - /// an actual project, the [`lines`] method would be easier, of - /// course. + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to read all the lines in a byte slice: /// - /// [`lines`]: #method.lines - /// [`read_until`]: #method.read_until + /// [`Cursor`]: struct.Cursor.html /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = String::new(); + /// let mut cursor = io::Cursor::new(b"foo\nbar"); + /// let mut buf = String::new(); /// - /// while stdin.read_line(&mut buffer).unwrap() > 0 { - /// // work with buffer - /// println!("{:?}", buffer); + /// // cursor is at 'f' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 4); + /// assert_eq!(buf, "foo\n"); + /// buf.clear(); /// - /// buffer.clear(); - /// } + /// // cursor is at 'b' + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 3); + /// assert_eq!(buf, "bar"); + /// buf.clear(); + /// + /// // cursor is at EOF + /// let num_bytes = cursor.read_line(&mut buf) + /// .expect("reading from cursor won't fail"); + /// assert_eq!(num_bytes, 0); + /// assert_eq!(buf, ""); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_line(&mut self, buf: &mut String) -> Result { @@ -1378,24 +1400,28 @@ pub trait BufRead: Read { /// This function will yield errors whenever [`read_until`] would have /// also yielded an error. /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read some input from standard input, splitting on commas. - /// /// [`io::Result`]: type.Result.html /// [`Vec`]: ../vec/struct.Vec.html /// [`read_until`]: #method.read_until /// + /// # Examples + /// + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all hyphen delimited + /// segments in a byte slice + /// + /// [`Cursor`]: struct.Cursor.html + /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// let stdin = io::stdin(); + /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor"); /// - /// for content in stdin.lock().split(b',') { - /// println!("{:?}", content.unwrap()); - /// } + /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap()); + /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec())); + /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec())); + /// assert_eq!(split_iter.next(), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn split(self, byte: u8) -> Split where Self: Sized { @@ -1413,17 +1439,22 @@ pub trait BufRead: Read { /// /// # Examples /// - /// A locked standard input implements `BufRead`: + /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In + /// this example, we use [`Cursor`] to iterate over all the lines in a byte + /// slice. + /// + /// [`Cursor`]: struct.Cursor.html /// /// ``` - /// use std::io; - /// use std::io::prelude::*; + /// use std::io::{self, BufRead}; /// - /// let stdin = io::stdin(); + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); /// - /// for line in stdin.lock().lines() { - /// println!("{}", line.unwrap()); - /// } + /// let mut lines_iter = cursor.lines().map(|l| l.unwrap()); + /// assert_eq!(lines_iter.next(), Some(String::from("lorem"))); + /// assert_eq!(lines_iter.next(), Some(String::from("ipsum"))); + /// assert_eq!(lines_iter.next(), Some(String::from("dolor"))); + /// assert_eq!(lines_iter.next(), None); /// ``` /// /// # Errors From 03949f5b5caa330375bb33d7b91b5fc24bd8c92e Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Fri, 24 Mar 2017 17:47:23 +0100 Subject: [PATCH 032/905] issue #40793 Correcting the two mistakes in the README.md --- src/librustc_borrowck/borrowck/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index 5cfbd59d3336..29b007a7499c 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -347,7 +347,7 @@ ALIASABLE(*LV, MQ) // M-Deref-Unique ALIASABLE(LV, MQ) ``` -### Checking mutability of immutable pointer types +### Checking aliasability of immutable pointer types Immutable pointer types like `&T` are aliasable, and hence can only be borrowed immutably: @@ -357,7 +357,7 @@ ALIASABLE(*LV, imm) // M-Deref-Borrowed-Imm TYPE(LV) = &Ty ``` -### Checking mutability of mutable pointer types +### Checking aliasability of mutable pointer types `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut: From 64e9af47f4e517208fc1dd950340a0c046ad87b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 11 Mar 2017 10:58:19 +0000 Subject: [PATCH 033/905] Allow declarative macros 2.0 and `use` macro imports to shadow builtin macros. --- src/librustc_resolve/lib.rs | 36 ++++--- src/librustc_resolve/macros.rs | 102 +++++++++++------- src/librustc_resolve/resolve_imports.rs | 12 ++- .../imports/shadow_builtin_macros.rs | 72 +++++++++++++ 4 files changed, 163 insertions(+), 59 deletions(-) create mode 100644 src/test/compile-fail/imports/shadow_builtin_macros.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f832e0f9a481..be8513c94d03 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -75,7 +75,7 @@ use std::mem::replace; use std::rc::Rc; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; -use macros::{InvocationData, LegacyBinding, LegacyScope}; +use macros::{InvocationData, LegacyBinding, LegacyScope, MacroBinding}; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -2566,6 +2566,7 @@ impl<'a> Resolver<'a> { self.resolve_ident_in_module(module, ident, ns, false, record_used) } else if opt_ns == Some(MacroNS) { self.resolve_lexical_macro_path_segment(ident, ns, record_used) + .map(MacroBinding::binding) } else { match self.resolve_ident_in_lexical_scope(ident, ns, record_used) { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), @@ -3223,7 +3224,7 @@ impl<'a> Resolver<'a> { }; let msg1 = format!("`{}` could refer to the name {} here", name, participle(b1)); let msg2 = format!("`{}` could also refer to the name {} here", name, participle(b2)); - let note = if !lexical && b1.is_glob_import() { + let note = if b1.expansion == Mark::root() || !lexical && b1.is_glob_import() { format!("consider adding an explicit import of `{}` to disambiguate", name) } else if let Def::Macro(..) = b1.def() { format!("macro-expanded {} do not shadow", @@ -3243,11 +3244,15 @@ impl<'a> Resolver<'a> { let msg = format!("`{}` is ambiguous", name); self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg); } else { - self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) - .span_note(b1.span, &msg1) - .span_note(b2.span, &msg2) - .note(¬e) - .emit(); + let mut err = + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)); + err.span_note(b1.span, &msg1); + match b2.def() { + Def::Macro(..) if b2.span == DUMMY_SP => + err.note(&format!("`{}` is also a builtin macro", name)), + _ => err.span_note(b2.span, &msg2), + }; + err.note(¬e).emit(); } } @@ -3361,14 +3366,13 @@ impl<'a> Resolver<'a> { if self.proc_macro_enabled { return; } for attr in attrs { - let name = unwrap_or!(attr.name(), continue); - let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| { - let ident = Ident::with_empty_ctxt(name); - self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok() - }); - - if let Some(binding) = maybe_binding { - if let SyntaxExtension::AttrProcMacro(..) = *binding.get_macro(self) { + if attr.path.segments.len() > 1 { + continue + } + let ident = attr.path.segments[0].identifier; + let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None); + if let Ok(binding) = result { + if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) { attr::mark_known(attr); let msg = "attribute procedural macros are experimental"; @@ -3376,7 +3380,7 @@ impl<'a> Resolver<'a> { feature_err(&self.session.parse_sess, feature, attr.span, GateIssue::Language, msg) - .span_note(binding.span, "procedural macro imported here") + .span_note(binding.span(), "procedural macro imported here") .emit(); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 99fc1c142f68..9af921a84459 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -81,11 +81,29 @@ pub struct LegacyBinding<'a> { pub span: Span, } +#[derive(Copy, Clone)] pub enum MacroBinding<'a> { Legacy(&'a LegacyBinding<'a>), + Builtin(&'a NameBinding<'a>), Modern(&'a NameBinding<'a>), } +impl<'a> MacroBinding<'a> { + pub fn span(self) -> Span { + match self { + MacroBinding::Legacy(binding) => binding.span, + MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding.span, + } + } + + pub fn binding(self) -> &'a NameBinding<'a> { + match self { + MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding, + MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"), + } + } +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -378,18 +396,18 @@ impl<'a> Resolver<'a> { } let name = path[0].name; - let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)), - Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()), - None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { - Ok(binding) => Ok(binding.def_ignoring_ambiguity()), - Err(Determinacy::Undetermined) if !force => - return Err(Determinacy::Undetermined), + let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, name, false); + let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { + Ok(Def::Macro(binding.def_id, MacroKind::Bang)) + } else { + match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { + Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()), + Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { self.found_unresolved_macro = true; Err(Determinacy::Determined) } - }, + } }; self.current_module.legacy_macro_resolutions.borrow_mut() @@ -403,42 +421,56 @@ impl<'a> Resolver<'a> { ident: Ident, ns: Namespace, record_used: Option) - -> Result<&'a NameBinding<'a>, Determinacy> { - let mut module = self.current_module; - let mut potential_expanded_shadower: Option<&NameBinding> = None; + -> Result, Determinacy> { + let mut module = Some(self.current_module); + let mut potential_illegal_shadower = Err(Determinacy::Determined); + let determinacy = + if record_used.is_some() { Determinacy::Determined } else { Determinacy::Undetermined }; loop { - // Since expanded macros may not shadow the lexical scope (enforced below), - // we can ignore unresolved invocations (indicated by the penultimate argument). - match self.resolve_ident_in_module(module, ident, ns, true, record_used) { + let result = if let Some(module) = module { + // Since expanded macros may not shadow the lexical scope and + // globs may not shadow builtin macros (both enforced below), + // we resolve with restricted shadowing (indicated by the penultimate argument). + self.resolve_ident_in_module(module, ident, ns, true, record_used) + .map(MacroBinding::Modern) + } else { + self.builtin_macros.get(&ident.name).cloned().ok_or(determinacy) + .map(MacroBinding::Builtin) + }; + + match result.map(MacroBinding::binding) { Ok(binding) => { let span = match record_used { Some(span) => span, - None => return Ok(binding), + None => return result, }; - match potential_expanded_shadower { - Some(shadower) if shadower.def() != binding.def() => { + if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower { + if shadower.def() != binding.def() { let name = ident.name; self.ambiguity_errors.push(AmbiguityError { span: span, name: name, b1: shadower, b2: binding, lexical: true, legacy: false, }); - return Ok(shadower); + return potential_illegal_shadower; } - _ if binding.expansion == Mark::root() => return Ok(binding), - _ => potential_expanded_shadower = Some(binding), + } + if binding.expansion != Mark::root() || + (binding.is_glob_import() && module.unwrap().def().is_some()) { + potential_illegal_shadower = result; + } else { + return result; } }, Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), Err(Determinacy::Determined) => {} } - match module.kind { - ModuleKind::Block(..) => module = module.parent.unwrap(), - ModuleKind::Def(..) => return match potential_expanded_shadower { - Some(binding) => Ok(binding), - None if record_used.is_some() => Err(Determinacy::Determined), - None => Err(Determinacy::Undetermined), + module = match module { + Some(module) => match module.kind { + ModuleKind::Block(..) => module.parent, + ModuleKind::Def(..) => None, }, + None => return potential_illegal_shadower, } } } @@ -492,7 +524,7 @@ impl<'a> Resolver<'a> { if !self.use_extern_macros { self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP); } - MacroBinding::Modern(binding) + MacroBinding::Builtin(binding) } else { return None; }; @@ -524,21 +556,15 @@ impl<'a> Resolver<'a> { let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true); let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span)); match (legacy_resolution, resolution) { - (Some(legacy_resolution), Ok(resolution)) => { - let (legacy_span, participle) = match legacy_resolution { - MacroBinding::Modern(binding) - if binding.def() == resolution.def() => continue, - MacroBinding::Modern(binding) => (binding.span, "imported"), - MacroBinding::Legacy(binding) => (binding.span, "defined"), - }; - let msg1 = format!("`{}` could refer to the macro {} here", ident, participle); + (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => { + let msg1 = format!("`{}` could refer to the macro defined here", ident); let msg2 = format!("`{}` could also refer to the macro imported here", ident); self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident)) - .span_note(legacy_span, &msg1) - .span_note(resolution.span, &msg2) + .span_note(legacy_binding.span, &msg1) + .span_note(binding.span, &msg2) .emit(); }, - (Some(MacroBinding::Modern(binding)), Err(_)) => { + (Some(MacroBinding::Builtin(binding)), Ok(MacroBinding::Builtin(_))) => { self.record_use(ident, MacroNS, binding, span); self.err_if_macro_use_proc_macro(ident.name, span, binding); }, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2f4ac12cd736..43654c8ce6f6 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -145,7 +145,7 @@ impl<'a> Resolver<'a> { module: Module<'a>, ident: Ident, ns: Namespace, - ignore_unresolved_invocations: bool, + restricted_shadowing: bool, record_used: Option) -> Result<&'a NameBinding<'a>, Determinacy> { self.populate_module_if_necessary(module); @@ -158,9 +158,8 @@ impl<'a> Resolver<'a> { if let Some(binding) = resolution.binding { if let Some(shadowed_glob) = resolution.shadows_glob { let name = ident.name; - // If we ignore unresolved invocations, we must forbid - // expanded shadowing to avoid time travel. - if ignore_unresolved_invocations && + // Forbid expanded shadowing to avoid time travel. + if restricted_shadowing && binding.expansion != Mark::root() && ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing binding.def() != shadowed_glob.def() { @@ -215,7 +214,7 @@ impl<'a> Resolver<'a> { } let no_unresolved_invocations = - ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty(); + restricted_shadowing || module.unresolved_invocations.borrow().is_empty(); match resolution.binding { // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`). Some(binding) if no_unresolved_invocations || ns == MacroNS => @@ -225,6 +224,9 @@ impl<'a> Resolver<'a> { } // Check if the globs are determined + if restricted_shadowing && module.def().is_some() { + return Err(Determined); + } for directive in module.globs.borrow().iter() { if self.is_accessible(directive.vis.get()) { if let Some(module) = directive.imported_module.get() { diff --git a/src/test/compile-fail/imports/shadow_builtin_macros.rs b/src/test/compile-fail/imports/shadow_builtin_macros.rs new file mode 100644 index 000000000000..2b3ba1b4aa7a --- /dev/null +++ b/src/test/compile-fail/imports/shadow_builtin_macros.rs @@ -0,0 +1,72 @@ +// 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. + +// aux-build:two_macros.rs + +#![feature(use_extern_macros)] + +mod foo { + extern crate two_macros; + pub use self::two_macros::m as panic; +} + +mod m1 { + use foo::panic; // ok + fn f() { panic!(); } +} + +mod m2 { + use foo::*; //~ NOTE `panic` could refer to the name imported here + fn f() { panic!(); } //~ ERROR ambiguous + //~| NOTE `panic` is also a builtin macro + //~| NOTE consider adding an explicit import of `panic` to disambiguate +} + +mod m3 { + ::two_macros::m!(use foo::panic;); //~ NOTE `panic` could refer to the name imported here + //~| NOTE in this expansion + fn f() { panic!(); } //~ ERROR ambiguous + //~| NOTE `panic` is also a builtin macro + //~| NOTE macro-expanded macro imports do not shadow +} + +mod m4 { + macro_rules! panic { () => {} } // ok + panic!(); +} + +mod m5 { + macro_rules! m { () => { + macro_rules! panic { () => {} } //~ ERROR `panic` is already in scope + //~| NOTE macro-expanded `macro_rules!`s may not shadow existing macros + } } + m!(); //~ NOTE in this expansion + //~| NOTE in this expansion + panic!(); +} + +#[macro_use(n)] //~ NOTE `n` could also refer to the name imported here +extern crate two_macros; +mod bar { + pub use two_macros::m as n; +} + +mod m6 { + use bar::n; // ok + n!(); +} + +mod m7 { + use bar::*; //~ NOTE `n` could refer to the name imported here + n!(); //~ ERROR ambiguous + //~| NOTE consider adding an explicit import of `n` to disambiguate +} + +fn main() {} From d64d3814c4a23fcb8440959bec77090fbbb25d7d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 16 Mar 2017 01:39:47 +0000 Subject: [PATCH 034/905] Rename `builtin` => `global`. --- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 8 +++--- src/librustc_resolve/macros.rs | 30 ++++++++++----------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c33d5b9b6e16..86e0d0039d1a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -539,7 +539,7 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, span: Span, allow_shadowing: bool) { - if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing { + if self.global_macros.insert(name, binding).is_some() && !allow_shadowing { let msg = format!("`{}` is already in scope", name); let note = "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index be8513c94d03..879d8816488b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1174,7 +1174,7 @@ pub struct Resolver<'a> { crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, - builtin_macros: FxHashMap>, + global_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, macro_defs: FxHashMap, @@ -1372,7 +1372,7 @@ impl<'a> Resolver<'a> { crate_loader: crate_loader, macro_names: FxHashSet(), - builtin_macros: FxHashMap(), + global_macros: FxHashMap(), lexical_macro_resolutions: Vec::new(), macro_map: FxHashMap(), macro_exports: Vec::new(), @@ -2429,9 +2429,9 @@ impl<'a> Resolver<'a> { }; } } - let is_builtin = self.builtin_macros.get(&path[0].name).cloned() + let is_global = self.global_macros.get(&path[0].name).cloned() .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false); - if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) { + if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].name)) { // Return some dummy definition, it's enough for error reporting. return Some( PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 9af921a84459..3d6c6896549a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -84,7 +84,7 @@ pub struct LegacyBinding<'a> { #[derive(Copy, Clone)] pub enum MacroBinding<'a> { Legacy(&'a LegacyBinding<'a>), - Builtin(&'a NameBinding<'a>), + Global(&'a NameBinding<'a>), Modern(&'a NameBinding<'a>), } @@ -92,13 +92,13 @@ impl<'a> MacroBinding<'a> { pub fn span(self) -> Span { match self { MacroBinding::Legacy(binding) => binding.span, - MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding.span, + MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding.span, } } pub fn binding(self) -> &'a NameBinding<'a> { match self { - MacroBinding::Builtin(binding) | MacroBinding::Modern(binding) => binding, + MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding, MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"), } } @@ -189,7 +189,7 @@ impl<'a> base::Resolver for Resolver<'a> { vis: ty::Visibility::Invisible, expansion: Mark::root(), }); - self.builtin_macros.insert(ident.name, binding); + self.global_macros.insert(ident.name, binding); } fn resolve_imports(&mut self) { @@ -207,7 +207,7 @@ impl<'a> base::Resolver for Resolver<'a> { attr::mark_known(&attrs[i]); } - match self.builtin_macros.get(&name).cloned() { + match self.global_macros.get(&name).cloned() { Some(binding) => match *binding.get_macro(self) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -239,7 +239,7 @@ impl<'a> base::Resolver for Resolver<'a> { } let trait_name = traits[j].segments[0].identifier.name; let legacy_name = Symbol::intern(&format!("derive_{}", trait_name)); - if !self.builtin_macros.contains_key(&legacy_name) { + if !self.global_macros.contains_key(&legacy_name) { continue } let span = traits.remove(j).span; @@ -429,13 +429,13 @@ impl<'a> Resolver<'a> { loop { let result = if let Some(module) = module { // Since expanded macros may not shadow the lexical scope and - // globs may not shadow builtin macros (both enforced below), + // globs may not shadow global macros (both enforced below), // we resolve with restricted shadowing (indicated by the penultimate argument). self.resolve_ident_in_module(module, ident, ns, true, record_used) .map(MacroBinding::Modern) } else { - self.builtin_macros.get(&ident.name).cloned().ok_or(determinacy) - .map(MacroBinding::Builtin) + self.global_macros.get(&ident.name).cloned().ok_or(determinacy) + .map(MacroBinding::Global) }; match result.map(MacroBinding::binding) { @@ -520,11 +520,11 @@ impl<'a> Resolver<'a> { let binding = if let Some(binding) = binding { MacroBinding::Legacy(binding) - } else if let Some(binding) = self.builtin_macros.get(&name).cloned() { + } else if let Some(binding) = self.global_macros.get(&name).cloned() { if !self.use_extern_macros { self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP); } - MacroBinding::Builtin(binding) + MacroBinding::Global(binding) } else { return None; }; @@ -564,7 +564,7 @@ impl<'a> Resolver<'a> { .span_note(binding.span, &msg2) .emit(); }, - (Some(MacroBinding::Builtin(binding)), Ok(MacroBinding::Builtin(_))) => { + (Some(MacroBinding::Global(binding)), Ok(MacroBinding::Global(_))) => { self.record_use(ident, MacroNS, binding, span); self.err_if_macro_use_proc_macro(ident.name, span, binding); }, @@ -593,11 +593,11 @@ impl<'a> Resolver<'a> { find_best_match_for_name(self.macro_names.iter(), name, None) } else { None - // Then check builtin macros. + // Then check global macros. }.or_else(|| { // FIXME: get_macro needs an &mut Resolver, can we do it without cloning? - let builtin_macros = self.builtin_macros.clone(); - let names = builtin_macros.iter().filter_map(|(name, binding)| { + let global_macros = self.global_macros.clone(); + let names = global_macros.iter().filter_map(|(name, binding)| { if binding.get_macro(self).kind() == kind { Some(name) } else { From 2c816f7fb6772fe0b77af04da9355aab6c2d3fb2 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 25 Mar 2017 00:27:47 +0100 Subject: [PATCH 035/905] Optimize insertion sort This change slightly changes the main iteration loop so that LLVM can optimize it more efficiently. Benchmark: name before ns/iter after ns/iter diff ns/iter diff % slice::sort_unstable_small_ascending 39 (2051 MB/s) 38 (2105 MB/s) -1 -2.56% slice::sort_unstable_small_big_random 579 (2210 MB/s) 575 (2226 MB/s) -4 -0.69% slice::sort_unstable_small_descending 80 (1000 MB/s) 70 (1142 MB/s) -10 -12.50% slice::sort_unstable_small_random 396 (202 MB/s) 386 -10 -2.53% --- src/libcore/slice/sort.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index d13d537d9930..307e4974d976 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -152,8 +152,8 @@ fn partial_insertion_sort(v: &mut [T], is_less: &mut F) -> bool fn insertion_sort(v: &mut [T], is_less: &mut F) where F: FnMut(&T, &T) -> bool { - for i in 2..v.len()+1 { - shift_tail(&mut v[..i], is_less); + for i in 1..v.len() { + shift_tail(&mut v[..i+1], is_less); } } From e7949d0013bb8b45c884b173ca22c20e6899d612 Mon Sep 17 00:00:00 2001 From: Adam Ransom Date: Tue, 21 Mar 2017 21:38:32 +0900 Subject: [PATCH 036/905] Warn when using a `'static` lifetime bound Previously a `'static` lifetime bound would result in an `undeclared lifetime` error when compiling, even though it could be considered valid. However, it is unnecessary to use it as a lifetime bound so we present the user with a warning instead and suggest using the `'static` lifetime directly, in place of the lifetime parameter. --- src/librustc/middle/resolve_lifetime.rs | 14 ++++++++++++-- src/test/compile-fail/static-lifetime-bound.rs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/static-lifetime-bound.rs diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 10ee760a6a61..5094e28475b2 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -29,7 +29,7 @@ use syntax::ast; use syntax::attr; use syntax::ptr::P; use syntax::symbol::keywords; -use syntax_pos::Span; +use syntax_pos::{mk_sp, Span}; use errors::DiagnosticBuilder; use util::nodemap::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap}; use rustc_back::slice; @@ -1464,7 +1464,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime); for bound in &lifetime_i.bounds { - self.resolve_lifetime_ref(bound); + if !bound.is_static() { + self.resolve_lifetime_ref(bound); + } else { + self.insert_lifetime(bound, Region::Static); + let full_span = mk_sp(lifetime_i.lifetime.span.lo, bound.span.hi); + self.sess.struct_span_warn(full_span, + &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name)) + .help(&format!("you can use the `'static` lifetime directly, in place \ + of `{}`", lifetime_i.lifetime.name)) + .emit(); + } } } } diff --git a/src/test/compile-fail/static-lifetime-bound.rs b/src/test/compile-fail/static-lifetime-bound.rs new file mode 100644 index 000000000000..38534ab0a368 --- /dev/null +++ b/src/test/compile-fail/static-lifetime-bound.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 f<'a: 'static>(_: &'a i32) {} //~WARN unnecessary lifetime parameter `'a` + +fn main() { + let x = 0; + f(&x); //~ERROR does not live long enough +} From bff332e0a22ce71f329202fc635693079e791bb5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Mar 2017 19:00:35 -0700 Subject: [PATCH 037/905] travis: Update sccache again Looks like the last version was built with mio 0.6.5 which now has known bugs against it. This build includes mio 0.6.6 --- .travis.yml | 2 +- appveyor.yml | 4 ++-- src/ci/docker/armhf-gnu/Dockerfile | 2 +- src/ci/docker/cross/Dockerfile | 2 +- src/ci/docker/dist-android/Dockerfile | 2 +- src/ci/docker/dist-arm-linux/Dockerfile | 2 +- src/ci/docker/dist-armv7-aarch64-linux/Dockerfile | 2 +- src/ci/docker/dist-freebsd/Dockerfile | 2 +- src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 2 +- src/ci/docker/dist-mips-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- src/ci/docker/dist-s390x-linux-netbsd/Dockerfile | 2 +- src/ci/docker/dist-x86-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-musl/Dockerfile | 2 +- src/ci/docker/emscripten/Dockerfile | 2 +- src/ci/docker/i686-gnu-nopt/Dockerfile | 2 +- src/ci/docker/i686-gnu/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-debug/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-distcheck/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-incremental/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-nopt/Dockerfile | 2 +- src/ci/docker/x86_64-gnu/Dockerfile | 2 +- 28 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1faf860a3004..148b59e8c64e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp diff --git a/appveyor.yml b/appveyor.yml index c33e07fb17e5..0f4d053b6cfe 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -115,8 +115,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-pc-windows-msvc - - mv 2017-03-22-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-pc-windows-msvc + - mv 2017-03-24-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index a5126cb3c3f2..933562c79e58 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 9e7abb8b36e3..8dc02ab522c2 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 2785d2135f86..44d6863bf0bb 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 6cdb5cfca74b..7facc52390ff 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile index ed9b4a592918..369e5a7dffe2 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-freebsd/Dockerfile index 332a1fa73a4d..633f58ea474b 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-freebsd/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index dcb9aa905f14..ed37a9e842e2 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index 205139698858..d88ec7aab346 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 3123e69e7e1d..938c53ae4883 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 52db932dcdc3..45de8100b4f2 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index fca931596853..c1e5e863ae06 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 17a4734aba7d..7413c327323e 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -67,7 +67,7 @@ COPY build-powerpc64le-toolchain.sh /tmp/ RUN ./build-powerpc64le-toolchain.sh RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index c2877b081d5d..4180006690fc 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -66,7 +66,7 @@ RUN ./build-netbsd-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 100b6dcf9937..18c7a4d2b3e7 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -76,7 +76,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 7ebd34ee904b..085aa3516599 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index 630b122c9359..77cf54a19a7f 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index b9f47731eee7..c84cf56e4e85 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index e4a9c5b258fe..f4bb9083b858 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index 104361830e1c..68184c65cf17 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 1575efdb4cb7..6320a806fc30 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 94847712094d..180f53ec33f3 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 542b4f90b119..4500fc0f642d 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index 4d9b218c7654..ad1227fa581f 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index 04358ff97484..f12402018057 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index dddeb82e6bfb..fa9707d1a735 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index 393bcf023ea5..e5d89034dbe4 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ From bde6336976f9a660fb9b14b89316ade85837fe44 Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Fri, 24 Mar 2017 23:29:23 -0400 Subject: [PATCH 038/905] Update `Child` docs to not have a note section In #29370 it's noted that for "the Note shouldn't be one, and should come before the examples." This commit changes the positioning of the section and removes wording that said take note in order for it to flow better with the surrounding text and it's new position. --- src/libstd/process.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 7a85e5886623..293c8501400a 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -73,6 +73,15 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// spawning process and can itself be constructed using a builder-style /// interface. /// +/// There is no implementation of [`Drop`] for child processes, +/// so if you do not ensure the `Child` has exited then it will continue to +/// run, even after the `Child` handle to the child process has gone out of +/// scope. +/// +/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make +/// the parent process wait until the child has actually exited before +/// continuing. +/// /// # Examples /// /// ```should_panic @@ -89,17 +98,6 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// assert!(ecode.success()); /// ``` /// -/// # Note -/// -/// Take note that there is no implementation of [`Drop`] for child processes, -/// so if you do not ensure the `Child` has exited then it will continue to -/// run, even after the `Child` handle to the child process has gone out of -/// scope. -/// -/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make -/// the parent process wait until the child has actually exited before -/// continuing. -/// /// [`Command`]: struct.Command.html /// [`Drop`]: ../../core/ops/trait.Drop.html /// [`wait`]: #method.wait From 29a052d2d807dcb9f1d45878a3083af7a993263d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 25 Mar 2017 04:04:13 +0000 Subject: [PATCH 039/905] Fix ICE with nested macros in certain situations. --- src/libsyntax/ext/placeholders.rs | 2 +- src/test/run-pass/issue-40770.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-40770.rs diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f0e328a551d5..2d0994a7b78f 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -106,8 +106,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_item(&mut self, item: P) -> SmallVector> { match item.node { - ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {} ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), + ast::ItemKind::MacroDef(_) => return SmallVector::one(item), _ => {} } diff --git a/src/test/run-pass/issue-40770.rs b/src/test/run-pass/issue-40770.rs new file mode 100644 index 000000000000..599d0b273e3f --- /dev/null +++ b/src/test/run-pass/issue-40770.rs @@ -0,0 +1,19 @@ +// 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. + +macro_rules! m { + ($e:expr) => { + macro_rules! n { () => { $e } } + } +} + +fn main() { + m!(foo!()); +} From 57009caabd2a45a6efa4d36149feec39ab0a0658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Mar 2017 23:00:21 -0700 Subject: [PATCH 040/905] Identify missing item category in `impl`s ```rust struct S; impl S { pub hello_method(&self) { println!("Hello"); } } fn main() { S.hello_method(); } ``` ```rust error: can't qualify macro invocation with `pub` --> file.rs:3:4 | 3 | pub hello_method(&self) { | ^^^- - expected `!` here for a macro invocation | | | did you mean to write `fn` here for a method declaration? | = help: try adjusting the macro to put `pub` inside the invocation ``` --- src/libsyntax/parse/parser.rs | 62 ++++++++++++++++----- src/test/ui/did_you_mean/issue-40006.rs | 21 +++++++ src/test/ui/did_you_mean/issue-40006.stderr | 12 ++++ 3 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-40006.rs create mode 100644 src/test/ui/did_you_mean/issue-40006.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c042..a19339f8cc1c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4660,25 +4660,30 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) { - match *visa { - Visibility::Inherited => (), + fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { + err.emit(); + } + } + + fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + match *vis { + Visibility::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), _ => false, }; if is_macro_rules { - self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ - invocation with `pub`") - .help("did you mean #[macro_export]?") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.help("did you mean #[macro_export]?"); + Err(err) } else { - self.diagnostic().struct_span_err(span, "can't qualify macro \ - invocation with `pub`") - .help("try adjusting the macro to put `pub` \ - inside the invocation") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + Err(err) } } } @@ -4689,14 +4694,41 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { - // method macro. + // Method macro. let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis, prev_span); + // Before complaining about trying to set a macro as `pub`, + // check if `!` comes after the path. + let err = self.complain_if_pub_macro_diag(&vis, prev_span); let lo = self.span.lo; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + let bang_err = self.expect(&token::Not); + if let Err(mut err) = err { + if let Err(mut bang_err) = bang_err { + // Given this code `pub path(`, it seems like this is not setting the + // visibility of a macro invocation, but rather a mistyped method declaration. + // Keep the macro diagnostic, but also provide a hint that `fn` might be + // missing. Don't complain about the missing `!` as a separate diagnostic, add + // label in the appropriate place as part of one unified diagnostic. + // + // x | pub path(&self) { + // | ^^^- - expected `!` here for a macro invocation + // | | + // | did you mean to write `fn` here for a method declaration? + + bang_err.cancel(); + err.span_label(self.span, &"expected `!` here for a macro invocation"); + // pub path( + // ^^ `sp` below will point to this + let sp = mk_sp(prev_span.hi, self.prev_span.lo); + err.span_label(sp, + &"did you mean to write `fn` here for a method declaration?"); + } + return Err(err); + } else if let Err(bang_err) = bang_err { + return Err(bang_err); + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs new file mode 100644 index 000000000000..cf75929bae20 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -0,0 +1,21 @@ +// 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. + +struct S; + +impl S { + pub hello_method(&self) { + println!("Hello"); + } +} + +fn main() { + S.hello_method(); +} diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr new file mode 100644 index 000000000000..93a0c58f91a5 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -0,0 +1,12 @@ +error: can't qualify macro invocation with `pub` + --> $DIR/issue-40006.rs:14:5 + | +14 | pub hello_method(&self) { + | ^^^- - expected `!` here for a macro invocation + | | + | did you mean to write `fn` here for a method declaration? + | + = help: try adjusting the macro to put `pub` inside the invocation + +error: aborting due to previous error + From 03eca713816ee00ecacde27cc655dc199c6bff40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Mar 2017 19:14:58 -0700 Subject: [PATCH 041/905] Point at last valid token on failed `expect_one_of` ```rust error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | 25 | foo() | - expected one of `.`, `;`, `?`, `}`, or an operator after this ... 29 | } else { | ^ unexpected token ``` --- src/libsyntax/parse/parser.rs | 28 +++++++++---------- src/test/compile-fail/issue-10636-2.rs | 2 ++ .../compile-fail/macro-incomplete-parse.rs | 2 ++ src/test/parse-fail/bounds-obj-parens.rs | 4 ++- src/test/parse-fail/match-refactor-to-expr.rs | 4 ++- .../parse-fail/trailing-plus-in-bounds.rs | 4 ++- .../ui/resolve/token-error-correct-3.stderr | 9 ++++-- .../ui/resolve/token-error-correct.stderr | 4 ++- 8 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c042..6379015055b6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -548,20 +548,20 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - Err(self.fatal( - &(if expected.len() > 1 { - (format!("expected one of {}, found `{}`", - expect, - actual)) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", - actual)) - } else { - (format!("expected {}, found `{}`", - expect, - actual)) - })[..] - )) + let (msg_exp, label_exp) = if expected.len() > 1 { + (format!("expected one of {}, found `{}`", expect, actual), + format!("expected one of {} after this", expect)) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + "unexpected token after this".to_string()) + } else { + (format!("expected {}, found `{}`", expect, actual), + format!("expected {} after this", expect)) + }; + let mut err = self.fatal(&msg_exp); + err.span_label(self.prev_span, &label_exp); + err.span_label(self.span, &"unexpected token"); + Err(err) } } diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/compile-fail/issue-10636-2.rs index beaf9e5059fa..93759123618f 100644 --- a/src/test/compile-fail/issue-10636-2.rs +++ b/src/test/compile-fail/issue-10636-2.rs @@ -14,5 +14,7 @@ pub fn trace_option(option: Option) { option.map(|some| 42; //~ NOTE: unclosed delimiter //~^ ERROR: expected one of + //~| NOTE: expected one of + //~| NOTE: unexpected token } //~ ERROR: incorrect close delimiter //~^ ERROR: expected expression, found `)` diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/compile-fail/macro-incomplete-parse.rs index c2ac99d1f6a2..682664df9810 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/compile-fail/macro-incomplete-parse.rs @@ -20,6 +20,8 @@ macro_rules! ignored_item { macro_rules! ignored_expr { () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator after this + //~| NOTE unexpected token 2 ) } diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/parse-fail/bounds-obj-parens.rs index ad59d4a52d74..02c119cf727f 100644 --- a/src/test/parse-fail/bounds-obj-parens.rs +++ b/src/test/parse-fail/bounds-obj-parens.rs @@ -12,4 +12,6 @@ type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 37b66601e709..7bb1c40118a4 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,9 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` + //~^ NOTE expected one of `.`, `?`, `{`, or an operator after this + ; //~ NOTE unexpected token + //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` println!("{}", foo) } diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs index 4a2e6d5bdcd9..2bb2c97790c1 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/parse-fail/trailing-plus-in-bounds.rs @@ -16,4 +16,6 @@ fn main() { let x: Box = box 3 as Box; // Trailing `+` is OK } -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 56e368895750..2e0edf0c4b8d 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -14,13 +14,18 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:23:35 | 23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter - | ^ + | -^ unexpected token + | | + | expected one of `,`, `.`, `?`, or an operator after this error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | +25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types + | - expected one of `.`, `;`, `?`, `}`, or an operator after this +... 29 | } else { //~ ERROR: incorrect close delimiter: `}` - | ^ + | ^ unexpected token error[E0425]: cannot find function `is_directory` in this scope --> $DIR/token-error-correct-3.rs:21:13 diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 248a923efaf3..36f298a456a6 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -32,7 +32,9 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | ^ + | -^ unexpected token + | | + | expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator after this error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 From 8b92255b64989ea0e7da00a2fa94fe4358a9d7a6 Mon Sep 17 00:00:00 2001 From: Phil Ellison Date: Sat, 25 Mar 2017 09:03:22 +0000 Subject: [PATCH 042/905] Don't stutter in operator descriptions #29365 --- src/libcore/ops.rs | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 686cc21eba1a..d203b68c0dfd 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -196,7 +196,7 @@ pub trait Drop { fn drop(&mut self); } -/// The `Add` trait is used to specify the functionality of `+`. +/// The addition operator `+`. /// /// # Examples /// @@ -269,7 +269,7 @@ macro_rules! add_impl { add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Sub` trait is used to specify the functionality of `-`. +/// The subtraction operator `-`. /// /// # Examples /// @@ -342,7 +342,7 @@ macro_rules! sub_impl { sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Mul` trait is used to specify the functionality of `*`. +/// The multiplication operator `*`. /// /// # Examples /// @@ -464,7 +464,7 @@ macro_rules! mul_impl { mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Div` trait is used to specify the functionality of `/`. +/// The division operator `/`. /// /// # Examples /// @@ -609,7 +609,7 @@ macro_rules! div_impl_float { div_impl_float! { f32 f64 } -/// The `Rem` trait is used to specify the functionality of `%`. +/// The remainder operator `%`. /// /// # Examples /// @@ -689,7 +689,7 @@ macro_rules! rem_impl_float { rem_impl_float! { f32 f64 } -/// The `Neg` trait is used to specify the functionality of unary `-`. +/// The unary negation operator `-`. /// /// # Examples /// @@ -768,7 +768,7 @@ macro_rules! neg_impl_unsigned { // neg_impl_unsigned! { usize u8 u16 u32 u64 } neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Not` trait is used to specify the functionality of unary `!`. +/// The unary logical negation operator `!`. /// /// # Examples /// @@ -826,7 +826,7 @@ macro_rules! not_impl { not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitAnd` trait is used to specify the functionality of `&`. +/// The bitwise AND operator `&`. /// /// # Examples /// @@ -909,7 +909,7 @@ macro_rules! bitand_impl { bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitOr` trait is used to specify the functionality of `|`. +/// The bitwise OR operator `|`. /// /// # Examples /// @@ -992,7 +992,7 @@ macro_rules! bitor_impl { bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitXor` trait is used to specify the functionality of `^`. +/// The bitwise XOR operator `^`. /// /// # Examples /// @@ -1078,7 +1078,7 @@ macro_rules! bitxor_impl { bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `Shl` trait is used to specify the functionality of `<<`. +/// The left shift operator `<<`. /// /// # Examples /// @@ -1181,7 +1181,7 @@ macro_rules! shl_impl_all { shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } -/// The `Shr` trait is used to specify the functionality of `>>`. +/// The right shift operator `>>`. /// /// # Examples /// @@ -1284,7 +1284,7 @@ macro_rules! shr_impl_all { shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } -/// The `AddAssign` trait is used to specify the functionality of `+=`. +/// The addition assignment operator `+=`. /// /// # Examples /// @@ -1340,7 +1340,7 @@ macro_rules! add_assign_impl { add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `SubAssign` trait is used to specify the functionality of `-=`. +/// The subtraction assignment operator `-=`. /// /// # Examples /// @@ -1396,7 +1396,7 @@ macro_rules! sub_assign_impl { sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `MulAssign` trait is used to specify the functionality of `*=`. +/// The multiplication assignment operator `*=`. /// /// # Examples /// @@ -1441,7 +1441,7 @@ macro_rules! mul_assign_impl { mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `DivAssign` trait is used to specify the functionality of `/=`. +/// The division assignment operator `/=`. /// /// # Examples /// @@ -1485,7 +1485,7 @@ macro_rules! div_assign_impl { div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `RemAssign` trait is used to specify the functionality of `%=`. +/// The remainder assignment operator `%=`. /// /// # Examples /// @@ -1529,7 +1529,7 @@ macro_rules! rem_assign_impl { rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `BitAndAssign` trait is used to specify the functionality of `&=`. +/// The bitwise AND assignment operator `&=`. /// /// # Examples /// @@ -1615,7 +1615,7 @@ macro_rules! bitand_assign_impl { bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitOrAssign` trait is used to specify the functionality of `|=`. +/// The bitwise OR assignment operator `|=`. /// /// # Examples /// @@ -1659,7 +1659,7 @@ macro_rules! bitor_assign_impl { bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitXorAssign` trait is used to specify the functionality of `^=`. +/// The bitwise XOR assignment operator `^=`. /// /// # Examples /// @@ -1703,7 +1703,7 @@ macro_rules! bitxor_assign_impl { bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `ShlAssign` trait is used to specify the functionality of `<<=`. +/// The left shift assignment operator `<<=`. /// /// # Examples /// @@ -1768,7 +1768,7 @@ macro_rules! shl_assign_impl_all { shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } -/// The `ShrAssign` trait is used to specify the functionality of `>>=`. +/// The right shift assignment operator `>>=`. /// /// # Examples /// From 779d2f3044ee858fad70a95b8ac156105682883d Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 06:25:08 -0400 Subject: [PATCH 043/905] Link ParseBoolError to from_str method of bool --- src/libcore/str/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index dfb6936da6bd..2ef0eb0cdcfb 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -101,7 +101,9 @@ impl FromStr for bool { } } -/// An error returned when parsing a `bool` from a string fails. +/// An error returned when parsing a `bool` using [`from_str`] fails +/// +/// [`from_str`]: ../../std/primitive.bool.html#method.from_str #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseBoolError { _priv: () } From 5d9d652e0f746d7db9542f95115d5820fefeedaa Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 25 Mar 2017 16:21:08 +0530 Subject: [PATCH 044/905] Fix typo in dec2flt/algorithm.rs --- src/libcore/num/dec2flt/algorithm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 604bc7c10dea..60dab943a3ac 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -141,7 +141,7 @@ pub fn fast_path(integral: &[u8], fractional: &[u8], e: i64) -> Opt /// /// It rounds ``f`` to a float with 64 bit significand and multiplies it by the best approximation /// of `10^e` (in the same floating point format). This is often enough to get the correct result. -/// However, when the result is close to halfway between two adjecent (ordinary) floats, the +/// However, when the result is close to halfway between two adjacent (ordinary) floats, the /// compound rounding error from multiplying two approximation means the result may be off by a /// few bits. When this happens, the iterative Algorithm R fixes things up. /// @@ -392,7 +392,7 @@ fn underflow(x: Big, v: Big, rem: Big) -> T { // // Therefore, when the rounded-off bits are != 0.5 ULP, they decide the rounding // on their own. When they are equal and the remainder is non-zero, the value still - // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainer + // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainder // is zero, we have a half-to-even situation. let bits = x.bit_length(); let lsb = bits - T::sig_bits() as usize; From 6344d087279e0cab9936c31e11e427694529c8f1 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Tue, 7 Mar 2017 10:17:55 -0300 Subject: [PATCH 045/905] Update libc to 0.2.21 --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 64d954c6a76e..05a2d197356e 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 64d954c6a76e896fbf7ed5c17e77c40e388abe84 +Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f From a7add43389d435bda8769cb73ac6636237633836 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 16 Mar 2017 16:07:56 -0300 Subject: [PATCH 046/905] Fix c_char (u8 -> i8) definition for i686-linux-android --- src/libstd/os/raw.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index 68d4ca900195..c34491941d69 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -14,22 +14,24 @@ use fmt; -#[cfg(any(target_os = "android", - target_os = "emscripten", +#[cfg(any(target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[cfg(not(any(target_os = "android", - target_os = "emscripten", +#[cfg(not(any(target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; From b45c631382a0bb831dc038973288e3f6d91cb07a Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Fri, 17 Mar 2017 08:06:23 -0300 Subject: [PATCH 047/905] Fix libc::bind call on aarch64-linux-android --- src/libstd/sys/unix/ext/net.rs | 4 ++-- src/libstd/sys_common/net.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 55118829eee9..d688f2fa5045 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -641,7 +641,7 @@ impl UnixListener { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; cvt(libc::listen(*inner.as_inner(), 128))?; Ok(UnixListener(inner)) @@ -920,7 +920,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; Ok(socket) } diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 3cdeb5119457..9239c18e5971 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -339,7 +339,7 @@ impl TcpListener { // Bind our new socket let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?; + cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; // Start listening cvt(unsafe { c::listen(*sock.as_inner(), 128) })?; @@ -430,7 +430,7 @@ impl UdpSocket { let sock = Socket::new(addr, c::SOCK_DGRAM)?; let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?; + cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; Ok(UdpSocket { inner: sock }) } From ca85c400dae365c9ade87bbd100ddfe3ecd3822a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 25 Mar 2017 15:01:25 +0300 Subject: [PATCH 048/905] travis: try to fix the build on emscripten The emsdk-portable .tar.gz now extracts to emsdk-portable instead of emsdk_portable. Handle that. --- src/ci/docker/emscripten/build-emscripten.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh index 88bf583007ce..b9aa197f85e0 100755 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ b/src/ci/docker/emscripten/build-emscripten.sh @@ -29,7 +29,20 @@ exit 1 } curl https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | \ - tar xzf - + tar xzf - + +# Some versions of the EMSDK archive have their contents in .emsdk-portable +# and others in emsdk_portable. Make sure the EMSDK ends up in a fixed path. +if [ -d emsdk-portable ]; then + mv emsdk-portable emsdk_portable +fi + +if [ ! -d emsdk_portable ]; then + echo "ERROR: Invalid emsdk archive. Dumping working directory." >&2 + ls -l + exit 1 +fi + source emsdk_portable/emsdk_env.sh hide_output emsdk update hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit From 33a6a07d586437e8d4894dc35413a21ee5cfba54 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 11:56:52 -0400 Subject: [PATCH 049/905] FromStr implementation example --- src/libcore/str/mod.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index dfb6936da6bd..bc5df6810a9d 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -35,6 +35,39 @@ pub mod pattern; /// [`from_str`]: #tymethod.from_str /// [`str`]: ../../std/primitive.str.html /// [`parse`]: ../../std/primitive.str.html#method.parse +/// +/// # Examples +/// +/// Basic implementation of `FromStr` on an example `Point` type: +/// +/// ``` +/// use std::str::FromStr; +/// use std::num::ParseIntError; +/// +/// #[derive(Debug, PartialEq)] +/// struct Point { +/// x: i32, +/// y: i32 +/// } +/// +/// impl FromStr for Point { +/// type Err = ParseIntError; +/// +/// fn from_str(s: &str) -> Result { +/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) +/// .split(",") +/// .collect(); +/// +/// let x_fromstr = try!(coords[0].parse::()); +/// let y_fromstr = try!(coords[1].parse::()); +/// +/// Ok(Point { x: x_fromstr, y: y_fromstr }) +/// } +/// } +/// +/// let p = Point::from_str("(1,2)"); +/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait FromStr: Sized { /// The associated error which can be returned from parsing. From 935d84a272a8b637e13c54b18a1571994e962e5c Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sat, 25 Mar 2017 17:22:07 +0100 Subject: [PATCH 050/905] fix permissions of emsdk_portable --- src/ci/docker/emscripten/build-emscripten.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh index b9aa197f85e0..e39767357ad6 100755 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ b/src/ci/docker/emscripten/build-emscripten.sh @@ -43,6 +43,10 @@ if [ ! -d emsdk_portable ]; then exit 1 fi +# Some versions of the EMSDK set the permissions of the root directory to +# 0700. Ensure the directory is readable by all users. +chmod 755 emsdk_portable + source emsdk_portable/emsdk_env.sh hide_output emsdk update hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit From 64cd0bebab1a9023dc5a4bbc38f9e6820629fbb9 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 12:22:23 -0400 Subject: [PATCH 051/905] Remove trailing whitespace --- src/libcore/str/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index bc5df6810a9d..ae08a3d0a9a7 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -43,28 +43,28 @@ pub mod pattern; /// ``` /// use std::str::FromStr; /// use std::num::ParseIntError; -/// +/// /// #[derive(Debug, PartialEq)] /// struct Point { /// x: i32, /// y: i32 /// } -/// +/// /// impl FromStr for Point { /// type Err = ParseIntError; -/// +/// /// fn from_str(s: &str) -> Result { /// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) /// .split(",") /// .collect(); -/// +/// /// let x_fromstr = try!(coords[0].parse::()); /// let y_fromstr = try!(coords[1].parse::()); -/// +/// /// Ok(Point { x: x_fromstr, y: y_fromstr }) /// } /// } -/// +/// /// let p = Point::from_str("(1,2)"); /// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) /// ``` From fb5e63fc475996ee5c65fb1b8686b8db17eb1e63 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 25 Mar 2017 14:41:37 -0400 Subject: [PATCH 052/905] Change `try!` to `?` --- src/libcore/str/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index ae08a3d0a9a7..f3c3994ef315 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -58,8 +58,8 @@ pub mod pattern; /// .split(",") /// .collect(); /// -/// let x_fromstr = try!(coords[0].parse::()); -/// let y_fromstr = try!(coords[1].parse::()); +/// let x_fromstr = coords[0].parse::()?; +/// let y_fromstr = coords[1].parse::()?; /// /// Ok(Point { x: x_fromstr, y: y_fromstr }) /// } From 2e14bfe0d7ce376a42bdc4c7eb964fd91aad3c32 Mon Sep 17 00:00:00 2001 From: projektir Date: Sat, 25 Mar 2017 15:33:44 -0400 Subject: [PATCH 053/905] rustdoc to accept `#` at the start of a markdown file #40560 --- src/librustdoc/markdown.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index c67e2fdc2b02..5fadda030a4b 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -28,20 +28,22 @@ use html::markdown; use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; use test::{TestOptions, Collector}; -/// Separate any lines at the start of the file that begin with `%`. +/// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { let mut metadata = Vec::new(); let mut count = 0; + for line in s.lines() { - if line.starts_with("%") { - // remove % + if line.starts_with("# ") || line.starts_with("%") { + // trim the whitespace after the symbol metadata.push(line[1..].trim_left()); count += line.len() + 1; } else { return (metadata, &s[count..]); } } - // if we're here, then all lines were metadata % lines. + + // if we're here, then all lines were metadata `# ` or `%` lines. (metadata, "") } @@ -83,7 +85,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, if metadata.is_empty() { let _ = writeln!( &mut io::stderr(), - "rustdoc: invalid markdown file: expecting initial line with `% ...TITLE...`" + "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`" ); return 5; } From 6341a8b0e5155abf4bf338d3df7f6d2971f83adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Mar 2017 23:40:24 -0700 Subject: [PATCH 054/905] Clarify suggetion for field used as method Instead of ``` error: no method named `src_addr` found for type `&wire::ipv4::Repr` in the current scope --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ | note: did you mean to write `self.src_addr`? --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ ``` present ``` error: no method named `src_addr` found for type `&wire::ipv4::Repr` in the current scope --> src/wire/ipv4.rs:409:34 | 409 | packet.set_src_addr(self.src_addr()); | ^^^^^^^^ `src_addr` is a field, not a method | = help: did you mean to write `self.src_addr` instead of `self.src_addr(...)`? ``` --- src/librustc_typeck/check/method/suggest.rs | 26 ++++++++------ src/test/compile-fail/issue-18343.rs | 6 ++-- src/test/compile-fail/issue-2392.rs | 39 ++++++++++++++------- src/test/compile-fail/issue-32128.rs | 6 ++-- src/test/compile-fail/issue-33784.rs | 9 +++-- 5 files changed, 56 insertions(+), 30 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 6ce50d91124d..b458c1af71d0 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -197,17 +197,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = field.ty(tcx, substs); if self.is_fn_ty(&field_ty, span) { - err.span_note(span, - &format!("use `({0}.{1})(...)` if you \ - meant to call the function \ - stored in the `{1}` field", - expr_string, - item_name)); + err.help(&format!("use `({0}.{1})(...)` if you \ + meant to call the function \ + stored in the `{1}` field", + expr_string, + item_name)); + err.span_label(span, + &format!("`{}` is a field storing a \ + function, not a method", + item_name)); } else { - err.span_note(span, - &format!("did you mean to write `{0}.{1}`?", - expr_string, - item_name)); + err.help(&format!("did you mean to write `{0}.{1}` \ + instead of `{0}.{1}(...)`?", + expr_string, + item_name)); + err.span_label(span, + &format!("`{}` is a field, not a method", + item_name)); } break; } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/compile-fail/issue-18343.rs index 4601db9dba0f..a095bb481261 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/compile-fail/issue-18343.rs @@ -14,6 +14,8 @@ struct Obj where F: FnMut() -> u32 { fn main() { let o = Obj { closure: || 42 }; - o.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + o.closure(); + //~^ ERROR no method named `closure` found + //~| HELP use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE `closure` is a field storing a function, not a method } diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/compile-fail/issue-2392.rs index 805725dd749f..12389f885364 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/compile-fail/issue-2392.rs @@ -48,45 +48,58 @@ fn main() { let o_closure = Obj { closure: || 42, not_closure: 42 }; o_closure.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_closure.closure)(...)` if you meant to call the function stored + //~^ HELP use `(o_closure.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method - o_closure.not_closure(); //~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `o_closure.not_closure`? + o_closure.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE `not_closure` is a field, not a method + //~| HELP did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? let o_func = Obj { closure: func, not_closure: 5 }; o_func.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(o_func.closure)(...)` if you meant to call the function stored + //~^ HELP use `(o_func.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE `boxed_closure` is a field storing a function, not a method let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found - //~^ NOTE use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~^ HELP use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored + //~| NOTE `boxed_closure` is a field storing a function, not a method // test expression writing in the notes let w = Wrapper { wrap: o_func }; w.wrap.closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(w.wrap.closure)(...)` if you meant to call the function stored + //~^ HELP use `(w.wrap.closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method - w.wrap.not_closure();//~ ERROR no method named `not_closure` found - //~^ NOTE did you mean to write `w.wrap.not_closure`? + w.wrap.not_closure(); + //~^ ERROR no method named `not_closure` found + //~| NOTE `not_closure` is a field, not a method + //~| HELP did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? check_expression().closure();//~ ERROR no method named `closure` found - //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored + //~^ HELP use `(check_expression().closure)(...)` if you meant to call the function stored + //~| NOTE `closure` is a field storing a function, not a method } impl FuncContainerOuter { fn run(&self) { unsafe { (*self.container).f1(1); //~ ERROR no method named `f1` found - //~^ NOTE use `((*self.container).f1)(...)` + //~^ HELP use `((*self.container).f1)(...)` + //~| NOTE `f1` is a field storing a function, not a method (*self.container).f2(1); //~ ERROR no method named `f2` found - //~^ NOTE use `((*self.container).f2)(...)` + //~^ HELP use `((*self.container).f2)(...)` + //~| NOTE `f2` is a field storing a function, not a method (*self.container).f3(1); //~ ERROR no method named `f3` found - //~^ NOTE use `((*self.container).f3)(...)` + //~^ HELP use `((*self.container).f3)(...)` + //~| NOTE `f3` is a field storing a function, not a method } } } diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/compile-fail/issue-32128.rs index fe7e66a2116e..74fbb33296e4 100644 --- a/src/test/compile-fail/issue-32128.rs +++ b/src/test/compile-fail/issue-32128.rs @@ -19,7 +19,9 @@ fn main() { }) }; - demo.example(1); //~ ERROR no method named `example` - //~^ NOTE use `(demo.example)(...)` + demo.example(1); + //~^ ERROR no method named `example` + //~| HELP use `(demo.example)(...)` + //~| NOTE `example` is a field storing a function, not a method // (demo.example)(1); } diff --git a/src/test/compile-fail/issue-33784.rs b/src/test/compile-fail/issue-33784.rs index 4229be29473d..03c84fc57bef 100644 --- a/src/test/compile-fail/issue-33784.rs +++ b/src/test/compile-fail/issue-33784.rs @@ -35,12 +35,15 @@ fn main() { let o = Obj { fn_ptr: empty, closure: || 42 }; let p = &o; p.closure(); //~ ERROR no method named `closure` found - //~^ NOTE use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~^ HELP use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + //~| NOTE `closure` is a field storing a function, not a method let q = &p; q.fn_ptr(); //~ ERROR no method named `fn_ptr` found - //~^ NOTE use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~^ HELP use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + //~| NOTE `fn_ptr` is a field storing a function, not a method let r = D(C { c_fn_ptr: empty }); let s = &r; s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found - //~^ NOTE use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~^ HELP use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` + //~| NOTE `c_fn_ptr` is a field storing a function, not a method } From 24be89980e2e89404075fe463edae0f5db369251 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Sat, 25 Mar 2017 17:15:26 -0300 Subject: [PATCH 055/905] Avoid using libc::sigemptyset on Android --- src/libstd/sys/unix/process/process_common.rs | 16 +++++++++++++++- src/libstd/sys/unix/process/process_unix.rs | 11 ++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 5f1a6c2f7465..e9f41009064c 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -417,12 +417,26 @@ mod tests { } } + // Android with api less than 21 define sig* functions inline, so it is not + // available for dynamic link. Implementing sigemptyset and sigaddset allow us + // to support older Android version (independent of libc version). + // The following implementations are based on https://git.io/vSkNf + #[cfg(not(target_os = "android"))] extern { + #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] + fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; } + #[cfg(target_os = "android")] + unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { + libc::memset(set as *mut _, 0, mem::size_of::()); + return 0; + } + #[cfg(target_os = "android")] unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { use slice; @@ -450,7 +464,7 @@ mod tests { let mut set: libc::sigset_t = mem::uninitialized(); let mut old_set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + t!(cvt(sigemptyset(&mut set))); t!(cvt(sigaddset(&mut set, libc::SIGINT))); t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index a213273aac8f..edd322ca6fa0 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -193,7 +193,16 @@ impl Command { // need to clean things up now to avoid confusing the program // we're about to run. let mut set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + if cfg!(target_os = "android") { + // Implementing sigemptyset allow us to support older Android + // versions. See the comment about Android and sig* functions in + // process_common.rs + libc::memset(&mut set as *mut _ as *mut _, + 0, + mem::size_of::()); + } else { + t!(cvt(libc::sigemptyset(&mut set))); + } t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, ptr::null_mut()))); let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); From 7ef1b39b2525dc5475f86b6dc27aa60fe5b3fdca Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Sat, 25 Mar 2017 16:16:50 -0400 Subject: [PATCH 056/905] Remove extra wait from Child docs --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 293c8501400a..edcf206501a0 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -78,7 +78,7 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// run, even after the `Child` handle to the child process has gone out of /// scope. /// -/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make +/// Calling [`wait`] (or other functions that wrap around it) will make /// the parent process wait until the child has actually exited before /// continuing. /// From 1d59c67942ea682d0de4bb847d6da38d6417e07d Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Sat, 25 Mar 2017 17:19:36 -0400 Subject: [PATCH 057/905] Update ChildStderr docs to be clearer Before the docs only had a line about where it was found and that it was a handle to stderr. This commit changes it so that the summary second line is removed and that it's a bit clearer about what can be done with it. Part of \#29370 --- src/libstd/process.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 7a85e5886623..265228281f85 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -233,8 +233,9 @@ impl fmt::Debug for ChildStdout { } } -/// A handle to a child process's stderr. This struct is used in the [`stderr`] -/// field on [`Child`]. +/// A handle to a child process's stderr. It can be used to +/// read any errors that the child process has output while +/// running. /// /// [`Child`]: struct.Child.html /// [`stderr`]: struct.Child.html#structfield.stderr From 78ae8feebbf9a2c70d42780d0c646cbbc1f2cdbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 25 Mar 2017 15:36:59 -0700 Subject: [PATCH 058/905] Improve wording and spans for unexpected token * Point at where the token was expected instead of the last token successfuly parsed. * Only show `unexpected token` if the next char and the unexpected token don't have the same span. * Change some cfail and pfail tests to ui test. * Don't show all possible tokens in span label if they are more than 6. --- src/libsyntax/parse/parser.rs | 25 +++++++++++---- src/libsyntax_pos/lib.rs | 6 ++++ src/test/parse-fail/match-refactor-to-expr.rs | 2 +- .../ui/resolve/token-error-correct-3.stderr | 6 ++-- .../ui/resolve/token-error-correct.stderr | 4 +-- .../token}/bounds-obj-parens.rs | 0 src/test/ui/token/bounds-obj-parens.stderr | 7 +++++ .../token}/issue-10636-2.rs | 0 src/test/ui/token/issue-10636-2.stderr | 27 ++++++++++++++++ .../token}/macro-incomplete-parse.rs | 2 +- .../ui/token/macro-incomplete-parse.stderr | 31 +++++++++++++++++++ .../token}/trailing-plus-in-bounds.rs | 0 .../ui/token/trailing-plus-in-bounds.stderr | 7 +++++ 13 files changed, 102 insertions(+), 15 deletions(-) rename src/test/{parse-fail => ui/token}/bounds-obj-parens.rs (100%) create mode 100644 src/test/ui/token/bounds-obj-parens.stderr rename src/test/{compile-fail => ui/token}/issue-10636-2.rs (100%) create mode 100644 src/test/ui/token/issue-10636-2.stderr rename src/test/{compile-fail => ui/token}/macro-incomplete-parse.rs (98%) create mode 100644 src/test/ui/token/macro-incomplete-parse.stderr rename src/test/{parse-fail => ui/token}/trailing-plus-in-bounds.rs (100%) create mode 100644 src/test/ui/token/trailing-plus-in-bounds.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6379015055b6..4076368c180b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -548,19 +548,32 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - let (msg_exp, label_exp) = if expected.len() > 1 { + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) + } else { + expect.clone() + }; (format!("expected one of {}, found `{}`", expect, actual), - format!("expected one of {} after this", expect)) + (self.prev_span.next_point(), format!("expected one of {} here", short_expect))) } else if expected.is_empty() { (format!("unexpected token: `{}`", actual), - "unexpected token after this".to_string()) + (self.prev_span, "unexpected token after this".to_string())) } else { (format!("expected {}, found `{}`", expect, actual), - format!("expected {} after this", expect)) + (self.prev_span.next_point(), format!("expected {} here", expect))) }; let mut err = self.fatal(&msg_exp); - err.span_label(self.prev_span, &label_exp); - err.span_label(self.span, &"unexpected token"); + let sp = if self.token == token::Token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + err.span_label(sp, &label_exp); + if label_sp != self.span { + err.span_label(self.span, &"unexpected token"); + } Err(err) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 3808923e7728..07494ff904e9 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -79,6 +79,12 @@ impl Span { Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} } + /// Returns a new span representing the next character after the end-point of this span + pub fn next_point(self) -> Span { + let lo = BytePos(cmp::max(self.hi.0, self.lo.0 + 1)); + Span { lo: lo, hi: lo, expn_id: self.expn_id} + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.source_equal(&DUMMY_SP) { other } else { self } diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 7bb1c40118a4..e2fee1d18959 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,7 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - //~^ NOTE expected one of `.`, `?`, `{`, or an operator after this + //~^ NOTE expected one of `.`, `?`, `{`, or an operator here ; //~ NOTE unexpected token //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 2e0edf0c4b8d..bf7db67e7285 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -14,15 +14,13 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:23:35 | 23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter - | -^ unexpected token - | | - | expected one of `,`, `.`, `?`, or an operator after this + | ^ expected one of `,`, `.`, `?`, or an operator here error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | 25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - | - expected one of `.`, `;`, `?`, `}`, or an operator after this + | - expected one of `.`, `;`, `?`, `}`, or an operator here ... 29 | } else { //~ ERROR: incorrect close delimiter: `}` | ^ unexpected token diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 36f298a456a6..226fa6469bc7 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -32,9 +32,7 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | -^ unexpected token - | | - | expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator after this + | ^ expected one of 18 possible tokens here error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/ui/token/bounds-obj-parens.rs similarity index 100% rename from src/test/parse-fail/bounds-obj-parens.rs rename to src/test/ui/token/bounds-obj-parens.rs diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr new file mode 100644 index 000000000000..ebee363f278e --- /dev/null +++ b/src/test/ui/token/bounds-obj-parens.stderr @@ -0,0 +1,7 @@ +error: expected one of `!` or `::`, found `` + --> $DIR/bounds-obj-parens.rs:15:1 + | +15 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/ui/token/issue-10636-2.rs similarity index 100% rename from src/test/compile-fail/issue-10636-2.rs rename to src/test/ui/token/issue-10636-2.rs diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr new file mode 100644 index 000000000000..183ad30c4ef4 --- /dev/null +++ b/src/test/ui/token/issue-10636-2.stderr @@ -0,0 +1,27 @@ +error: incorrect close delimiter: `}` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + | +note: unclosed delimiter + --> $DIR/issue-10636-2.rs:15:15 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ + +error: expected one of `,`, `.`, `?`, or an operator, found `;` + --> $DIR/issue-10636-2.rs:15:25 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ expected one of `,`, `.`, `?`, or an operator here + +error: expected expression, found `)` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + +error: main function not found + +error: aborting due to 4 previous errors diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/ui/token/macro-incomplete-parse.rs similarity index 98% rename from src/test/compile-fail/macro-incomplete-parse.rs rename to src/test/ui/token/macro-incomplete-parse.rs index 682664df9810..47374fc3c608 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/ui/token/macro-incomplete-parse.rs @@ -20,7 +20,7 @@ macro_rules! ignored_item { macro_rules! ignored_expr { () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator after this + //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator here //~| NOTE unexpected token 2 ) } diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr new file mode 100644 index 000000000000..bea00a6444c4 --- /dev/null +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -0,0 +1,31 @@ +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:17:9 + | +17 | , //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_item!` is likely invalid in item context + --> $DIR/macro-incomplete-parse.rs:32:1 + | +32 | ignored_item!(); //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/macro-incomplete-parse.rs:22:14 + | +22 | () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + | ^ expected one of `.`, `;`, `?`, `}`, or an operator here + +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:29:14 + | +29 | () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_pat!` is likely invalid in pattern context + --> $DIR/macro-incomplete-parse.rs:37:9 + | +37 | ignored_pat!() => (), //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/ui/token/trailing-plus-in-bounds.rs similarity index 100% rename from src/test/parse-fail/trailing-plus-in-bounds.rs rename to src/test/ui/token/trailing-plus-in-bounds.rs diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr new file mode 100644 index 000000000000..74caf8f5c2b3 --- /dev/null +++ b/src/test/ui/token/trailing-plus-in-bounds.stderr @@ -0,0 +1,7 @@ +error: expected one of `!` or `::`, found `` + --> ../../src/test/ui/token/trailing-plus-in-bounds.rs:19:1 + | +19 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error From 53b70953c3e628794debf38acfad90f21bc74a7e Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 25 Mar 2017 15:46:13 -0700 Subject: [PATCH 059/905] char::to_uppercase doc typo: s/lowercase/uppercase/ --- src/libstd_unicode/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index b980300126e4..e612be52e779 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -846,7 +846,7 @@ impl char { /// 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 + /// 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. From 188299e04a0c065f7b8f536e40d0a8826b1ae833 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 25 Mar 2017 15:58:35 -0700 Subject: [PATCH 060/905] char::to_uppercase doc typo: use the 'an' article. --- src/libstd_unicode/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index e612be52e779..92e5369758b4 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -842,7 +842,7 @@ impl char { /// Returns an iterator that yields the uppercase equivalent of a `char` /// as one or more `char`s. /// - /// If a character does not have a uppercase equivalent, the same character + /// 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 From 7e0f7a50ab649fb70773af35e78ca73b5123f52e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 26 Mar 2017 14:15:47 +0300 Subject: [PATCH 061/905] store a copy of the Issue32230 info within TypeError The data can't be looked up from the region variable directly, because the region variable might have been destroyed at the end of a snapshot. Fixes #40000. Fixes #40743. --- src/librustc/infer/error_reporting/mod.rs | 42 ++++++++++------------- src/librustc/infer/higher_ranked/mod.rs | 18 ++++++++-- src/librustc/ty/error.rs | 14 ++++---- src/librustc/ty/structural_impls.rs | 10 +++--- src/test/compile-fail/issue-40000.rs | 21 ++++++++++++ 5 files changed, 69 insertions(+), 36 deletions(-) create mode 100644 src/test/compile-fail/issue-40000.rs diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 21139c8dde2a..9fa2bc8a2a7a 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -426,30 +426,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { debug!("note_issue_32330: terr={:?}", terr); match *terr { - TypeError::RegionsInsufficientlyPolymorphic(_, &Region::ReVar(vid)) | - TypeError::RegionsOverlyPolymorphic(_, &Region::ReVar(vid)) => { - match self.region_vars.var_origin(vid) { - RegionVariableOrigin::EarlyBoundRegion(_, _, Some(Issue32330 { - fn_def_id, - region_name - })) => { - diag.note( - &format!("lifetime parameter `{0}` declared on fn `{1}` \ - appears only in the return type, \ - but here is required to be higher-ranked, \ - which means that `{0}` must appear in both \ - argument and return types", - region_name, - self.tcx.item_path_str(fn_def_id))); - diag.note( - &format!("this error is the result of a recent bug fix; \ - for more information, see issue #33685 \ - ")); - } - _ => { } - } + TypeError::RegionsInsufficientlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) | + TypeError::RegionsOverlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) => { + diag.note( + &format!("lifetime parameter `{0}` declared on fn `{1}` \ + appears only in the return type, \ + but here is required to be higher-ranked, \ + which means that `{0}` must appear in both \ + argument and return types", + region_name, + self.tcx.item_path_str(fn_def_id))); + diag.note( + &format!("this error is the result of a recent bug fix; \ + for more information, see issue #33685 \ + ")); } - _ => { } + _ => {} } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index e919f025409c..e3ffc99c0e96 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -15,6 +15,7 @@ use super::{CombinedSnapshot, InferCtxt, LateBoundRegion, HigherRankedType, + RegionVariableOrigin, SubregionOrigin, SkolemizationMap}; use super::combine::CombineFields; @@ -656,14 +657,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { skol_br, tainted_region); + let issue_32330 = if let &ty::ReVar(vid) = tainted_region { + match self.region_vars.var_origin(vid) { + RegionVariableOrigin::EarlyBoundRegion(_, _, issue_32330) => { + issue_32330.map(Box::new) + } + _ => None + } + } else { + None + }; + if overly_polymorphic { debug!("Overly polymorphic!"); return Err(TypeError::RegionsOverlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } else { debug!("Not as polymorphic!"); return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } } } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5a696446b4bb..73d9c8b00ae4 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -39,8 +39,8 @@ pub enum TypeError<'tcx> { RegionsDoesNotOutlive(&'tcx Region, &'tcx Region), RegionsNotSame(&'tcx Region, &'tcx Region), RegionsNoOverlap(&'tcx Region, &'tcx Region), - RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region), - RegionsOverlyPolymorphic(BoundRegion, &'tcx Region), + RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region, Option>), + RegionsOverlyPolymorphic(BoundRegion, &'tcx Region, Option>), Sorts(ExpectedFound>), IntMismatch(ExpectedFound), FloatMismatch(ExpectedFound), @@ -116,11 +116,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { RegionsNoOverlap(..) => { write!(f, "lifetimes do not intersect") } - RegionsInsufficientlyPolymorphic(br, _) => { + RegionsInsufficientlyPolymorphic(br, _, _) => { write!(f, "expected bound lifetime parameter {}, \ found concrete lifetime", br) } - RegionsOverlyPolymorphic(br, _) => { + RegionsOverlyPolymorphic(br, _, _) => { write!(f, "expected concrete lifetime, \ found bound lifetime parameter {}", br) } @@ -253,15 +253,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.note_and_explain_region(db, "...does not overlap ", region2, ""); } - RegionsInsufficientlyPolymorphic(_, conc_region) => { + RegionsInsufficientlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "concrete lifetime that was found is ", conc_region, ""); } - RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => { + RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => { // don't bother to print out the message below for // inference variables, it's not very illuminating. } - RegionsOverlyPolymorphic(_, conc_region) => { + RegionsOverlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "expected concrete lifetime is ", conc_region, ""); } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 49824e8a738d..9126600e3f65 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -293,11 +293,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { RegionsNoOverlap(a, b) => { return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b)) } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)) + RegionsInsufficientlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b, c)) } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) + RegionsOverlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b, c)) } IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), diff --git a/src/test/compile-fail/issue-40000.rs b/src/test/compile-fail/issue-40000.rs new file mode 100644 index 000000000000..9be114ebcb6e --- /dev/null +++ b/src/test/compile-fail/issue-40000.rs @@ -0,0 +1,21 @@ +// 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(closure_to_fn_coercion)] + +fn main() { + let bar: fn(&mut u32) = |_| {}; //~ ERROR mismatched types + //~| expected concrete lifetime, found bound lifetime parameter + + fn foo(x: Box) {} + let bar = Box::new(|x: &i32| {}) as Box; + foo(bar); //~ ERROR mismatched types + //~| expected concrete lifetime, found bound lifetime parameter +} From 6e6dec0cab0731c4c32f6592f02c02cf4fd03a8d Mon Sep 17 00:00:00 2001 From: aStoate Date: Sun, 26 Mar 2017 21:47:22 +1030 Subject: [PATCH 062/905] change string references in asciiext r? @steveklabnik --- src/libstd/ascii.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index af21d6d906eb..ba2b059f8284 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -17,7 +17,7 @@ use mem; use ops::Range; use iter::FusedIterator; -/// Extension methods for ASCII-subset only operations on string slices. +/// Extension methods for ASCII-subset only operations. /// /// Be aware that operations on seemingly non-ASCII characters can sometimes /// have unexpected results. Consider this example: @@ -54,19 +54,21 @@ pub trait AsciiExt { /// /// let ascii = 'a'; /// let utf8 = '❀'; + /// let int_ascii = 97; /// /// assert!(ascii.is_ascii()); /// assert!(!utf8.is_ascii()); + /// assert!(int_ascii.is_ascii()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; - /// Makes a copy of the string in ASCII upper case. + /// Makes a copy of the value in it's ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// - /// To uppercase the string in-place, use [`make_ascii_uppercase`]. + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. /// /// To uppercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_uppercase`]. @@ -78,9 +80,11 @@ pub trait AsciiExt { /// /// let ascii = 'a'; /// let utf8 = '❀'; + /// let int_ascii = 97; /// /// assert_eq!('A', ascii.to_ascii_uppercase()); /// assert_eq!('❀', utf8.to_ascii_uppercase()); + /// assert_eq!(65, int_ascii.to_ascii_uppercase()); /// ``` /// /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase @@ -88,12 +92,12 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_uppercase(&self) -> Self::Owned; - /// Makes a copy of the string in ASCII lower case. + /// Makes a copy of the value in it's ASCII lower case equivalent. /// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// - /// To lowercase the string in-place, use [`make_ascii_lowercase`]. + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. /// /// To lowercase ASCII characters in addition to non-ASCII characters, use /// [`str::to_lowercase`]. @@ -105,9 +109,11 @@ pub trait AsciiExt { /// /// let ascii = 'A'; /// let utf8 = '❀'; + /// let int_ascii = 65; /// /// assert_eq!('a', ascii.to_ascii_lowercase()); /// assert_eq!('❀', utf8.to_ascii_lowercase()); + /// assert_eq!(97, int_ascii.to_ascii_lowercase()); /// ``` /// /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase @@ -115,10 +121,10 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_lowercase(&self) -> Self::Owned; - /// Checks that two strings are an ASCII case-insensitive match. + /// Checks that two values are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporary strings. + /// but without allocating and copying temporaries. /// /// # Examples /// @@ -142,7 +148,7 @@ pub trait AsciiExt { /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. /// - /// To return a new uppercased string without modifying the existing one, use + /// To return a new uppercased value without modifying the existing one, use /// [`to_ascii_uppercase`]. /// /// # Examples @@ -166,7 +172,7 @@ pub trait AsciiExt { /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. /// - /// To return a new lowercased string without modifying the existing one, use + /// To return a new lowercased value without modifying the existing one, use /// [`to_ascii_lowercase`]. /// /// # Examples From 169facfc288586b7635652abace56d56da2a6f99 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 17:11:08 +0100 Subject: [PATCH 063/905] added missing links in std::net TCP docs part of #29363 --- src/libstd/net/tcp.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index a07972468e68..8a21f17dc49f 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -83,11 +83,15 @@ impl TcpStream { /// Opens a TCP connection to a remote host. /// /// `addr` is an address of the remote host. Anything which implements - /// `ToSocketAddrs` trait can be supplied for the address; see this trait + /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait /// documentation for concrete examples. - /// In case `ToSocketAddrs::to_socket_addrs()` returns more than one entry, + /// In case [`ToSocketAddrs::to_socket_addrs()`] returns more than one entry, /// then the first valid and reachable address is used. /// + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// [`ToSocketAddrs::to_socket_addrs()`]: + /// ../../std/net/trait.ToSocketAddrs.html#tymethod.to_socket_addrs + /// /// # Examples /// /// ```no_run @@ -494,11 +498,14 @@ impl TcpListener { /// /// Binding with a port number of 0 will request that the OS assigns a port /// to this listener. The port allocated can be queried via the - /// `local_addr` method. + /// [`local_addr`] method. /// - /// The address type can be any implementor of `ToSocketAddrs` trait. See + /// The address type can be any implementor of [`ToSocketAddrs`] trait. See /// its documentation for concrete examples. /// + /// [`local_addr`]: #method.local_addr + /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html + /// /// # Examples /// /// ```no_run @@ -529,10 +536,12 @@ impl TcpListener { /// Creates a new independently owned handle to the underlying socket. /// - /// The returned `TcpListener` is a reference to the same socket that this + /// The returned [`TcpListener`] is a reference to the same socket that this /// object references. Both handles can be used to accept incoming /// connections and options set on one listener will affect the other. /// + /// [`TcpListener`]: ../../std/net/struct.TcpListener.html + /// /// # Examples /// /// ```no_run @@ -549,9 +558,11 @@ impl TcpListener { /// Accept a new incoming connection from this listener. /// /// This function will block the calling thread until a new TCP connection - /// is established. When established, the corresponding `TcpStream` and the + /// is established. When established, the corresponding [`TcpStream`] and the /// remote peer's address will be returned. /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// /// # Examples /// /// ```no_run From 76d08eda7d228ed475bf190253b8fd7ebfe667db Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 14:30:03 +0200 Subject: [PATCH 064/905] Update std::net:Incoming's docs to use standard iterator boilerplate Part of #29363 --- src/libstd/net/tcp.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 8a21f17dc49f..c6cf748d981c 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -65,16 +65,14 @@ pub struct TcpStream(net_imp::TcpStream); #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpListener(net_imp::TcpListener); -/// An infinite iterator over the connections from a `TcpListener`. -/// -/// This iterator will infinitely yield [`Some`] of the accepted connections. It -/// is equivalent to calling `accept` in a loop. +/// An iterator that infinitely [`accept`]s connections on a [`TcpListener`]. /// /// This `struct` is created by the [`incoming`] method on [`TcpListener`]. +/// See its documentation for more. /// -/// [`Some`]: ../../std/option/enum.Option.html#variant.Some -/// [`incoming`]: struct.TcpListener.html#method.incoming -/// [`TcpListener`]: struct.TcpListener.html +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`incoming`]: ../../std/net/struct.TcpListener.html#method.incoming +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Incoming<'a> { listener: &'a TcpListener } @@ -583,10 +581,12 @@ impl TcpListener { /// listener. /// /// The returned iterator will never return [`None`] and will also not yield - /// the peer's [`SocketAddr`] structure. + /// the peer's [`SocketAddr`] structure. Iterating over it is equivalent to + /// calling [`accept`] in a loop. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// [`accept`]: #method.accept /// /// # Examples /// From 0df7398558cb7d8fbf5d191d7e07a601a4a30702 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 17:27:00 +0100 Subject: [PATCH 065/905] std::net docs: changed occurences of "RFC" to say "IETF RFC" part of #29363 --- src/libstd/net/ip.rs | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 24e0e6f3fa65..44dc689a30f4 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -296,9 +296,9 @@ impl Ipv4Addr { /// Returns true if this is a loopback address (127.0.0.0/8). /// - /// This property is defined by [RFC 1122]. + /// This property is defined by [IETF RFC 1122]. /// - /// [RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 /// /// # Examples /// @@ -315,13 +315,13 @@ impl Ipv4Addr { /// Returns true if this is a private address. /// - /// The private address ranges are defined in [RFC 1918] and include: + /// The private address ranges are defined in [IETF RFC 1918] and include: /// /// - 10.0.0.0/8 /// - 172.16.0.0/12 /// - 192.168.0.0/16 /// - /// [RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 /// /// # Examples /// @@ -348,9 +348,9 @@ impl Ipv4Addr { /// Returns true if the address is link-local (169.254.0.0/16). /// - /// This property is defined by [RFC 3927]. + /// This property is defined by [IETF RFC 3927]. /// - /// [RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 /// /// # Examples /// @@ -403,9 +403,9 @@ impl Ipv4Addr { /// Returns true if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, - /// and is defined by [RFC 5771]. + /// and is defined by [IETF RFC 5771]. /// - /// [RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 /// /// # Examples /// @@ -423,9 +423,9 @@ impl Ipv4Addr { /// Returns true if this is a broadcast address (255.255.255.255). /// - /// A broadcast address has all octets set to 255 as defined in [RFC 919]. + /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. /// - /// [RFC 919]: https://tools.ietf.org/html/rfc919 + /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 /// /// # Examples /// @@ -443,13 +443,13 @@ impl Ipv4Addr { /// Returns true if this address is in a range designated for documentation. /// - /// This is defined in [RFC 5737]: + /// This is defined in [IETF RFC 5737]: /// /// - 192.0.2.0/24 (TEST-NET-1) /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) /// - /// [RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 /// /// # Examples /// @@ -719,9 +719,9 @@ impl Ipv6Addr { /// Returns true for the special 'unspecified' address (::). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// @@ -738,9 +738,9 @@ impl Ipv6Addr { /// Returns true if this is a loopback address (::1). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// @@ -786,9 +786,9 @@ impl Ipv6Addr { /// Returns true if this is a unique local address (fc00::/7). /// - /// This property is defined in [RFC 4193]. + /// This property is defined in [IETF RFC 4193]. /// - /// [RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 /// /// # Examples /// @@ -809,9 +809,9 @@ impl Ipv6Addr { /// Returns true if the address is unicast and link-local (fe80::/10). /// - /// This property is defined in [RFC 4291]. + /// This property is defined in [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples /// @@ -853,9 +853,9 @@ impl Ipv6Addr { /// Returns true if this is an address reserved for documentation /// (2001:db8::/32). /// - /// This property is defined in [RFC 3849]. + /// This property is defined in [IETF RFC 3849]. /// - /// [RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 /// /// # Examples /// @@ -939,9 +939,9 @@ impl Ipv6Addr { /// Returns true if this is a multicast address (ff00::/8). /// - /// This property is defined by [RFC 4291]. + /// This property is defined by [IETF RFC 4291]. /// - /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// # Examples /// /// ``` From df5830a4ece5eae8451e7b3d4f77b8af92a9f9fc Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 18:28:12 +0100 Subject: [PATCH 066/905] Added links throughout std::net::ToSocketAddrs' documentation Part of #29363 In the section about the default implementations of ToSocketAddrs, I moved the bulletpoint of SocketAddrV4 & SocketAddrV6 to the one stating that SocketAddr is constructed trivially, as this is what's actually the case --- src/libstd/net/addr.rs | 52 ++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 84c4acb8d924..ea78843aa8c0 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -559,37 +559,51 @@ impl hash::Hash for SocketAddrV6 { } /// A trait for objects which can be converted or resolved to one or more -/// `SocketAddr` values. +/// [`SocketAddr`] values. /// /// This trait is used for generic address resolution when constructing network /// objects. By default it is implemented for the following types: /// -/// * `SocketAddr`, `SocketAddrV4`, `SocketAddrV6` - `to_socket_addrs` is -/// identity function. +/// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. /// -/// * `(IpvNAddr, u16)` - `to_socket_addrs` constructs `SocketAddr` trivially. +/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, +/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: +/// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(&str, u16)` - the string should be either a string representation of an -/// IP address expected by `FromStr` implementation for `IpvNAddr` or a host +/// * `(`[`&str`]`, `[`u16`]`)`: the string should be either a string representation +/// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. /// -/// * `&str` - the string should be either a string representation of a -/// `SocketAddr` as expected by its `FromStr` implementation or a string like -/// `:` pair where `` is a `u16` value. +/// * [`&str`]: the string should be either a string representation of a +/// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like +/// `:` pair where `` is a [`u16`] value. /// -/// This trait allows constructing network objects like `TcpStream` or -/// `UdpSocket` easily with values of various types for the bind/connection +/// This trait allows constructing network objects like [`TcpStream`] or +/// [`UdpSocket`] easily with values of various types for the bind/connection /// address. It is needed because sometimes one type is more appropriate than /// the other: for simple uses a string like `"localhost:12345"` is much nicer -/// than manual construction of the corresponding `SocketAddr`, but sometimes -/// `SocketAddr` value is *the* main source of the address, and converting it to +/// than manual construction of the corresponding [`SocketAddr`], but sometimes +/// [`SocketAddr`] value is *the* main source of the address, and converting it to /// some other type (e.g. a string) just for it to be converted back to -/// `SocketAddr` in constructor methods is pointless. +/// [`SocketAddr`] in constructor methods is pointless. /// /// Addresses returned by the operating system that are not IP addresses are /// silently ignored. /// -/// Some examples: +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// [`&str`]: ../../std/primitive.str.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +/// [`to_socket_addrs`]: #tymethod.to_socket_addrs +/// [`UdpSocket`]: ../../std/net/struct.UdpSocket.html +/// [`u16`]: ../../std/primitive.u16.html +/// +/// # Examples /// /// ```no_run /// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr}; @@ -622,7 +636,7 @@ pub trait ToSocketAddrs { #[stable(feature = "rust1", since = "1.0.0")] type Iter: Iterator; - /// Converts this object to an iterator of resolved `SocketAddr`s. + /// Converts this object to an iterator of resolved [`SocketAddr`]s. /// /// The returned iterator may not actually yield any values depending on the /// outcome of any resolution performed. @@ -630,9 +644,13 @@ pub trait ToSocketAddrs { /// Note that this function may block the current thread while resolution is /// performed. /// + /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// /// # Errors /// - /// Any errors encountered during resolution will be returned as an `Err`. + /// Any errors encountered during resolution will be returned as an [`Err`]. + /// + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[stable(feature = "rust1", since = "1.0.0")] fn to_socket_addrs(&self) -> io::Result; } From 0d5baba70d3adbb2a8ea436c6c89f21c1c6927b8 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 25 Mar 2017 19:23:13 +0100 Subject: [PATCH 067/905] Added links to std::net::AddrParseError's documentation Additionally changed the summary sentence to be more consistent with most of the other FromStr implementations' error types. --- src/libstd/net/parser.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index d86711c10ac7..7d7c67ff3f9f 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -368,7 +368,19 @@ impl FromStr for SocketAddr { } } -/// An error returned when parsing an IP address or a socket address. +/// An error which can be returned when parsing an IP address or a socket address. +/// +/// This error is used as the error type for the [`FromStr`] implementation for +/// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and +/// [`SocketAddrV6`]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct AddrParseError(()); From 347b70901cdabcd78d2b0229c13c31b334b00617 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 14:25:31 +0200 Subject: [PATCH 068/905] Expanded and added links to std::net::{IpAddr,Ipv4Addr,Ipv6Addr} docs Part of #29363 Expanded top-level documentation & linked to relevant IETF RFCs. Added a bunch of links (to true/false/Ipv4Addr/etc.) throughout the docs. --- src/libstd/net/ip.rs | 204 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 161 insertions(+), 43 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 44dc689a30f4..3e58a335470a 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -21,44 +21,99 @@ use net::{hton, ntoh}; use sys::net::netc as c; use sys_common::{AsInner, FromInner}; -/// An IP address, either an IPv4 or IPv6 address. +/// Either an IPv4 address or an IPv6 address. +/// +/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their +/// respective documentation for more details. +/// +/// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +/// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html /// /// # Examples /// -/// Constructing an IPv4 address: -/// /// ``` -/// use std::net::{IpAddr, Ipv4Addr}; +/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// -/// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); -/// ``` +/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// -/// Constructing an IPv6 address: +/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4)); +/// assert_eq!("::1".parse(), Ok(localhost_v6)); /// -/// ``` -/// use std::net::{IpAddr, Ipv6Addr}; -/// -/// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(localhost_v4.is_ipv6(), false); +/// assert_eq!(localhost_v4.is_ipv4(), true); /// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] pub enum IpAddr { - /// Representation of an IPv4 address. + /// An IPv4 address. #[stable(feature = "ip_addr", since = "1.7.0")] V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr), - /// Representation of an IPv6 address. + /// An IPv6 address. #[stable(feature = "ip_addr", since = "1.7.0")] V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr), } -/// Representation of an IPv4 address. +/// An IPv4 address. +/// +/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791]. +/// They are usually represented as four octets. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal +/// notation, divided by `.` (this is called "dot-decimal notation"). +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv4Addr; +/// +/// let localhost = Ipv4Addr::new(127, 0, 0, 1); +/// assert_eq!("127.0.0.1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { inner: c::in_addr, } -/// Representation of an IPv6 address. +/// An IPv6 address. +/// +/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291]. +/// They are usually represented as eight 16-bit segments. +/// +/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. +/// +/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 +/// [`IpAddr`]: ../../std/net/enum.IpAddr.html +/// +/// # Textual representation +/// +/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent +/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// notation, and segments are separated by `:`. For more information, see +/// [IETF RFC 5952]. +/// +/// [`FromStr`]: ../../std/str/trait.FromStr.html +/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952 +/// +/// # Examples +/// +/// ``` +/// use std::net::Ipv6Addr; +/// +/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +/// assert_eq!("::1".parse(), Ok(localhost)); +/// assert_eq!(localhost.is_loopback(), true); #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { @@ -78,10 +133,14 @@ pub enum Ipv6MulticastScope { } impl IpAddr { - /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). + /// Returns [`true`] for the special 'unspecified' address. + /// + /// See the documentation for [`Ipv4Addr::is_unspecified`][IPv4] and + /// [`Ipv6Addr::is_unspecified`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -99,10 +158,14 @@ impl IpAddr { } } - /// Returns true if this is a loopback address ([IPv4], [IPv6]). + /// Returns [`true`] if this is a loopback address. + /// + /// See the documentation for [`Ipv4Addr::is_loopback`][IPv4] and + /// [`Ipv6Addr::is_loopback`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -120,10 +183,14 @@ impl IpAddr { } } - /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). + /// Returns [`true`] if the address appears to be globally routable. + /// + /// See the documentation for [`Ipv4Addr::is_global`][IPv4] and + /// [`Ipv6Addr::is_global`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -145,10 +212,14 @@ impl IpAddr { } } - /// Returns true if this is a multicast address ([IPv4], [IPv6]). + /// Returns [`true`] if this is a multicast address. + /// + /// See the documentation for [`Ipv4Addr::is_multicast`][IPv4] and + /// [`Ipv6Addr::is_multicast`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -166,10 +237,14 @@ impl IpAddr { } } - /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). + /// Returns [`true`] if this address is in a range designated for documentation. + /// + /// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and + /// [`Ipv6Addr::is_documentation`][IPv6] for more details. /// /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -191,7 +266,13 @@ impl IpAddr { } } - /// Returns true if this address is a valid IPv4 address, false if it's a valid IPv6 address. + /// Returns [`true`] if this address is an [IPv4 address] and [`false`] if it's an + /// [IPv6 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv4 address]: #variant.V4 + /// [IPv6 address]: #variant.V6 /// /// # Examples /// @@ -212,7 +293,13 @@ impl IpAddr { } } - /// Returns true if this address is a valid IPv6 address, false if it's a valid IPv4 address. + /// Returns [`true`] if this address is an [IPv6 address] and [`false`] if it's an + /// [IPv4 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IPv4 address]: #variant.V4 + /// [IPv6 address]: #variant.V6 /// /// # Examples /// @@ -274,12 +361,13 @@ impl Ipv4Addr { [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] } - /// Returns true for the special 'unspecified' address (0.0.0.0). + /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). /// /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -294,11 +382,12 @@ impl Ipv4Addr { self.inner.s_addr == 0 } - /// Returns true if this is a loopback address (127.0.0.0/8). + /// Returns [`true`] if this is a loopback address (127.0.0.0/8). /// /// This property is defined by [IETF RFC 1122]. /// /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -313,7 +402,7 @@ impl Ipv4Addr { self.octets()[0] == 127 } - /// Returns true if this is a private address. + /// Returns [`true`] if this is a private address. /// /// The private address ranges are defined in [IETF RFC 1918] and include: /// @@ -322,6 +411,7 @@ impl Ipv4Addr { /// - 192.168.0.0/16 /// /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -346,11 +436,12 @@ impl Ipv4Addr { } } - /// Returns true if the address is link-local (169.254.0.0/16). + /// Returns [`true`] if the address is link-local (169.254.0.0/16). /// /// This property is defined by [IETF RFC 3927]. /// /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -366,7 +457,7 @@ impl Ipv4Addr { self.octets()[0] == 169 && self.octets()[1] == 254 } - /// Returns true if the address appears to be globally routable. + /// Returns [`true`] if the address appears to be globally routable. /// See [iana-ipv4-special-registry][ipv4-sr]. /// /// The following return false: @@ -379,6 +470,7 @@ impl Ipv4Addr { /// - the unspecified address (0.0.0.0) /// /// [ipv4-sr]: http://goo.gl/RaZ7lg + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -400,12 +492,13 @@ impl Ipv4Addr { !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() } - /// Returns true if this is a multicast address (224.0.0.0/4). + /// Returns [`true`] if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, /// and is defined by [IETF RFC 5771]. /// /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -421,11 +514,12 @@ impl Ipv4Addr { self.octets()[0] >= 224 && self.octets()[0] <= 239 } - /// Returns true if this is a broadcast address (255.255.255.255). + /// Returns [`true`] if this is a broadcast address (255.255.255.255). /// /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. /// /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -441,7 +535,7 @@ impl Ipv4Addr { self.octets()[2] == 255 && self.octets()[3] == 255 } - /// Returns true if this address is in a range designated for documentation. + /// Returns [`true`] if this address is in a range designated for documentation. /// /// This is defined in [IETF RFC 5737]: /// @@ -450,6 +544,7 @@ impl Ipv4Addr { /// - 203.0.113.0/24 (TEST-NET-3) /// /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -471,10 +566,12 @@ impl Ipv4Addr { } } - /// Converts this address to an IPv4-compatible IPv6 address. + /// Converts this address to an IPv4-compatible [IPv6 address]. /// /// a.b.c.d becomes ::a.b.c.d /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// /// # Examples /// /// ``` @@ -490,10 +587,12 @@ impl Ipv4Addr { ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) } - /// Converts this address to an IPv4-mapped IPv6 address. + /// Converts this address to an IPv4-mapped [IPv6 address]. /// /// a.b.c.d becomes ::ffff:a.b.c.d /// + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html + /// /// # Examples /// /// ``` @@ -717,11 +816,12 @@ impl Ipv6Addr { ] } - /// Returns true for the special 'unspecified' address (::). + /// Returns [`true`] for the special 'unspecified' address (::). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -736,11 +836,12 @@ impl Ipv6Addr { self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] } - /// Returns true if this is a loopback address (::1). + /// Returns [`true`] if this is a loopback address (::1). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -755,14 +856,17 @@ impl Ipv6Addr { self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] } - /// Returns true if the address appears to be globally routable. + /// Returns [`true`] if the address appears to be globally routable. /// - /// The following return false: + /// The following return [`false`]: /// /// - the loopback address /// - link-local, site-local, and unique local unicast addresses /// - interface-, link-, realm-, admin- and site-local multicast addresses /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -784,11 +888,12 @@ impl Ipv6Addr { } } - /// Returns true if this is a unique local address (fc00::/7). + /// Returns [`true`] if this is a unique local address (fc00::/7). /// /// This property is defined in [IETF RFC 4193]. /// /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -807,11 +912,12 @@ impl Ipv6Addr { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns true if the address is unicast and link-local (fe80::/10). + /// Returns [`true`] if the address is unicast and link-local (fe80::/10). /// /// This property is defined in [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -830,9 +936,11 @@ impl Ipv6Addr { (self.segments()[0] & 0xffc0) == 0xfe80 } - /// Returns true if this is a deprecated unicast site-local address + /// Returns [`true`] if this is a deprecated unicast site-local address /// (fec0::/10). /// + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -850,12 +958,13 @@ impl Ipv6Addr { (self.segments()[0] & 0xffc0) == 0xfec0 } - /// Returns true if this is an address reserved for documentation + /// Returns [`true`] if this is an address reserved for documentation /// (2001:db8::/32). /// /// This property is defined in [IETF RFC 3849]. /// /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -874,7 +983,7 @@ impl Ipv6Addr { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } - /// Returns true if the address is a globally routable unicast address. + /// Returns [`true`] if the address is a globally routable unicast address. /// /// The following return false: /// @@ -885,6 +994,8 @@ impl Ipv6Addr { /// - the unspecified address /// - the address range reserved for documentation /// + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -937,11 +1048,13 @@ impl Ipv6Addr { } } - /// Returns true if this is a multicast address (ff00::/8). + /// Returns [`true`] if this is a multicast address (ff00::/8). /// /// This property is defined by [IETF RFC 4291]. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [`true`]: ../../std/primitive.bool.html + /// /// # Examples /// /// ``` @@ -955,11 +1068,16 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } - /// Converts this address to an IPv4 address. Returns None if this address is + /// Converts this address to an [IPv4 address]. Returns [`None`] if this address is /// neither IPv4-compatible or IPv4-mapped. /// /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// /// ``` /// use std::net::{Ipv4Addr, Ipv6Addr}; /// From be713fa4bf12cf87a799dddfd29ab095a548fd01 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 01:01:32 +0100 Subject: [PATCH 069/905] Removed link in std::net::ToSocketAddr's summary sentence Relative links in trait methods don't resolve in e.g. std/primitive.tuple.html :( --- src/libstd/net/addr.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index ea78843aa8c0..0b63a5a5c143 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -636,7 +636,7 @@ pub trait ToSocketAddrs { #[stable(feature = "rust1", since = "1.0.0")] type Iter: Iterator; - /// Converts this object to an iterator of resolved [`SocketAddr`]s. + /// Converts this object to an iterator of resolved `SocketAddr`s. /// /// The returned iterator may not actually yield any values depending on the /// outcome of any resolution performed. @@ -644,8 +644,6 @@ pub trait ToSocketAddrs { /// Note that this function may block the current thread while resolution is /// performed. /// - /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html - /// /// # Errors /// /// Any errors encountered during resolution will be returned as an [`Err`]. From 6f0c742b001e7861099e1048c4f0cd08f0528774 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 14:13:37 +0200 Subject: [PATCH 070/905] Expanded and added links to std::net::{SocketAddr,SocketAddrV4,SocketAddrV6} docs Part of #29363 Changed summary sentences of SocketAddr and IpAddr for consistency Linked to SocketAddrV4 and SocketAddrV6 from SocketAddr, moving explaination there Expanded top-level docs for SocketAddrV4 and SocketAddrV6, linking to some relevant IETF RFCs, and linking back to SocketAddr Changed some of the method summaries to third person as per RFC 1574; added links to IETF RFCs where appropriate --- src/libstd/net/addr.rs | 114 ++++++++++++++++++++++++++++++++--------- src/libstd/net/ip.rs | 2 +- 2 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 0b63a5a5c143..6584531a92a2 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -20,15 +20,17 @@ use vec; use iter; use slice; -/// Representation of a socket address for networking applications. +/// An internet socket address, either IPv4 or IPv6. /// -/// A socket address can either represent the IPv4 or IPv6 protocol and is -/// paired with at least a port number as well. Each protocol may have more -/// specific information about the address available to it as well. +/// This enum can contain either an [`SocketAddrV4`] or an [`SocketAddrV6`]. see their +/// respective documentation for more details. +/// +/// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +/// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SocketAddr { - /// An IPv4 socket address which is a (ip, port) combination. + /// An IPv4 socket address. #[stable(feature = "rust1", since = "1.0.0")] V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4), /// An IPv6 socket address. @@ -36,18 +38,39 @@ pub enum SocketAddr { V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6), } -/// An IPv4 socket address which is a (ip, port) combination. +/// An IPv4 socket address. +/// +/// IPv4 socket addresses consist of an [IPv4 address] and a 16-bit port number, as +/// stated in [IETF RFC 793]. +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV4 { inner: c::sockaddr_in } /// An IPv6 socket address. +/// +/// IPv6 socket addresses consist of an [Ipv6 address], a 16-bit port number, as well +/// as fields containing the traffic class, the flow label, and a scope identifier +/// (see [IETF RFC 2553, Section 3.3] for more details). +/// +/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. +/// +/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 +/// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html +/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV6 { inner: c::sockaddr_in6 } impl SocketAddr { - /// Creates a new socket address from the (ip, port) pair. + /// Creates a new socket address from an [IP address] and a port number. + /// + /// [IP address]: ../../std/net/enum.IpAddr.html /// /// # Examples /// @@ -84,7 +107,7 @@ impl SocketAddr { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -123,7 +146,7 @@ impl SocketAddr { } } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -142,8 +165,14 @@ impl SocketAddr { } } - /// Returns true if the IP in this `SocketAddr` is a valid IPv4 address, - /// false if it's a valid IPv6 address. + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [IPv4 address] and [`false`] if it's an [IPv6 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 + /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples /// @@ -164,8 +193,14 @@ impl SocketAddr { } } - /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address, - /// false if it's a valid IPv4 address. + /// Returns [`true`] if the [IP address] in this `SocketAddr` is an + /// [IPv6 address] and [`false`] if it's an [IPv4 address]. + /// + /// [`true`]: ../../std/primitive.bool.html + /// [`false`]: ../../std/primitive.bool.html + /// [IP address]: ../../std/net/enum.IpAddr.html + /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 + /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples /// @@ -189,7 +224,9 @@ impl SocketAddr { } impl SocketAddrV4 { - /// Creates a new socket address from the (ip, port) pair. + /// Creates a new socket address from an [IPv4 address] and a port number. + /// + /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html /// /// # Examples /// @@ -227,7 +264,7 @@ impl SocketAddrV4 { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -258,7 +295,7 @@ impl SocketAddrV4 { ntoh(self.inner.sin_port) } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -276,8 +313,14 @@ impl SocketAddrV4 { } impl SocketAddrV6 { - /// Creates a new socket address from the ip/port/flowinfo/scope_id - /// components. + /// Creates a new socket address from an [IPv6 address], a 16-bit port number, + /// and the `flowinfo` and `scope_id` fields. + /// + /// For more information on the meaning and layout of the `flowinfo` and `scope_id` + /// parameters, see [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html /// /// # Examples /// @@ -318,7 +361,7 @@ impl SocketAddrV6 { } } - /// Change the IP address associated with this socket address. + /// Changes the IP address associated with this socket address. /// /// # Examples /// @@ -349,7 +392,7 @@ impl SocketAddrV6 { ntoh(self.inner.sin6_port) } - /// Change the port number associated with this socket address. + /// Changes the port number associated with this socket address. /// /// # Examples /// @@ -365,8 +408,17 @@ impl SocketAddrV6 { self.inner.sin6_port = hton(new_port); } - /// Returns the flow information associated with this address, - /// corresponding to the `sin6_flowinfo` field in C. + /// Returns the flow information associated with this address. + /// + /// This information corresponds to the `sin6_flowinfo` field in C, as specified in + /// [IETF RFC 2553, Section 3.3]. It combines information about the flow label and + /// the traffic class as specified in [IETF RFC 2460], respectively [Section 6] and + /// [Section 7]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 + /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 + /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6 + /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7 /// /// # Examples /// @@ -381,7 +433,11 @@ impl SocketAddrV6 { self.inner.sin6_flowinfo } - /// Change the flow information associated with this socket address. + /// Changes the flow information associated with this socket address. + /// + /// See the [`flowinfo`] method's documentation for more details. + /// + /// [`flowinfo`]: #method.flowinfo /// /// # Examples /// @@ -397,8 +453,12 @@ impl SocketAddrV6 { self.inner.sin6_flowinfo = new_flowinfo; } - /// Returns the scope ID associated with this address, - /// corresponding to the `sin6_scope_id` field in C. + /// Returns the scope ID associated with this address. + /// + /// This information corresponds to the `sin6_scope_id` field in C, as specified in + /// [IETF RFC 2553, Section 3.3]. + /// + /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// /// # Examples /// @@ -415,6 +475,10 @@ impl SocketAddrV6 { /// Change the scope ID associated with this socket address. /// + /// See the [`scope_id`] method's documentation for more details. + /// + /// [`scope_id`]: #method.scope_id + /// /// # Examples /// /// ``` diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 3e58a335470a..85803ff0501d 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -21,7 +21,7 @@ use net::{hton, ntoh}; use sys::net::netc as c; use sys_common::{AsInner, FromInner}; -/// Either an IPv4 address or an IPv6 address. +/// An IP address, either IPv4 or IPv6. /// /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their /// respective documentation for more details. From 1a9c8baed55547593610eb935c9cceccec40fdb4 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 15:43:25 +0200 Subject: [PATCH 071/905] Added examples to std::net::{SocketAddr, SocketAddrV4, SocketAddrV6} docs --- src/libstd/net/addr.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 6584531a92a2..ccfd2a1dfb15 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -27,6 +27,18 @@ use slice; /// /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +/// +/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.port(), 8080); +/// assert_eq!(socket.is_ipv4(), true); +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SocketAddr { @@ -48,6 +60,18 @@ pub enum SocketAddr { /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv4Addr, SocketAddrV4}; +/// +/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080); +/// +/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV4 { inner: c::sockaddr_in } @@ -63,6 +87,18 @@ pub struct SocketAddrV4 { inner: c::sockaddr_in } /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +/// +/// # Examples +/// +/// ``` +/// use std::net::{Ipv6Addr, SocketAddrV6}; +/// +/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); +/// +/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); +/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); +/// assert_eq!(socket.port(), 8080); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV6 { inner: c::sockaddr_in6 } From ad816f81748e6314b428a91352b0eb536f7fffc5 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 16:12:27 +0200 Subject: [PATCH 072/905] Added links to std::net::Shutdown docs and made them more consistent Part of #29363 --- src/libstd/net/mod.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index b0d2e3e4687b..e4593cf38177 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -43,17 +43,30 @@ mod test; #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Shutdown { - /// Indicates that the reading portion of this stream/socket should be shut - /// down. All currently blocked and future reads will return `Ok(0)`. + /// The reading portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [reads] will return [`Ok(0)`]. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [reads]: ../../std/io/trait.Read.html + /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok #[stable(feature = "rust1", since = "1.0.0")] Read, - /// Indicates that the writing portion of this stream/socket should be shut - /// down. All currently blocked and future writes will return an error. + /// The writing portion of the [`TcpStream`] should be shut down. + /// + /// All currently blocked and future [writes] will return an error. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [writes]: ../../std/io/trait.Write.html #[stable(feature = "rust1", since = "1.0.0")] Write, - /// Shut down both the reading and writing portions of this stream. + /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. /// - /// See `Shutdown::Read` and `Shutdown::Write` for more information. + /// See [`Shutdown::Read`] and [`Shutdown::Write`] for more information. + /// + /// [`TcpStream`]: ../../std/net/struct.TcpStream.html + /// [`Shutdown::Read`]: #variant.Read + /// [`Shutdown::Write`]: #variant.Write #[stable(feature = "rust1", since = "1.0.0")] Both, } From 597bcec379bec40641eb6a4637ebbec69e184582 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 17:06:39 +0200 Subject: [PATCH 073/905] Expanded top-level docs for std::net{TcpListener,TcpStream,UdpSocket} Part of #29363 --- src/libstd/net/tcp.rs | 37 +++++++++++++++++++++++++++++++++---- src/libstd/net/udp.rs | 30 +++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index c6cf748d981c..cf119720e5a1 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -17,10 +17,25 @@ use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; -/// A structure which represents a TCP stream between a local socket and a -/// remote socket. +/// A TCP stream between a local and a remote socket. /// -/// The socket will be closed when the value is dropped. +/// After creating a `TcpStream` by either [`connect`]ing to a remote host or +/// [`accept`]ing a connection on a [`TcpListener`], data can be transmitted +/// by [reading] and [writing] to it. +/// +/// The connection will be closed when the value is dropped. The reading and writing +/// portions of the connection can also be shut down individually with the [`shutdown`] +/// method. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: ../../std/net/struct.TcpListener.html#method.accept +/// [`connect`]: #method.connect +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [reading]: ../../std/io/trait.Read.html +/// [`shutdown`]: #method.shutdown +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [writing]: ../../std/io/trait.Write.html /// /// # Examples /// @@ -39,7 +54,21 @@ use time::Duration; #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpStream(net_imp::TcpStream); -/// A structure representing a socket server. +/// A TCP socket server, listening for connections. +/// +/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens +/// for incoming TCP connections. These can be accepted by calling [`accept`] or by +/// iterating over the [`Incoming`] iterator returned by [`incoming`]. +/// +/// The socket will be closed when the value is dropped. +/// +/// The Transmission Control Protocol is specified in [IETF RFC 793]. +/// +/// [`accept`]: #method.accept +/// [`bind`]: #method.bind +/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 +/// [`Incoming`]: ../../std/net/struct.Incoming.html +/// [`incoming`]: #method.incoming /// /// # Examples /// diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 1ebce9393484..cdf04f7f1a48 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -15,11 +15,29 @@ use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; -/// A User Datagram Protocol socket. +/// A UDP socket. /// -/// This is an implementation of a bound UDP socket. This supports both IPv4 and -/// IPv6 addresses, and there is no corresponding notion of a server because UDP -/// is a datagram protocol. +/// After creating a `UdpSocket` by [`bind`]ing it to a socket address, data can be +/// [sent to] and [received from] any other socket address. +/// +/// Although UDP is a connectionless protocol, this implementation provides an interface +/// to set an address where data should be sent and received from. After setting a remote +/// address with [`connect`], data can be sent to and received from that address with +/// [`send`] and [`recv`]. +/// +/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is +/// an unordered, unreliable protocol; refer to [`TcpListener`] and [`TcpStream`] for TCP +/// primitives. +/// +/// [`bind`]: #method.bind +/// [`connect`]: #method.connect +/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768 +/// [`recv`]: #method.recv +/// [received from]: #method.recv_from +/// [`send`]: #method.send +/// [sent to]: #method.send_to +/// [`TcpListener`]: ../../std/net/struct.TcpListener.html +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples /// @@ -582,9 +600,11 @@ impl UdpSocket { /// Receives data on the socket from the remote address to which it is /// connected. /// - /// The `connect` method will connect this socket to a remote address. This + /// The [`connect`] method will connect this socket to a remote address. This /// method will fail if the socket is not connected. /// + /// [`connect`]: #method.connect + /// /// # Examples /// /// ```no_run From 577677d55d7ca793b3845577939d99a97e112691 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 17:27:40 +0200 Subject: [PATCH 074/905] Expanded std::net module docs Part of #29363 --- src/libstd/net/mod.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index e4593cf38177..3b4808fee251 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -9,6 +9,32 @@ // except according to those terms. //! Networking primitives for TCP/UDP communication. +//! +//! This module provides networking functionality for the Transmission Control and User +//! Datagram Protocols, as well as types for IP and socket addresses. +//! +//! # Organization +//! +//! * [`TcpListener`] and [`TcpStream`] provide functionality for communication over TCP +//! * [`UdpSocket`] provides functionality for communication over UDP +//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and +//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses +//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] +//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses +//! * [`ToSocketAddr`] is a trait that used for generic address resolution interacting +//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] +//! * Other types are return or parameter types for various methods in this module +//! +//! [`IpAddr`]: ../../std/net/enum.IpAddr.html +//! [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html +//! [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html +//! [`SocketAddr`]: ../../std/net/enum.SocketAddr.html +//! [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html +//! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html +//! [`TcpListener`]: ../../std/net/struct.TcpListener.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`ToSocketAddr`]: ../../std/net/trait.ToSocketAddr.html +//! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html #![stable(feature = "rust1", since = "1.0.0")] From c2601fd358769cbecae479e8d32521f6e5d5c633 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sun, 26 Mar 2017 18:06:22 +0200 Subject: [PATCH 075/905] fix trailing whitespace --- src/libstd/net/ip.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 85803ff0501d..2a1f959b35d0 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -99,7 +99,7 @@ pub struct Ipv4Addr { /// # Textual representation /// /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent -/// an IPv6 address in text, but in general, each segments is written in hexadecimal +/// an IPv6 address in text, but in general, each segments is written in hexadecimal /// notation, and segments are separated by `:`. For more information, see /// [IETF RFC 5952]. /// From 2cf686f2cdd6446a3cd47df0305ead40fabe85df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Sun, 26 Mar 2017 18:54:08 +0200 Subject: [PATCH 076/905] Implement AsRawFd/IntoRawFd for RawFd This is useful to build os abstraction like the nix crate does. It allows to define functions, which accepts generic arguments of data structures convertible to RawFd, including RawFd itself. For example: fn write(fd: FD, buf: &[u8]) -> Result instead of: fn write(fd: RawFd, buf: &[u8]) -> Result write(foo.as_raw_fd(), buf); --- src/libstd/sys/unix/ext/io.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 296235e173d1..75aa72e3cff8 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -72,6 +72,13 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -84,6 +91,14 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} + #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { fn into_raw_fd(self) -> RawFd { From fda8e1571f7a0c4da77c57bc7a7728c4ed1e6aea Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Sun, 26 Mar 2017 01:01:54 +0300 Subject: [PATCH 077/905] libcore: sort_unstable: improve randomization in break_patterns. Select 3 random points instead of just 1. Also the code now compiles on 16bit architectures. --- src/libcore/slice/sort.rs | 50 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 307e4974d976..3612ee65bca0 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -498,32 +498,40 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize #[cold] fn break_patterns(v: &mut [T]) { let len = v.len(); - if len >= 8 { - // A random number will be taken modulo this one. The modulus is a power of two so that we - // can simply take bitwise "and", thus avoiding costly CPU operations. - let modulus = (len / 4).next_power_of_two(); - debug_assert!(modulus >= 1 && modulus <= len / 2); + // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia. + let mut random = len as u32; + let mut gen_u32 = || { + random ^= random << 13; + random ^= random >> 17; + random ^= random << 5; + random + }; + let mut gen_usize = || { + if mem::size_of::() <= 4 { + gen_u32() as usize + } else { + (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize + } + }; - // Pseudorandom number generation from the "Xorshift RNGs" paper by George Marsaglia. - let mut random = len; - random ^= random << 13; - random ^= random >> 17; - random ^= random << 5; - random &= modulus - 1; - debug_assert!(random < len / 2); + // Take random numbers modulo this number. + // The number fits into `usize` because `len` is not greater than `isize::MAX`. + let modulus = len.next_power_of_two(); - // The first index. - let a = len / 4 * 2; - debug_assert!(a >= 1 && a < len - 2); + // Some pivot candidates will be in the nearby of this index. Let's randomize them. + let pos = len / 4 * 2; - // The second index. - let b = len / 4 + random; - debug_assert!(b >= 1 && b < len - 2); - - // Swap neighbourhoods of `a` and `b`. for i in 0..3 { - v.swap(a - 1 + i, b - 1 + i); + // Generate a random number modulo `len`. However, in order to avoid costly operations + // we first take it modulo a power of two, and then decrease by `len` until it fits + // into the range `[0, len - 1]`. + let mut other = gen_usize() & (modulus - 1); + while other >= len { + other -= len; + } + + v.swap(pos - 1 + i, other); } } } From 1579fbd8ca8452d462f76e47a5367c1d51fb8d43 Mon Sep 17 00:00:00 2001 From: Alan Stoate Date: Mon, 27 Mar 2017 07:46:43 +1030 Subject: [PATCH 078/905] Fixed spelling mistakes --- src/libstd/ascii.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index ba2b059f8284..1cac11f668d9 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -63,7 +63,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn is_ascii(&self) -> bool; - /// Makes a copy of the value in it's ASCII upper case equivalent. + /// 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. @@ -92,7 +92,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_uppercase(&self) -> Self::Owned; - /// Makes a copy of the value in it's ASCII lower case equivalent. + /// 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. From 50728e52455804143e5cc601004381e395a1e2f7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 26 Mar 2017 19:35:46 +0300 Subject: [PATCH 079/905] borrowck: consolidate `mut` suggestions This converts all of borrowck's `mut` suggestions to a new `mc::ImmutabilityBlame` API instead of the current mix of various hacks. Fixes #35937. Fixes #40823. --- src/librustc/middle/mem_categorization.rs | 140 +++++------- .../borrowck/gather_loans/mod.rs | 9 - src/librustc_borrowck/borrowck/mod.rs | 210 ++++++++++-------- src/librustc_borrowck/diagnostics.rs | 6 +- .../compile-fail/augmented-assignments.rs | 2 +- .../borrowck/borrowck-issue-14498.rs | 6 +- src/test/compile-fail/issue-33819.rs | 2 +- src/test/compile-fail/mut-suggestion.rs | 4 +- .../huge_multispan_highlight.stderr | 2 +- src/test/ui/did_you_mean/issue-31424.stderr | 2 + src/test/ui/did_you_mean/issue-35937.rs | 31 +++ src/test/ui/did_you_mean/issue-35937.stderr | 26 +++ src/test/ui/did_you_mean/issue-38147-2.stderr | 2 +- src/test/ui/did_you_mean/issue-38147-3.stderr | 4 +- src/test/ui/did_you_mean/issue-39544.rs | 11 +- src/test/ui/did_you_mean/issue-39544.stderr | 19 +- src/test/ui/did_you_mean/issue-40823.rs | 14 ++ src/test/ui/did_you_mean/issue-40823.stderr | 8 + ...ck-borrow-overloaded-auto-deref-mut.stderr | 8 +- ...orrowck-borrow-overloaded-deref-mut.stderr | 4 +- .../ui/span/borrowck-object-mutability.stderr | 3 + 21 files changed, 305 insertions(+), 208 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-35937.rs create mode 100644 src/test/ui/did_you_mean/issue-35937.stderr create mode 100644 src/test/ui/did_you_mean/issue-40823.rs create mode 100644 src/test/ui/did_you_mean/issue-40823.stderr diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0cf53826dd42..3b52e85e08e3 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -194,76 +194,75 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; +pub enum ImmutabilityBlame<'tcx> { + ImmLocal(ast::NodeId), + ClosureEnv(ast::NodeId), + LocalDeref(ast::NodeId), + AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef) +} + impl<'tcx> cmt_<'tcx> { - pub fn get_def(&self) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - Some(nid) - } else { - None - } + fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef) + { + let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| { + bug!("interior cmt {:?} is not an ADT", self) + }); + let variant_def = match self.cat { + Categorization::Downcast(_, variant_did) => { + adt_def.variant_with_id(variant_did) } - _ => None - } + _ => { + assert!(adt_def.is_univariant()); + &adt_def.variants[0] + } + }; + let field_def = match field_name { + NamedField(name) => variant_def.field_named(name), + PositionalField(idx) => &variant_def.fields[idx] + }; + (adt_def, field_def) } - pub fn get_field(&self, name: ast::Name) -> Option { + pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(_) = cmt.cat { - if let ty::TyAdt(def, _) = self.ty.sty { - if def.is_struct() { - return def.struct_variant().find_field_named(name).map(|x| x.did); + Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => { + // try to figure out where the immutable reference came from + match base_cmt.cat { + Categorization::Local(node_id) => + Some(ImmutabilityBlame::LocalDeref(node_id)), + Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { + let (adt_def, field_def) = base_cmt.resolve_field(field_name); + Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)) + } + Categorization::Upvar(Upvar { id, .. }) => { + if let NoteClosureEnv(..) = self.note { + Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id)) + } else { + None } } - None - } else { - cmt.get_field(name) + _ => None } } - _ => None - } - } - - pub fn get_field_name(&self) -> Option { - match self.cat { - Categorization::Interior(_, ref ik) => { - if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik { - Some(name) - } else { - None - } + Categorization::Local(node_id) => { + Some(ImmutabilityBlame::ImmLocal(node_id)) } - Categorization::Deref(ref cmt, ..) | - Categorization::Downcast(ref cmt, _) => { - cmt.get_field_name() + Categorization::Rvalue(..) | + Categorization::Upvar(..) | + Categorization::Deref(.., UnsafePtr(..)) => { + // This should not be reachable up to inference limitations. + None } - _ => None, - } - } - - pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - if let ty::TyAdt(_, _) = self.ty.sty { - if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty { - return Some(nid); - } - } - None - } else { - cmt.get_arg_if_immutable(map) - } + Categorization::Interior(ref base_cmt, _) | + Categorization::Downcast(ref base_cmt, _) | + Categorization::Deref(ref base_cmt, _, _) => { + base_cmt.immutability_blame() + } + Categorization::StaticItem => { + // Do we want to do something here? + None } - _ => None } } } @@ -1282,9 +1281,6 @@ pub enum Aliasability { #[derive(Copy, Clone, Debug)] pub enum AliasableReason { AliasableBorrowed, - AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env - AliasableOther, - UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique AliasableStatic, AliasableStaticMut, } @@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> { Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) | Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, _, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { // Aliasability depends on base cmt b.freely_aliasable() } - Categorization::Deref(ref b, _, Unique) => { - let sub = b.freely_aliasable(); - if b.mutbl.is_mutable() { - // Aliasability depends on base cmt alone - sub - } else { - // Do not allow mutation through an immutable box. - ImmutableUnique(Box::new(sub)) - } - } - Categorization::Rvalue(..) | Categorization::Local(..) | Categorization::Upvar(..) | @@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => { - match base.cat { - Categorization::Upvar(Upvar{ id, .. }) => - FreelyAliasable(AliasableClosure(id.closure_expr_id)), - _ => FreelyAliasable(AliasableBorrowed) - } + Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => { + FreelyAliasable(AliasableBorrowed) } } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 28b6c7a13f17..cedb9e1cd1cf 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, // user knows what they're doing in these cases. Ok(()) } - (mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => { - bccx.report_aliasability_violation( - borrow_span, - loan_cause, - mc::AliasableReason::UnaliasableImmutable, - cmt); - Err(()) - } (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) | (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => { bccx.report_aliasability_violation( @@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { self.move_error_collector.report_potential_errors(self.bccx); } } - diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 20d495976b05..0981369ace5c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -34,6 +34,7 @@ use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; +use rustc::middle::mem_categorization::ImmutabilityBlame; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; @@ -41,6 +42,7 @@ use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; +use syntax::symbol::keywords; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; @@ -659,12 +661,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { + fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { let span = err.span.clone(); - let mut immutable_field = None; - let mut local_def = None; - let msg = &match err.code { + let msg = match err.code { err_mutbl => { let descr = match err.cmt.note { mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => { @@ -700,27 +700,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { - // Check for this field's definition to see if it is an immutable reference - // and suggest making it mutable if that is the case. - immutable_field = err.cmt.get_field_name() - .and_then(|name| err.cmt.get_field(name)) - .and_then(|did| self.tcx.hir.as_local_node_id(did)) - .and_then(|nid| { - if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) { - return self.suggest_mut_for_immutable(&field.ty) - .map(|msg| (self.tcx.hir.span(nid), msg)); - } - None - }); - local_def = err.cmt.get_def() - .and_then(|nid| { - if !self.tcx.hir.is_argument(nid) { - Some(self.tcx.hir.span(nid)) - } else { - None - } - }); - format!("cannot borrow {} as mutable", descr) } BorrowViolation(euv::ClosureInvocation) => { @@ -746,16 +725,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut db = self.struct_span_err(span, msg); - if let Some((span, msg)) = immutable_field { - db.span_label(span, &msg); - } - if let Some(let_span) = local_def { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet)); - } - } - db + self.struct_span_err(span, &msg) } pub fn report_aliasability_violation(&self, @@ -788,34 +758,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut err = match cause { - mc::AliasableOther => { - struct_span_err!( - self.tcx.sess, span, E0385, - "{} in an aliasable location", prefix) - } - mc::AliasableReason::UnaliasableImmutable => { - struct_span_err!( - self.tcx.sess, span, E0386, - "{} in an immutable container", prefix) - } - mc::AliasableClosure(id) => { - let mut err = struct_span_err!( - self.tcx.sess, span, E0387, - "{} in a captured outer variable in an `Fn` closure", prefix); - if let BorrowViolation(euv::ClosureCapture(_)) = kind { - // The aliasability violation with closure captures can - // happen for nested closures, so we know the enclosing - // closure incorrectly accepts an `Fn` while it needs to - // be `FnMut`. - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this to accept closures that implement `FnMut`"); - } else { - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this closure to take self by mutable reference"); - } - err - } + match cause { mc::AliasableStatic | mc::AliasableStaticMut => { // This path cannot occur. It happens when we have an @@ -826,17 +769,38 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // ignored. span_bug!(span, "aliasability violation for static `{}`", prefix) } - mc::AliasableBorrowed => { - let mut e = struct_span_err!( + mc::AliasableBorrowed => {} + }; + let blame = cmt.immutability_blame(); + let mut err = match blame { + Some(ImmutabilityBlame::ClosureEnv(id)) => { + let mut err = struct_span_err!( + self.tcx.sess, span, E0387, + "{} in a captured outer variable in an `Fn` closure", prefix); + + // FIXME: the distinction between these 2 messages looks wrong. + let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind { + // The aliasability violation with closure captures can + // happen for nested closures, so we know the enclosing + // closure incorrectly accepts an `Fn` while it needs to + // be `FnMut`. + "consider changing this to accept closures that implement `FnMut`" + + } else { + "consider changing this closure to take self by mutable reference" + }; + err.span_help(self.tcx.hir.span(id), help); + err + } + _ => { + let mut err = struct_span_err!( self.tcx.sess, span, E0389, "{} in a `&` reference", prefix); - e.span_label(span, &"assignment into an immutable reference"); - if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(nid, &mut e); - } - e + err.span_label(span, &"assignment into an immutable reference"); + err } }; + self.note_immutability_blame(&mut err, blame); if is_closure { err.help("closures behind references must be called via `&mut`"); @@ -873,8 +837,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { None } - fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) { - let parent = self.tcx.hir.get_parent_node(nid); + fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode { + let pat = match self.tcx.hir.get(node_id) { + hir_map::Node::NodeLocal(pat) => pat, + node => bug!("bad node for local: {:?}", node) + }; + + match pat.node { + hir::PatKind::Binding(mode, ..) => mode, + _ => bug!("local is not a binding: {:?}", pat) + } + } + + fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> { + let parent = self.tcx.hir.get_parent_node(node_id); let parent_node = self.tcx.hir.get(parent); // The parent node is like a fn @@ -882,12 +858,72 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // `nid`'s parent's `Body` let fn_body = self.tcx.hir.body(fn_like.body()); // Get the position of `nid` in the arguments list - let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid); + let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); if let Some(i) = arg_pos { // The argument's `Ty` - let arg_ty = &fn_like.decl().inputs[i]; - if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) { - db.span_label(arg_ty.span, &msg); + Some(&fn_like.decl().inputs[i]) + } else { + None + } + } else { + None + } + } + + fn note_immutability_blame(&self, + db: &mut DiagnosticBuilder, + blame: Option) { + match blame { + None => {} + Some(ImmutabilityBlame::ClosureEnv(_)) => {} + Some(ImmutabilityBlame::ImmLocal(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { + if self.tcx.hir.name(node_id) == keywords::SelfValue.name() && + snippet != "self" { + // avoid suggesting `mut &self`. + return + } + db.span_label( + let_span, + &format!("consider changing this to `mut {}`", snippet) + ); + } + } + } + Some(ImmutabilityBlame::LocalDeref(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + match self.local_binding_mode(node_id) { + hir::BindingMode::BindByRef(..) => { + let snippet = self.tcx.sess.codemap().span_to_snippet(let_span); + if let Ok(snippet) = snippet { + db.span_label( + let_span, + &format!("consider changing this to `{}`", + snippet.replace("ref ", "ref mut ")) + ); + } + } + hir::BindingMode::BindByValue(..) => { + if let Some(local_ty) = self.local_ty(node_id) { + if let Some(msg) = self.suggest_mut_for_immutable(local_ty) { + db.span_label(local_ty.span, &msg); + } + } + } + } + } + Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => { + let node_id = match self.tcx.hir.as_local_node_id(field.did) { + Some(node_id) => node_id, + None => return + }; + + if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) { + if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) { + db.span_label(field.ty.span, &msg); + } } } } @@ -941,10 +977,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { + fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { let error_span = err.span.clone(); match err.code { - err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), + err_mutbl => { + self.note_and_explain_mutbl_error(db, &err, &error_span); + self.note_immutability_blame(db, err.cmt.immutability_blame()); + } err_out_of_scope(super_scope, sub_scope, cause) => { let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(..) => @@ -1096,13 +1135,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ _ => { if let Categorization::Deref(..) = err.cmt.cat { db.span_label(*error_span, &"cannot borrow as mutable"); - if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(local_id, db); - } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { - if let Categorization::Local(local_id) = inner_cmt.cat { - self.immutable_argument_should_be_mut(local_id, db); - } - } } else if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.hir.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { @@ -1110,14 +1142,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ db.span_label(*error_span, &format!("cannot reborrow mutably")); db.span_label(*error_span, &format!("try removing `&mut` here")); } else { - if snippet.starts_with("ref ") { - db.span_label(span, &format!("use `{}` here to make mutable", - snippet.replace("ref ", "ref mut "))); - } else if snippet != "self" { - db.span_label(span, - &format!("use `mut {}` here to make mutable", - snippet)); - } db.span_label(*error_span, &format!("cannot borrow mutably")); } } else { diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index db4a1701e976..bfd342a9f213 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -198,7 +198,7 @@ fn main() { ``` "##, -E0386: r##" +/*E0386: r##" This error occurs when an attempt is made to mutate the target of a mutable reference stored inside an immutable container. @@ -228,7 +228,7 @@ let x: i64 = 1; let y: Box> = Box::new(Cell::new(x)); y.set(2); ``` -"##, +"##,*/ E0387: r##" This error occurs when an attempt is made to mutate or mutably reference data @@ -1117,6 +1117,6 @@ fn main() { } register_diagnostics! { - E0385, // {} in an aliasable location +// E0385, // {} in an aliasable location E0524, // two closures require unique access to `..` at the same time } diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs index 92a8b10669ce..736aa465aa73 100644 --- a/src/test/compile-fail/augmented-assignments.rs +++ b/src/test/compile-fail/augmented-assignments.rs @@ -27,7 +27,7 @@ fn main() { x; //~ value moved here let y = Int(2); - //~^use `mut y` here to make mutable + //~^ consider changing this to `mut y` y //~ error: cannot borrow immutable local variable `y` as mutable //~| cannot borrow += diff --git a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs index 64033623fe2d..8b7ccedd6974 100644 --- a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs +++ b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs @@ -23,7 +23,7 @@ fn indirect_write_to_imm_box() { let mut x: isize = 1; let y: Box<_> = box &mut x; let p = &y; - ***p = 2; //~ ERROR cannot assign to data in an immutable container + ***p = 2; //~ ERROR cannot assign to data in a `&` reference drop(p); } @@ -43,7 +43,6 @@ fn borrow_in_var_from_var_via_imm_box() { let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -64,7 +63,6 @@ fn borrow_in_var_from_field_via_imm_box() { let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -85,7 +83,6 @@ fn borrow_in_field_from_var_via_imm_box() { let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } @@ -106,7 +103,6 @@ fn borrow_in_field_from_field_via_imm_box() { let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed - //~^ ERROR cannot assign to data in an immutable container drop(p); drop(q); } diff --git a/src/test/compile-fail/issue-33819.rs b/src/test/compile-fail/issue-33819.rs index 9c9677c1e986..499e7e54947b 100644 --- a/src/test/compile-fail/issue-33819.rs +++ b/src/test/compile-fail/issue-33819.rs @@ -12,7 +12,7 @@ fn main() { match op { Some(ref v) => { let a = &mut v; }, //~^ ERROR:cannot borrow immutable - //~| use `ref mut v` here to make mutable + //~| cannot borrow mutably None => {}, } } diff --git a/src/test/compile-fail/mut-suggestion.rs b/src/test/compile-fail/mut-suggestion.rs index 242ad7aee8d1..0015c8e5c00a 100644 --- a/src/test/compile-fail/mut-suggestion.rs +++ b/src/test/compile-fail/mut-suggestion.rs @@ -17,7 +17,7 @@ impl S { } fn func(arg: S) { - //~^ here to make mutable + //~^ consider changing this to `mut arg` arg.mutate(); //~^ ERROR cannot borrow immutable argument //~| cannot borrow mutably @@ -25,7 +25,7 @@ fn func(arg: S) { fn main() { let local = S; - //~^ here to make mutable + //~^ consider changing this to `mut local` local.mutate(); //~^ ERROR cannot borrow immutable local variable //~| cannot borrow mutably diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr index edbfd72df615..7bb69caa1024 100644 --- a/src/test/ui/codemap_tests/huge_multispan_highlight.stderr +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable local variable `x` as mutable --> $DIR/huge_multispan_highlight.rs:100:18 | 12 | let x = "foo"; - | - use `mut x` here to make mutable + | - consider changing this to `mut x` ... 100 | let y = &mut x; | ^ cannot borrow mutably diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr index 4873acf551eb..60fa06d314ff 100644 --- a/src/test/ui/did_you_mean/issue-31424.stderr +++ b/src/test/ui/did_you_mean/issue-31424.stderr @@ -10,6 +10,8 @@ error: cannot borrow immutable argument `self` as mutable error: cannot borrow immutable argument `self` as mutable --> $DIR/issue-31424.rs:23:15 | +22 | fn bar(self: &mut Self) { + | ---- consider changing this to `mut self` 23 | (&mut self).bar(); | ^^^^ cannot borrow mutably diff --git a/src/test/ui/did_you_mean/issue-35937.rs b/src/test/ui/did_you_mean/issue-35937.rs new file mode 100644 index 000000000000..9ec8728fd32c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35937.rs @@ -0,0 +1,31 @@ +// 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. + +struct Foo { + pub v: Vec +} + +fn main() { + let f = Foo { v: Vec::new() }; + f.v.push("cat".to_string()); +} + + +struct S { + x: i32, +} +fn foo() { + let s = S { x: 42 }; + s.x += 1; +} + +fn bar(s: S) { + s.x += 1; +} diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr new file mode 100644 index 000000000000..bea3d1291433 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35937.stderr @@ -0,0 +1,26 @@ +error: cannot borrow immutable field `f.v` as mutable + --> $DIR/issue-35937.rs:17:5 + | +16 | let f = Foo { v: Vec::new() }; + | - consider changing this to `mut f` +17 | f.v.push("cat".to_string()); + | ^^^ cannot mutably borrow immutable field + +error: cannot assign to immutable field `s.x` + --> $DIR/issue-35937.rs:26:5 + | +25 | let s = S { x: 42 }; + | - consider changing this to `mut s` +26 | s.x += 1; + | ^^^^^^^^ cannot mutably borrow immutable field + +error: cannot assign to immutable field `s.x` + --> $DIR/issue-35937.rs:30:5 + | +29 | fn bar(s: S) { + | - consider changing this to `mut s` +30 | s.x += 1; + | ^^^^^^^^ cannot mutably borrow immutable field + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr index fdaf0cd44d9d..855feaf7d2d5 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable --> $DIR/issue-38147-2.rs:17:9 | 12 | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- use `&'a mut String` here to make mutable ... 17 | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr index d2280fa561bd..d970d078df8d 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.stderr @@ -2,10 +2,8 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable --> $DIR/issue-38147-3.rs:17:9 | 12 | s: &'a String - | ------------- use `&'a mut String` here to make mutable + | ---------- use `&'a mut String` here to make mutable ... -16 | fn f(&self) { - | ----- use `&mut self` here to make mutable 17 | self.s.push('x'); | ^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index bcdafefa2472..c98fed3c3c3c 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -8,15 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum X { +pub enum X { Y } -struct Z { +pub struct Z { x: X } -fn main() { +pub fn main() { let z = Z { x: X::Y }; let _ = &mut z.x; } + +pub fn with_arg(z: Z, w: &Z) { + let _ = &mut z.x; + let _ = &mut w.x; +} diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index 7f124e6d34d3..bcd55fd744bb 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -6,5 +6,22 @@ error: cannot borrow immutable field `z.x` as mutable 21 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to previous error +error: cannot borrow immutable field `z.x` as mutable + --> $DIR/issue-39544.rs:25:18 + | +24 | pub fn with_arg(z: Z, w: &Z) { + | - consider changing this to `mut z` +25 | let _ = &mut z.x; + | ^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `w.x` as mutable + --> $DIR/issue-39544.rs:26:18 + | +24 | pub fn with_arg(z: Z, w: &Z) { + | -- use `&mut Z` here to make mutable +25 | let _ = &mut z.x; +26 | let _ = &mut w.x; + | ^^^ cannot mutably borrow immutable field + +error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/issue-40823.rs b/src/test/ui/did_you_mean/issue-40823.rs new file mode 100644 index 000000000000..f4ae32572798 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40823.rs @@ -0,0 +1,14 @@ +// 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() { + let mut buf = &[1, 2, 3, 4]; + buf.iter_mut(); +} diff --git a/src/test/ui/did_you_mean/issue-40823.stderr b/src/test/ui/did_you_mean/issue-40823.stderr new file mode 100644 index 000000000000..8e77ebd9b6da --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40823.stderr @@ -0,0 +1,8 @@ +error: cannot borrow immutable borrowed content `*buf` as mutable + --> $DIR/issue-40823.rs:13:5 + | +13 | buf.iter_mut(); + | ^^^ cannot borrow as mutable + +error: aborting due to previous error + diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index b83a6aaebf32..edf1635a6b84 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24 | 62 | fn deref_mut_field1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 63 | let __isize = &mut x.y; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -28,7 +28,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5 | 97 | fn assign_field1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 98 | x.y = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -54,7 +54,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5 | 118 | fn deref_mut_method1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 119 | x.set(0, 0); //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -70,7 +70,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 | 138 | fn assign_method1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 139 | *x.y_mut() = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr index af954a4d7924..2ec011687217 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25 | 38 | fn deref_mut1(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 39 | let __isize = &mut *x; //~ ERROR cannot borrow | ^ cannot borrow mutably @@ -18,7 +18,7 @@ error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 | 58 | fn assign1<'a>(x: Own) { - | - use `mut x` here to make mutable + | - consider changing this to `mut x` 59 | *x = 3; //~ ERROR cannot borrow | ^ cannot borrow mutably diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr index 4ef1cb9c239e..0abdbdc3a21b 100644 --- a/src/test/ui/span/borrowck-object-mutability.stderr +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -10,6 +10,9 @@ error: cannot borrow immutable borrowed content `*x` as mutable error: cannot borrow immutable `Box` content `*x` as mutable --> $DIR/borrowck-object-mutability.rs:29:5 | +27 | fn owned_receiver(x: Box) { + | - consider changing this to `mut x` +28 | x.borrowed(); 29 | x.borrowed_mut(); //~ ERROR cannot borrow | ^ cannot borrow as mutable From 39011f8590b69d5ee9037c4ac9b863a516ae2e1e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 27 Mar 2017 01:35:50 +0300 Subject: [PATCH 080/905] fix handling of `self` --- src/librustc/hir/lowering.rs | 7 ++ src/librustc/hir/mod.rs | 3 + src/librustc_borrowck/borrowck/mod.rs | 60 ++++++++------- src/test/ui/did_you_mean/issue-39544.rs | 28 ++++++- src/test/ui/did_you_mean/issue-39544.stderr | 85 ++++++++++++++++++--- 5 files changed, 144 insertions(+), 39 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ac1a036f99e..726c305e9030 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -907,6 +907,13 @@ impl<'a> LoweringContext<'a> { FunctionRetTy::Default(span) => hir::DefaultReturn(span), }, variadic: decl.variadic, + has_implicit_self: decl.inputs.get(0).map_or(false, |arg| { + match arg.ty.node { + TyKind::ImplicitSelf => true, + TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf, + _ => false + } + }) }) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 1c79a02d3da0..43b7deb5b90e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1379,6 +1379,9 @@ pub struct FnDecl { pub inputs: HirVec>, pub output: FunctionRetTy, pub variadic: bool, + /// True if this function has an `self`, `&self` or `&mut self` receiver + /// (but not a `self: Xxx` one). + pub has_implicit_self: bool, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0981369ace5c..558a835be188 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -42,7 +42,6 @@ use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; -use syntax::symbol::keywords; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; @@ -809,32 +808,33 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } /// Given a type, if it is an immutable reference, return a suggestion to make it mutable - fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { + fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option { // Check wether the argument is an immutable reference + debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self); if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty }) = pty.node { // Account for existing lifetimes when generating the message - if !lifetime.is_elided() { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { - if let Ok(lifetime_snippet) = self.tcx.sess.codemap() - .span_to_snippet(lifetime.span) { - return Some(format!("use `&{} mut {}` here to make mutable", - lifetime_snippet, - snippet)); - } - } - } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) { - if snippet.starts_with("&") { - return Some(format!("use `{}` here to make mutable", - snippet.replace("&", "&mut "))); - } + let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) { + Ok(snippet) => snippet, + _ => return None + }; + + let lifetime_snippet = if !lifetime.is_elided() { + format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) { + Ok(lifetime_snippet) => lifetime_snippet, + _ => return None + }) } else { - bug!("couldn't find a snippet for span: {:?}", pty.span); - } + String::new() + }; + Some(format!("use `&{}mut {}` here to make mutable", + lifetime_snippet, + if is_implicit_self { "self" } else { &*pointee_snippet })) + } else { + None } - None } fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode { @@ -849,7 +849,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> { + fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) { let parent = self.tcx.hir.get_parent_node(node_id); let parent_node = self.tcx.hir.get(parent); @@ -857,16 +857,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some(fn_like) = FnLikeNode::from_node(parent_node) { // `nid`'s parent's `Body` let fn_body = self.tcx.hir.body(fn_like.body()); - // Get the position of `nid` in the arguments list + // Get the position of `node_id` in the arguments list let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); if let Some(i) = arg_pos { // The argument's `Ty` - Some(&fn_like.decl().inputs[i]) + (Some(&fn_like.decl().inputs[i]), + i == 0 && fn_like.decl().has_implicit_self) } else { - None + (None, false) } } else { - None + (None, false) } } @@ -880,8 +881,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let let_span = self.tcx.hir.span(node_id); if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) { if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - if self.tcx.hir.name(node_id) == keywords::SelfValue.name() && - snippet != "self" { + let (_, is_implicit_self) = self.local_ty(node_id); + if is_implicit_self && snippet != "self" { // avoid suggesting `mut &self`. return } @@ -906,8 +907,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } hir::BindingMode::BindByValue(..) => { - if let Some(local_ty) = self.local_ty(node_id) { - if let Some(msg) = self.suggest_mut_for_immutable(local_ty) { + if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) { + if let Some(msg) = + self.suggest_mut_for_immutable(local_ty, is_implicit_self) { db.span_label(local_ty.span, &msg); } } @@ -921,7 +923,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) { - if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) { + if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) { db.span_label(field.ty.span, &msg); } } diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index c98fed3c3c3c..6331fc5771fc 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -16,11 +16,37 @@ pub struct Z { x: X } -pub fn main() { +fn main() { let z = Z { x: X::Y }; let _ = &mut z.x; } +impl Z { + fn foo<'z>(&'z self) { + let _ = &mut self.x; + } + + fn foo1(&self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo2<'a>(&'a self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo3<'a>(self: &'a Self, other: &Z) { + let _ = &mut self.x; + let _ = &mut other.x; + } + + fn foo4(other: &Z) { + let _ = &mut other.x; + } + +} + pub fn with_arg(z: Z, w: &Z) { let _ = &mut z.x; let _ = &mut w.x; diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index bcd55fd744bb..e1e229a8b057 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -6,22 +6,89 @@ error: cannot borrow immutable field `z.x` as mutable 21 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field -error: cannot borrow immutable field `z.x` as mutable - --> $DIR/issue-39544.rs:25:18 +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:26:22 | -24 | pub fn with_arg(z: Z, w: &Z) { +25 | fn foo<'z>(&'z self) { + | -------- use `&'z mut self` here to make mutable +26 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:30:22 + | +29 | fn foo1(&self, other: &Z) { + | ----- use `&mut self` here to make mutable +30 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:31:22 + | +29 | fn foo1(&self, other: &Z) { + | -- use `&mut Z` here to make mutable +30 | let _ = &mut self.x; +31 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:35:22 + | +34 | fn foo2<'a>(&'a self, other: &Z) { + | -------- use `&'a mut self` here to make mutable +35 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:36:22 + | +34 | fn foo2<'a>(&'a self, other: &Z) { + | -- use `&mut Z` here to make mutable +35 | let _ = &mut self.x; +36 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `self.x` as mutable + --> $DIR/issue-39544.rs:40:22 + | +39 | fn foo3<'a>(self: &'a Self, other: &Z) { + | -------- use `&'a mut Self` here to make mutable +40 | let _ = &mut self.x; + | ^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:41:22 + | +39 | fn foo3<'a>(self: &'a Self, other: &Z) { + | -- use `&mut Z` here to make mutable +40 | let _ = &mut self.x; +41 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `other.x` as mutable + --> $DIR/issue-39544.rs:45:22 + | +44 | fn foo4(other: &Z) { + | -- use `&mut Z` here to make mutable +45 | let _ = &mut other.x; + | ^^^^^^^ cannot mutably borrow immutable field + +error: cannot borrow immutable field `z.x` as mutable + --> $DIR/issue-39544.rs:51:18 + | +50 | pub fn with_arg(z: Z, w: &Z) { | - consider changing this to `mut z` -25 | let _ = &mut z.x; +51 | let _ = &mut z.x; | ^^^ cannot mutably borrow immutable field error: cannot borrow immutable field `w.x` as mutable - --> $DIR/issue-39544.rs:26:18 + --> $DIR/issue-39544.rs:52:18 | -24 | pub fn with_arg(z: Z, w: &Z) { +50 | pub fn with_arg(z: Z, w: &Z) { | -- use `&mut Z` here to make mutable -25 | let _ = &mut z.x; -26 | let _ = &mut w.x; +51 | let _ = &mut z.x; +52 | let _ = &mut w.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to 3 previous errors +error: aborting due to 11 previous errors From 737511ee118b16382bc7eb6a217ea370731f4821 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 27 Mar 2017 05:22:18 +0000 Subject: [PATCH 081/905] Ensure that macro resolutions in trait positions get finalized. --- src/librustc_resolve/lib.rs | 4 ++++ src/librustc_resolve/macros.rs | 5 ++--- src/test/compile-fail/issue-40845.rs | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-40845.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 879d8816488b..0466e76475da 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -922,6 +922,10 @@ impl<'a> ModuleData<'a> { fn is_local(&self) -> bool { self.normal_ancestor_id.is_local() } + + fn nearest_item_scope(&'a self) -> Module<'a> { + if self.is_trait() { self.parent.unwrap() } else { self } + } } impl<'a> fmt::Debug for ModuleData<'a> { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3d6c6896549a..05f30f039c8f 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -172,7 +172,6 @@ impl<'a> base::Resolver for Resolver<'a> { expansion: mark, }; expansion.visit_with(&mut visitor); - self.current_module.unresolved_invocations.borrow_mut().remove(&mark); invocation.expansion.set(visitor.legacy_scope); } @@ -390,7 +389,7 @@ impl<'a> Resolver<'a> { Err(Determinacy::Determined) }, }; - self.current_module.macro_resolutions.borrow_mut() + self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); return def; } @@ -410,7 +409,7 @@ impl<'a> Resolver<'a> { } }; - self.current_module.legacy_macro_resolutions.borrow_mut() + self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() .push((scope, path[0], span, kind)); result diff --git a/src/test/compile-fail/issue-40845.rs b/src/test/compile-fail/issue-40845.rs new file mode 100644 index 000000000000..c5604a0427b2 --- /dev/null +++ b/src/test/compile-fail/issue-40845.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. + +trait T { m!(); } //~ ERROR cannot find macro `m!` in this scope + +struct S; +impl S { m!(); } //~ ERROR cannot find macro `m!` in this scope + +fn main() {} From 79feb9476d9275cb6abac88affdbfd3c922a2805 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Mar 2017 10:10:18 +0100 Subject: [PATCH 082/905] allow `InternedString` to be compared to `str` directly --- src/libsyntax/symbol.rs | 44 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index 6642c60d256b..2acbeee426be 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -72,9 +72,9 @@ impl Decodable for Symbol { } } -impl<'a> PartialEq<&'a str> for Symbol { - fn eq(&self, other: &&str) -> bool { - *self.as_str() == **other +impl> PartialEq for Symbol { + fn eq(&self, other: &T) -> bool { + self.as_str() == other.deref() } } @@ -244,11 +244,47 @@ fn with_interner T>(f: F) -> T { /// destroyed. In particular, they must not access string contents. This can /// be fixed in the future by just leaking all strings until thread death /// somehow. -#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] +#[derive(Clone, Hash, PartialOrd, Eq, Ord)] pub struct InternedString { string: &'static str, } +impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { + fn as_ref(&self) -> &U { + self.string.as_ref() + } +} + +impl> ::std::cmp::PartialEq for InternedString { + fn eq(&self, other: &T) -> bool { + self.string == other.deref() + } +} + +impl ::std::cmp::PartialEq for str { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a str { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + +impl ::std::cmp::PartialEq for String { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a String { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + impl !Send for InternedString { } impl ::std::ops::Deref for InternedString { From eb447f4ef436f0c6211a13de1e6150a09228a9c6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 24 Mar 2017 09:31:26 +0100 Subject: [PATCH 083/905] Fix various useless derefs and slicings --- src/bootstrap/check.rs | 2 +- src/grammar/verify.rs | 6 ++--- src/libcollections/linked_list.rs | 2 +- src/libgraphviz/lib.rs | 6 ++--- src/librustc/ich/fingerprint.rs | 4 ++-- src/librustc/lint/context.rs | 5 ++-- src/librustc/middle/stability.rs | 2 +- src/librustc_borrowck/borrowck/fragments.rs | 24 +++++++++---------- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_borrowck/graphviz.rs | 2 +- src/librustc_const_eval/_match.rs | 4 ++-- src/librustc_const_eval/check_match.rs | 2 +- .../accumulate_vec.rs | 8 +++---- src/librustc_data_structures/base_n.rs | 2 +- src/librustc_data_structures/blake2b.rs | 2 +- src/librustc_data_structures/indexed_set.rs | 8 +++---- src/librustc_driver/lib.rs | 10 ++++---- src/librustc_driver/pretty.rs | 6 ++--- src/librustc_driver/test.rs | 2 +- .../persist/file_format.rs | 4 ++-- src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 2 +- src/librustc_llvm/build.rs | 4 ++-- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/encoder.rs | 4 ++-- src/librustc_metadata/locator.rs | 6 ++--- src/librustc_plugin/load.rs | 6 ++--- src/librustc_save_analysis/csv_dumper.rs | 2 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/adt.rs | 8 +++---- src/librustc_trans/asm.rs | 4 ++-- src/librustc_trans/back/archive.rs | 4 ++-- src/librustc_trans/back/link.rs | 14 +++++------ src/librustc_trans/back/lto.rs | 4 ++-- src/librustc_trans/back/rpath.rs | 14 +++++------ src/librustc_trans/back/symbol_export.rs | 4 ++-- src/librustc_trans/back/symbol_names.rs | 2 +- src/librustc_trans/back/write.rs | 12 +++++----- src/librustc_trans/base.rs | 12 +++++----- src/librustc_trans/builder.rs | 6 ++--- src/librustdoc/html/render.rs | 4 ++-- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/feature_gate.rs | 9 ++++--- src/libsyntax/parse/parser.rs | 6 ++--- src/libsyntax/test.rs | 2 +- 46 files changed, 120 insertions(+), 122 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 40cdb9242df1..f8f641060c44 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -586,7 +586,7 @@ fn android_copy_libs(build: &Build, compiler: &Compiler, target: &str) { .arg(ADB_TEST_DIR)); let target_dir = format!("{}/{}", ADB_TEST_DIR, target); - build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir[..]])); + build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir])); for f in t!(build.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 919fc98e438c..bd28a63c5f4d 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -196,7 +196,7 @@ fn parse_antlr_token(s: &str, tokens: &HashMap, surrogate_ let toknum = &s[content_end + 3 .. toknum_end]; let not_found = format!("didn't find token {:?} in the map", toknum); - let proto_tok = tokens.get(toknum).expect(¬_found[..]); + let proto_tok = tokens.get(toknum).expect(¬_found); let nm = Symbol::intern(content); @@ -304,14 +304,14 @@ fn main() { let mut token_file = File::open(&Path::new(&args.next().unwrap())).unwrap(); let mut token_list = String::new(); token_file.read_to_string(&mut token_list).unwrap(); - let token_map = parse_token_list(&token_list[..]); + let token_map = parse_token_list(&token_list); let stdin = std::io::stdin(); let lock = stdin.lock(); let lines = lock.lines(); let antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().trim(), &token_map, - &surrogate_pairs_pos[..], + &surrogate_pairs_pos, has_bom)); for antlr_tok in antlr_tokens { diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index f58c87b801f5..8f0488f69369 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -1376,7 +1376,7 @@ mod tests { thread::spawn(move || { check_links(&n); let a: &[_] = &[&1, &2, &3]; - assert_eq!(a, &n.iter().collect::>()[..]); + assert_eq!(a, &*n.iter().collect::>()); }) .join() .ok() diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 8e587ad211de..1b2c7775185f 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -554,7 +554,7 @@ impl<'a> LabelText<'a> { pub fn to_dot_string(&self) -> String { match self { &LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s[..])), + &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), &HtmlStr(ref s) => format!("<{}>", s), } } @@ -587,7 +587,7 @@ impl<'a> LabelText<'a> { let mut prefix = self.pre_escaped_content().into_owned(); let suffix = suffix.pre_escaped_content(); prefix.push_str(r"\n\n"); - prefix.push_str(&suffix[..]); + prefix.push_str(&suffix); EscStr(prefix.into_cow()) } } @@ -878,7 +878,7 @@ mod tests { type Node = Node; type Edge = &'a Edge; fn graph_id(&'a self) -> Id<'a> { - Id::new(&self.name[..]).unwrap() + Id::new(self.name).unwrap() } fn node_id(&'a self, n: &Node) -> Id<'a> { id_name(n) diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index d296d8293fb0..e760f7efc93d 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -55,7 +55,7 @@ impl Fingerprint { impl Encodable for Fingerprint { #[inline] fn encode(&self, s: &mut S) -> Result<(), S::Error> { - for &byte in &self.0[..] { + for &byte in &self.0 { s.emit_u8(byte)?; } Ok(()) @@ -66,7 +66,7 @@ impl Decodable for Fingerprint { #[inline] fn decode(d: &mut D) -> Result { let mut result = Fingerprint([0u8; FINGERPRINT_LENGTH]); - for byte in &mut result.0[..] { + for byte in &mut result.0 { *byte = d.read_u8()?; } Ok(result) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index d35f965e2ffd..20bf241a9990 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -40,7 +40,6 @@ use std::cmp; use std::default::Default as StdDefault; use std::mem; use std::fmt; -use std::ops::Deref; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; @@ -485,7 +484,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, Allow => bug!("earlier conditional return should handle Allow case") }; let hyphen_case_lint_name = name.replace("_", "-"); - if lint_flag_val.as_str().deref() == name { + if lint_flag_val.as_str() == name { err.note(&format!("requested on the command line with `{} {}`", flag, hyphen_case_lint_name)); } else { @@ -496,7 +495,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, }, Node(lint_attr_name, src) => { def = Some(src); - if lint_attr_name.as_str().deref() != name { + if lint_attr_name.as_str() != name { let level_str = level.as_str(); err.note(&format!("#[{}({})] implied by #[{}({})]", level_str, name, level_str, lint_attr_name)); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4115b4669f4b..4354ed6817ae 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -536,7 +536,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if !self.stability.borrow().active_features.contains(feature) { let msg = match *reason { Some(ref r) => format!("use of unstable library feature '{}': {}", - &feature.as_str(), &r), + feature.as_str(), &r), None => format!("use of unstable library feature '{}'", &feature) }; emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index c0f681680a96..b728d4d53451 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -267,11 +267,11 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx // First, filter out duplicates moved.sort(); moved.dedup(); - debug!("fragments 1 moved: {:?}", path_lps(&moved[..])); + debug!("fragments 1 moved: {:?}", path_lps(&moved)); assigned.sort(); assigned.dedup(); - debug!("fragments 1 assigned: {:?}", path_lps(&assigned[..])); + debug!("fragments 1 assigned: {:?}", path_lps(&assigned)); // Second, build parents from the moved and assigned. for m in &moved { @@ -291,14 +291,14 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx parents.sort(); parents.dedup(); - debug!("fragments 2 parents: {:?}", path_lps(&parents[..])); + debug!("fragments 2 parents: {:?}", path_lps(&parents)); // Third, filter the moved and assigned fragments down to just the non-parents - moved.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 moved: {:?}", path_lps(&moved[..])); + moved.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 moved: {:?}", path_lps(&moved)); - assigned.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 assigned: {:?}", path_lps(&assigned[..])); + assigned.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 assigned: {:?}", path_lps(&assigned)); // Fourth, build the leftover from the moved, assigned, and parents. for m in &moved { @@ -316,16 +316,16 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx unmoved.sort(); unmoved.dedup(); - debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved)); // Fifth, filter the leftover fragments down to its core. unmoved.retain(|f| match *f { AllButOneFrom(_) => true, - Just(mpi) => non_member(mpi, &parents[..]) && - non_member(mpi, &moved[..]) && - non_member(mpi, &assigned[..]) + Just(mpi) => non_member(mpi, &parents) && + non_member(mpi, &moved) && + non_member(mpi, &assigned) }); - debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved)); // Swap contents back in. fragments.unmoved_fragments = unmoved; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 20d495976b05..59c3e68aadab 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -112,7 +112,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { &flowed_moves.move_data, owner_id); - check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index 0da9525efd85..e3a2bfa39273 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -88,7 +88,7 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { set.push_str(", "); } let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp); - set.push_str(&loan_str[..]); + set.push_str(&loan_str); saw_some = true; true }); diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 53a7e8729281..c1dc5f5f7a2b 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -680,10 +680,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( }).collect(); let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect(); let matrix = Matrix(m.iter().flat_map(|r| { - specialize(cx, &r[..], &ctor, &wild_patterns) + specialize(cx, &r, &ctor, &wild_patterns) }).collect()); match specialize(cx, v, &ctor, &wild_patterns) { - Some(v) => match is_useful(cx, &matrix, &v[..], witness) { + Some(v) => match is_useful(cx, &matrix, &v, witness) { UsefulWithWitness(witnesses) => UsefulWithWitness( witnesses.into_iter() .map(|witness| witness.apply_constructor(cx, &ctor, lty)) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e2b9f174ff0c..9d55281d019d 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -311,7 +311,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, for &(pat, hir_pat) in pats { let v = vec![pat]; - match is_useful(cx, &seen, &v[..], LeaveOutWitness) { + match is_useful(cx, &seen, &v, LeaveOutWitness) { NotUseful => { match source { hir::MatchSource::IfLetDesugar { .. } => { diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index d4bd9e707fdc..c03c2890ba34 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -91,8 +91,8 @@ impl Deref for AccumulateVec { type Target = [A::Element]; fn deref(&self) -> &Self::Target { match *self { - AccumulateVec::Array(ref v) => &v[..], - AccumulateVec::Heap(ref v) => &v[..], + AccumulateVec::Array(ref v) => v, + AccumulateVec::Heap(ref v) => v, } } } @@ -100,8 +100,8 @@ impl Deref for AccumulateVec { impl DerefMut for AccumulateVec { fn deref_mut(&mut self) -> &mut [A::Element] { match *self { - AccumulateVec::Array(ref mut v) => &mut v[..], - AccumulateVec::Heap(ref mut v) => &mut v[..], + AccumulateVec::Array(ref mut v) => v, + AccumulateVec::Heap(ref mut v) => v, } } } diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs index 4359581a897f..cf54229fa7f5 100644 --- a/src/librustc_data_structures/base_n.rs +++ b/src/librustc_data_structures/base_n.rs @@ -48,7 +48,7 @@ pub fn encode(n: u64, base: u64) -> String { #[test] fn test_encode() { fn test(n: u64, base: u64) { - assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base)[..], base as u32)); + assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base), base as u32)); } for base in 2..37 { diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index 31492e262194..9d97a83f693c 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -35,7 +35,7 @@ pub struct Blake2bCtx { impl ::std::fmt::Debug for Blake2bCtx { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { try!(write!(fmt, "hash: ")); - for v in &self.h[..] { + for v in &self.h { try!(write!(fmt, "{:x}", v)); } Ok(()) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 2e9e054e97ea..572ce98d3ae8 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -91,13 +91,13 @@ impl IdxSet { impl Deref for IdxSetBuf { type Target = IdxSet; fn deref(&self) -> &IdxSet { - unsafe { IdxSet::from_slice(&self.bits[..]) } + unsafe { IdxSet::from_slice(&self.bits) } } } impl DerefMut for IdxSetBuf { fn deref_mut(&mut self) -> &mut IdxSet { - unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) } + unsafe { IdxSet::from_slice_mut(&mut self.bits) } } } @@ -135,11 +135,11 @@ impl IdxSet { } pub fn words(&self) -> &[Word] { - &self.bits[..] + &self.bits } pub fn words_mut(&mut self) -> &mut [Word] { - &mut self.bits[..] + &mut self.bits } pub fn clone_from(&mut self, other: &IdxSet) { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 68b9f85721ad..e11118901d28 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -233,7 +233,7 @@ fn make_output(matches: &getopts::Matches) -> (Option, Option) // Extract input (string or file and optional path) from matches. fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { if free_matches.len() == 1 { - let ifile = &free_matches[0][..]; + let ifile = &free_matches[0]; if ifile == "-" { let mut src = String::new(); io::stdin().read_to_string(&mut src).unwrap(); @@ -800,7 +800,7 @@ Available lint options: for lint in lints { let name = lint.name_lower().replace("_", "-"); println!(" {} {:7.7} {}", - padded(&name[..]), + padded(&name), lint.default_level.as_str(), lint.desc); } @@ -838,7 +838,7 @@ Available lint options: .map(|x| x.to_string().replace("_", "-")) .collect::>() .join(", "); - println!(" {} {}", padded(&name[..]), desc); + println!(" {} {}", padded(&name), desc); } println!("\n"); }; @@ -945,7 +945,7 @@ pub fn handle_options(args: &[String]) -> Option { .into_iter() .map(|x| x.opt_group) .collect(); - let matches = match getopts::getopts(&args[..], &all_groups) { + let matches = match getopts::getopts(&args, &all_groups) { Ok(m) => m, Err(f) => early_error(ErrorOutputType::default(), &f.to_string()), }; @@ -1084,7 +1084,7 @@ pub fn monitor(f: F) { format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; for note in &xs { handler.emit(&MultiSpan::new(), - ¬e[..], + ¬e, errors::Level::Note); } if match env::var_os("RUST_BACKTRACE") { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 6cd97e955988..18dc504ca8aa 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -589,7 +589,7 @@ impl UserIdentifiedItem { -> NodesMatchingUII<'a, 'hir> { match *self { ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), - ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts[..])), + ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), } } @@ -600,7 +600,7 @@ impl UserIdentifiedItem { user_option, self.reconstructed_input(), is_wrong_because); - sess.fatal(&message[..]) + sess.fatal(&message) }; let mut saw_node = ast::DUMMY_NODE_ID; @@ -771,7 +771,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, fn expand_err_details(r: io::Result<()>) -> io::Result<()> { r.map_err(|ioerr| { io::Error::new(io::ErrorKind::Other, - &format!("graphviz::render failed: {}", ioerr)[..]) + format!("graphviz::render failed: {}", ioerr)) }) } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 9568cc3d6de0..af2416f787ea 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name[..])) + self.infcx.tcx.mk_param(index, Symbol::intern(&name)) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> &'tcx ty::Region { diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index b67caa6750a8..5c20f65274f5 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -99,9 +99,9 @@ pub fn read_file(sess: &Session, path: &Path) -> io::Result>> { let rustc_version_str_len = rustc_version_str_len[0] as usize; let mut buffer = Vec::with_capacity(rustc_version_str_len); buffer.resize(rustc_version_str_len, 0); - file.read_exact(&mut buffer[..])?; + file.read_exact(&mut buffer)?; - if &buffer[..] != rustc_version().as_bytes() { + if buffer != rustc_version().as_bytes() { report_format_mismatch(sess, path, "Different compiler version"); return Ok(None); } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 353b86820c40..c4220e9a0d3d 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -88,7 +88,7 @@ impl NonCamelCaseTypes { } else { format!("{} `{}` should have a camel case name such as `{}`", sort, name, c) }; - cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); + cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m); } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f0276f90f274..0ee9d4a42c7f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -334,7 +334,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { attr.check_name("doc") && match attr.meta_item_list() { None => false, - Some(l) => attr::list_contains_name(&l[..], "hidden"), + Some(l) => attr::list_contains_name(&l, "hidden"), } }); self.doc_hidden_stack.push(doc_hidden); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index abba8afd9da8..86bf209ccf8c 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty::TyBool => return, ty::TyAdt(def, _) => { let attrs = cx.tcx.get_attrs(def.did); - check_must_use(cx, &attrs[..], s.span) + check_must_use(cx, &attrs, s.span) } _ => false, }; diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 42717ec289c3..2b945e0a3afa 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -140,7 +140,7 @@ fn main() { cfg.flag(flag); } - for component in &components[..] { + for component in &components { let mut flag = String::from("-DLLVM_COMPONENT_"); flag.push_str(&component.to_uppercase()); cfg.flag(&flag); @@ -173,7 +173,7 @@ fn main() { if !is_crossed { cmd.arg("--system-libs"); } - cmd.args(&components[..]); + cmd.args(&components); for lib in output(&mut cmd).split_whitespace() { let name = if lib.starts_with("-l") { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index e1255110a83d..04a8b88f8a59 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -669,7 +669,7 @@ impl<'a> CrateLoader<'a> { name, config::host_triple(), self.sess.opts.target_triple); - span_fatal!(self.sess, span, E0456, "{}", &message[..]); + span_fatal!(self.sess, span, E0456, "{}", &message); } let root = ekrate.metadata.get_root(); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a324c166e738..1370d69f9046 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -918,14 +918,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { self.encode_fields(def_id); } hir::ItemImpl(..) => { - for &trait_item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { + for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(trait_item_def_id, EncodeContext::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { - for &item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { + for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(item_def_id, EncodeContext::encode_info_for_trait_item, item_def_id); diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index a6771083fc34..e8bc8b01652a 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -477,15 +477,15 @@ impl<'a> Context<'a> { Some(file) => file, }; let (hash, found_kind) = - if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") { + if file.starts_with(&rlib_prefix) && file.ends_with(".rlib") { (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib) - } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") { + } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") { (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta) } else if file.starts_with(&dylib_prefix) && file.ends_with(&dypair.1) { (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib) } else { - if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) { + if file.starts_with(&staticlib_prefix) && file.ends_with(&staticpair.1) { staticlibs.push(CrateMismatch { path: path.to_path_buf(), got: "static".to_string(), diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 1bfc445fca98..efe9963cecc7 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -126,19 +126,19 @@ impl<'a> PluginLoader<'a> { // inside this crate, so continue would spew "macro undefined" // errors Err(err) => { - self.sess.span_fatal(span, &err[..]) + self.sess.span_fatal(span, &err) } }; unsafe { let registrar = - match lib.symbol(&symbol[..]) { + match lib.symbol(&symbol) { Ok(registrar) => { mem::transmute::<*mut u8,PluginRegistrarFun>(registrar) } // again fatal if we can't register macros Err(err) => { - self.sess.span_fatal(span, &err[..]) + self.sess.span_fatal(span, &err) } }; diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index 59340ae87ee5..4bab135ff12f 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -423,7 +423,7 @@ fn make_values_str(pairs: &[(&'static str, &str)]) -> String { let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v)))); strs.fold(String::new(), |mut s, ss| { - s.push_str(&ss[..]); + s.push_str(&ss); s }) } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 27a19d211c29..1530708b4b88 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -369,7 +369,7 @@ impl FnType { match sig.inputs().last().unwrap().sty { ty::TyTuple(ref tupled_arguments, _) => { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - &tupled_arguments[..] + &tupled_arguments } _ => { bug!("argument to function with \"rust-call\" ABI \ diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 058f37f62dd8..5c1ced573402 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -229,11 +229,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, variant_fill].iter().cloned().collect(); match name { None => { - Type::struct_(cx, &fields[..], false) + Type::struct_(cx, &fields, false) } Some(name) => { let mut llty = Type::named_struct(cx, name); - llty.set_struct_body(&fields[..], false); + llty.set_struct_body(&fields, false); llty } } @@ -330,7 +330,7 @@ fn struct_wrapped_nullable_bitdiscr( alignment: Alignment, ) -> ValueRef { let llptrptr = bcx.gepi(scrutinee, - &discrfield.iter().map(|f| *f as usize).collect::>()[..]); + &discrfield.iter().map(|f| *f as usize).collect::>()); let llptr = bcx.load(llptrptr, alignment.to_align()); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; bcx.icmp(cmp, llptr, C_null(val_ty(llptr))) @@ -402,7 +402,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu base::call_memset(bcx, llptr, fill_byte, size, align, false); } else { let path = discrfield.iter().map(|&i| i as usize).collect::>(); - let llptrptr = bcx.gepi(val, &path[..]); + let llptrptr = bcx.gepi(val, &path); let llptrty = val_ty(llptrptr).element_type(); bcx.store(C_null(llptrty), llptrptr, None); } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 12e4e57964f9..b6195765b27c 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -77,14 +77,14 @@ pub fn trans_inline_asm<'a, 'tcx>( .chain(arch_clobbers.iter().map(|s| s.to_string())) .collect::>().join(","); - debug!("Asm Constraints: {}", &all_constraints[..]); + 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(bcx.ccx), 1 => output_types[0], - _ => Type::struct_(bcx.ccx, &output_types[..], false) + _ => Type::struct_(bcx.ccx, &output_types, false) }; let dialect = match ia.dialect { diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 11ab6dcaa87f..0f908b7d0698 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -65,10 +65,10 @@ pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) for path in search_paths { debug!("looking for {} inside {:?}", name, path); - let test = path.join(&oslibname[..]); + let test = path.join(&oslibname); if test.exists() { return test } if oslibname != unixlibname { - let test = path.join(&unixlibname[..]); + let test = path.join(&unixlibname); if test.exists() { return test } } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index cf1e10b317b1..6d17b2f0eeda 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -91,7 +91,7 @@ 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); + cstore::validate_crate_name(sess, &s, span); s }; @@ -109,7 +109,7 @@ pub fn find_crate_name(sess: Option<&Session>, let msg = format!("--crate-name and #[crate_name] are \ required to match, but `{}` != `{}`", s, name); - sess.span_err(attr.span, &msg[..]); + sess.span_err(attr.span, &msg); } } return validate(s.clone(), None); @@ -417,7 +417,7 @@ fn object_filenames(trans: &CrateTranslation, outputs: &OutputFilenames) -> Vec { trans.modules.iter().map(|module| { - outputs.temp_path(OutputType::Object, Some(&module.name[..])) + outputs.temp_path(OutputType::Object, Some(&module.name)) }).collect() } @@ -551,7 +551,7 @@ fn link_rlib<'a>(sess: &'a Session, e)) } - let bc_data_deflated = flate::deflate_bytes(&bc_data[..]); + let bc_data_deflated = flate::deflate_bytes(&bc_data); let mut bc_file_deflated = match fs::File::create(&bc_deflated_filename) { Ok(file) => file, @@ -819,12 +819,12 @@ fn link_natively(sess: &Session, pname, prog.status)) .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output[..])) + .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[..])); + info!("linker stderr:\n{}", escape_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_string(&prog.stdout)); }, Err(e) => { sess.struct_err(&format!("could not exec the linker `{}`: {}", pname, e)) diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 0ef3f351a2a4..e23ddd2542a8 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -61,7 +61,7 @@ pub fn run(sess: &session::Session, } let export_threshold = - symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + symbol_export::crates_export_threshold(&sess.crate_types.borrow()); let symbol_filter = &|&(ref name, level): &(String, _)| { if symbol_export::is_below_threshold(level, export_threshold) { @@ -147,7 +147,7 @@ pub fn run(sess: &session::Session, bc_decoded.len() as libc::size_t) { write::llvm_err(sess.diagnostic(), format!("failed to load bc of `{}`", - &name[..])); + name)); } }); } diff --git a/src/librustc_trans/back/rpath.rs b/src/librustc_trans/back/rpath.rs index 9c982be3fa03..104e7bc6a52b 100644 --- a/src/librustc_trans/back/rpath.rs +++ b/src/librustc_trans/back/rpath.rs @@ -37,8 +37,8 @@ pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { let libs = config.used_crates.clone(); let libs = libs.into_iter().filter_map(|(_, l)| l.option()).collect::>(); - let rpaths = get_rpaths(config, &libs[..]); - flags.extend_from_slice(&rpaths_to_flags(&rpaths[..])); + 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 { @@ -84,14 +84,14 @@ fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec { } } - log_rpaths("relative", &rel_rpaths[..]); - log_rpaths("fallback", &fallback_rpaths[..]); + log_rpaths("relative", &rel_rpaths); + log_rpaths("fallback", &fallback_rpaths); let mut rpaths = rel_rpaths; - rpaths.extend_from_slice(&fallback_rpaths[..]); + rpaths.extend_from_slice(&fallback_rpaths); // Remove duplicates - let rpaths = minimize_rpaths(&rpaths[..]); + let rpaths = minimize_rpaths(&rpaths); return rpaths; } @@ -177,7 +177,7 @@ fn minimize_rpaths(rpaths: &[String]) -> Vec { let mut set = HashSet::new(); let mut minimized = Vec::new(); for rpath in rpaths { - if set.insert(&rpath[..]) { + if set.insert(rpath) { minimized.push(rpath.clone()); } } diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 005fb3533ab0..23a67ef5046e 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -154,7 +154,7 @@ impl ExportedSymbols { cnum: CrateNum) -> &[(String, SymbolExportLevel)] { match self.exports.get(&cnum) { - Some(exports) => &exports[..], + Some(exports) => exports, None => &[] } } @@ -167,7 +167,7 @@ impl ExportedSymbols { { for &(ref name, export_level) in self.exported_symbols(cnum) { if is_below_threshold(export_level, export_threshold) { - f(&name[..], export_level) + f(&name, export_level) } } } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 518995dfedcc..3ad04e10cb02 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -341,7 +341,7 @@ pub fn sanitize(s: &str) -> String { if !result.is_empty() && result.as_bytes()[0] != '_' as u8 && ! (result.as_bytes()[0] as char).is_xid_start() { - return format!("_{}", &result[..]); + return format!("_{}", result); } return result; diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 377ff34cb7e0..5a017e4fb8a9 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -105,7 +105,7 @@ impl SharedEmitter { Some(ref code) => { handler.emit_with_code(&MultiSpan::new(), &diag.msg, - &code[..], + &code, diag.lvl); }, None => { @@ -189,8 +189,8 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { let fdata_sections = ffunction_sections; let code_model_arg = match sess.opts.cg.code_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.code_model[..], + Some(ref s) => &s, + None => &sess.target.target.options.code_model, }; let code_model = match CODE_GEN_MODEL_ARGS.iter().find( @@ -397,7 +397,7 @@ unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) .expect("non-UTF8 SMDiagnostic"); - report_inline_asm(cgcx, &msg[..], cookie); + report_inline_asm(cgcx, &msg, cookie); } unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { @@ -823,7 +823,7 @@ pub fn run_passes(sess: &Session, if trans.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(&(trans.modules[0].name)[..]); + let module_name = Some(&trans.modules[0].name[..]); let path = crate_output.temp_path(output_type, module_name); copy_gracefully(&path, &crate_output.path(output_type)); @@ -939,7 +939,7 @@ pub fn run_passes(sess: &Session, if metadata_config.emit_bc && !user_wants_bitcode { let path = crate_output.temp_path(OutputType::Bitcode, - Some(&trans.metadata_module.name[..])); + Some(&trans.metadata_module.name)); remove(sess, &path); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f7ca468fddae..ec45c5593632 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -514,7 +514,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>, n_bytes: ValueRef, align: u32) { let ccx = b.ccx; - let ptr_width = &ccx.sess().target.target.target_pointer_width[..]; + let ptr_width = &ccx.sess().target.target.target_pointer_width; let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); let memcpy = ccx.get_intrinsic(&key); let src_ptr = b.pointercast(src, Type::i8p(ccx)); @@ -550,7 +550,7 @@ pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>, size: ValueRef, align: ValueRef, volatile: bool) -> ValueRef { - let ptr_width = &b.ccx.sess().target.target.target_pointer_width[..]; + let ptr_width = &b.ccx.sess().target.target.target_pointer_width; let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); let llintrinsicfn = b.ccx.get_intrinsic(&intrinsic_key); let volatile = C_bool(b.ccx, volatile); @@ -765,7 +765,7 @@ fn write_metadata(cx: &SharedCrateContext, let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); - let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]); + let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); let name = cx.metadata_symbol_name(); let buf = CString::new(name).unwrap(); @@ -796,7 +796,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, symbol_map: &SymbolMap<'tcx>, exported_symbols: &ExportedSymbols) { let export_threshold = - symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + symbol_export::crates_export_threshold(&sess.crate_types.borrow()); let exported_symbols = exported_symbols .exported_symbols(LOCAL_CRATE) @@ -1035,7 +1035,7 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated // with "internal" linkage and are never exported. - !attr::requests_inline(&attributes[..]) + !attr::requests_inline(&attributes) } _ => false @@ -1574,7 +1574,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a cgus.dedup(); for &(ref cgu_name, linkage) in cgus.iter() { output.push_str(" "); - output.push_str(&cgu_name[..]); + output.push_str(&cgu_name); let linkage_abbrev = match linkage { llvm::Linkage::ExternalLinkage => "External", diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index a62f07042a70..8b1010d89fd9 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -627,7 +627,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { let v = ixs.iter().map(|i| C_i32(self.ccx, *i as i32)).collect::>(); self.count_insn("gepi"); - self.inbounds_gep(base, &v[..]) + self.inbounds_gep(base, &v) } } @@ -835,8 +835,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let s = format!("{} ({})", text, self.ccx.sess().codemap().span_to_string(sp)); - debug!("{}", &s[..]); - self.add_comment(&s[..]); + debug!("{}", s); + self.add_comment(&s); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5c94032c6b9c..612e765a499b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2611,7 +2611,7 @@ fn render_attribute(attr: &ast::MetaItem) -> Option { if attr.is_word() { Some(format!("{}", name)) } else if let Some(v) = attr.value_str() { - Some(format!("{} = {:?}", name, &v.as_str()[..])) + Some(format!("{} = {:?}", name, v.as_str())) } else if let Some(values) = attr.meta_item_list() { let display: Vec<_> = values.iter().filter_map(|attr| { attr.meta_item().and_then(|mi| render_attribute(mi)) @@ -2642,7 +2642,7 @@ fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { for attr in &it.attrs.other_attrs { let name = attr.name().unwrap(); - if !ATTRIBUTE_WHITELIST.contains(&&name.as_str()[..]) { + if !ATTRIBUTE_WHITELIST.contains(&&*name.as_str()) { continue; } if let Some(s) = render_attribute(&attr.meta().unwrap()) { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 021c5398a420..66f5520b8826 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -119,7 +119,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, }; let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false); p.root_module_name = cx.current_expansion.module.mod_path.last() - .map(|id| (*id.name.as_str()).to_owned()); + .map(|id| id.name.as_str().to_string()); p.check_unknown_macro_variable(); // Let the context choose how to interpret the result. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7af432176cf6..9d280a413e66 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -818,7 +818,7 @@ pub struct GatedCfg { impl GatedCfg { pub fn gate(cfg: &ast::MetaItem) -> Option { - let name = &*cfg.name().as_str(); + let name = cfg.name().as_str(); GATED_CFGS.iter() .position(|info| info.0 == name) .map(|idx| { @@ -865,8 +865,7 @@ macro_rules! gate_feature { impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); - let name = unwrap_or!(attr.name(), return); - + let name = unwrap_or!(attr.name(), return).as_str(); for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { if name == n { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { @@ -885,12 +884,12 @@ impl<'a> Context<'a> { return; } } - if name.as_str().starts_with("rustc_") { + if name.starts_with("rustc_") { gate_feature!(self, rustc_attrs, attr.span, "unless otherwise specified, attributes \ with the prefix `rustc_` \ are reserved for internal compiler diagnostics"); - } else if name.as_str().starts_with("derive_") { + } else if name.starts_with("derive_") { gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); } else if !attr::is_known(attr) { // Only run the custom attribute lint during regular diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 649e90599345..43a9d8c5f787 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5151,15 +5151,15 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { - self.directory.path.push(&*path.as_str()); + self.directory.path.push(&path.as_str()); self.directory.ownership = DirectoryOwnership::Owned; } else { - self.directory.path.push(&*id.name.as_str()); + self.directory.path.push(&id.name.as_str()); } } pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option { - attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str())) + attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&d.as_str())) } /// Returns either a path to a module, or . diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e052d2cda3a4..6fb6db9ca028 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -616,7 +616,7 @@ fn mk_tests(cx: &TestCtxt) -> P { fn is_test_crate(krate: &ast::Crate) -> bool { match attr::find_crate_name(&krate.attrs) { - Some(s) if "test" == &*s.as_str() => true, + Some(s) if "test" == s.as_str() => true, _ => false } } From 3545fb512eacc18f4ef62aa91916b45bf9097497 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 27 Mar 2017 12:55:57 +0100 Subject: [PATCH 084/905] rustbuild: Fix compiler docs again The docs need to be built with the rustbuild feature so the correct stability attributes (rustc_private) get applied. --- src/bootstrap/bin/rustdoc.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index e9ca430f1582..3a1a9c3e40d6 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -40,6 +40,14 @@ fn main() { .arg(sysroot) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + + // Pass the `rustbuild` feature flag to crates which rustbuild is + // building. See the comment in bootstrap/lib.rs where this env var is + // set for more details. + if env::var_os("RUSTBUILD_UNSTABLE").is_some() { + cmd.arg("--cfg").arg("rustbuild"); + } + std::process::exit(match cmd.status() { Ok(s) => s.code().unwrap_or(1), Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), From c80868e3b348f00d316ca411f9f3f2f3feb7e6a9 Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Mon, 27 Mar 2017 16:17:08 +0200 Subject: [PATCH 085/905] correcting another mistake in an example copy_pointer -> copy_borrowed_ptr --- src/librustc_borrowck/borrowck/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index 29b007a7499c..034b7cbadd9c 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -633,7 +633,7 @@ Here is a concrete example of a bug this rule prevents: ```rust // Test region-reborrow-from-shorter-mut-ref.rs: -fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { +fn copy_borrowed_ptr<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { &mut **p // ERROR due to clause (1) } fn main() { From 99a069eec9a1ad8f4b4dd592d062f948e9b99540 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 27 Mar 2017 15:21:04 +0100 Subject: [PATCH 086/905] Fix broken Markdown and bad links in the error index This makes sure RFC links point to the RFC text not the pull request. --- src/librustc/diagnostics.rs | 5 +++-- src/librustc_resolve/diagnostics.rs | 6 ++++- src/librustc_typeck/diagnostics.rs | 34 ++++++++++++++++------------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 85b4ddcdd719..5a0fbf8efb70 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1336,7 +1336,7 @@ trait SecondTrait : FirstTrait { E0398: r##" In Rust 1.3, the default object lifetime bounds are expected to change, as -described in RFC #1156 [1]. You are getting a warning because the compiler +described in [RFC 1156]. You are getting a warning because the compiler thinks it is possible that this change will cause a compilation error in your code. It is possible, though unlikely, that this is a false alarm. @@ -1365,7 +1365,7 @@ fn foo<'a>(arg: &Box) { ... } This explicitly states that you expect the trait object `SomeTrait` to contain references (with a maximum lifetime of `'a`). -[1]: https://github.com/rust-lang/rfcs/pull/1156 +[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md "##, E0452: r##" @@ -1771,6 +1771,7 @@ This pattern is incorrect because, because the type of `foo` is a function **item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`) is a function pointer, which is not zero-sized. This pattern should be rewritten. There are a few possible ways to do this: + - change the original fn declaration to match the expected signature, and do the cast in the fn body (the prefered option) - cast the fn item fo a fn pointer before calling transmute, as shown here: diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 8f6b1b8971e5..2c2babf0a665 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -890,19 +890,23 @@ match (A, B, C) { E0422: r##" You are trying to use an identifier that is either undefined or not a struct. Erroneous code example: -``` compile_fail,E0422 + +```compile_fail,E0422 fn main () { let x = Foo { x: 1, y: 2 }; } ``` + In this case, `Foo` is undefined, so it inherently isn't anything, and definitely not a struct. + ```compile_fail fn main () { let foo = 1; let x = foo { x: 1, y: 2 }; } ``` + In this case, `foo` is defined, but is not a struct, so Rust can't use it as one. "##, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 0136faef28d8..bd6129eb5bee 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -790,7 +790,7 @@ 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/pull/809 +[RFC 809]: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md "##, E0067: r##" @@ -1428,7 +1428,7 @@ type X = u32; // this compiles ``` Note that type parameters for enum-variant constructors go after the variant, -not after the enum (Option::None::, not Option::::None). +not after the enum (`Option::None::`, not `Option::::None`). "##, E0110: r##" @@ -1521,7 +1521,7 @@ impl Bar for u32 { For information on the design of the orphan rules, see [RFC 1023]. -[RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023 +[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md "##, E0118: r##" @@ -1911,8 +1911,9 @@ type Foo = Trait; // ok! E0192: r##" Negative impls are only allowed for traits with default impls. For more -information see the [opt-in builtin traits RFC](https://github.com/rust-lang/ -rfcs/blob/master/text/0019-opt-in-builtin-traits.md). +information see the [opt-in builtin traits RFC][RFC 19]. + +[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md "##, E0193: r##" @@ -2147,7 +2148,7 @@ E0202: r##" Inherent associated types were part of [RFC 195] but are not yet implemented. See [the tracking issue][iss8995] for the status of this implementation. -[RFC 195]: https://github.com/rust-lang/rfcs/pull/195 +[RFC 195]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md [iss8995]: https://github.com/rust-lang/rust/issues/8995 "##, @@ -2424,7 +2425,7 @@ such that `Ti` is a local type. Then no type parameter can appear in any of the For information on the design of the orphan rules, see [RFC 1023]. -[RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023 +[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md "##, /* @@ -2799,8 +2800,9 @@ verify this assertion; therefore we must tag this `impl` as unsafe. E0318: r##" Default impls for a trait must be located in the same crate where the trait was -defined. For more information see the [opt-in builtin traits RFC](https://github -.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md). +defined. For more information see the [opt-in builtin traits RFC][RFC 19]. + +[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md "##, E0321: r##" @@ -3018,10 +3020,8 @@ impl Unsize for MyType {} ``` If you are defining your own smart pointer type and would like to enable -conversion from a sized to an unsized type with the [DST coercion system] -(https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md), use -[`CoerceUnsized`](https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html) -instead. +conversion from a sized to an unsized type with the +[DST coercion system][RFC 982], use [`CoerceUnsized`] instead. ``` #![feature(coerce_unsized)] @@ -3035,6 +3035,9 @@ pub struct MyType { impl CoerceUnsized> for MyType where T: CoerceUnsized {} ``` + +[RFC 982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md +[`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html "##, E0329: r##" @@ -3438,8 +3441,9 @@ struct. E0380: r##" Default impls are only allowed for traits with no methods or associated items. -For more information see the [opt-in builtin traits RFC](https://github.com/rust --lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md). +For more information see the [opt-in builtin traits RFC][RFC 19]. + +[RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md "##, E0390: r##" From b8cbc5d46af4b15bfeca324aa37d8c2ca054e58e Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 27 Mar 2017 16:38:17 +0200 Subject: [PATCH 087/905] Addressed requested changes for PR #40838 * Fixed spelling ToSocketAddr -> ToSocketAddrs in module docs (which also fixes a link) * Added missing "when" before "interacting" in module docs * Changed SocketAddr's top-level docs to explicitly state what socket addresses consist of, making them more consistent with SocketAddrV4's and SocketAddrV6's docs * Changed "in C" -> "in C's `netinet/in.h`" * Changed wording in is_ipv4/is_ipv6 methods to ", `false` otherwise" * Add missing closing ` ``` ` in Ipv6Addr's examples * Removed "Errors" section in ToSocketAddrs' to_socket_addrs method as it was rather redundant --- src/libstd/net/addr.rs | 30 ++++++++++++------------------ src/libstd/net/ip.rs | 9 +++------ src/libstd/net/mod.rs | 4 ++-- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index ccfd2a1dfb15..36c06dc0b58d 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -22,9 +22,11 @@ use slice; /// An internet socket address, either IPv4 or IPv6. /// -/// This enum can contain either an [`SocketAddrV4`] or an [`SocketAddrV6`]. see their -/// respective documentation for more details. +/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well +/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and +/// [`SocketAddrV6`]'s respective documentation for more details. /// +/// [IP address]: ../../std/net/enum.IpAddr.html /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html /// @@ -202,13 +204,12 @@ impl SocketAddr { } /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [IPv4 address] and [`false`] if it's an [IPv6 address]. + /// [IPv4 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html /// [IP address]: ../../std/net/enum.IpAddr.html /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 - /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples /// @@ -230,12 +231,11 @@ impl SocketAddr { } /// Returns [`true`] if the [IP address] in this `SocketAddr` is an - /// [IPv6 address] and [`false`] if it's an [IPv4 address]. + /// [IPv6 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html /// [IP address]: ../../std/net/enum.IpAddr.html - /// [IPv4 address]: ../../std/net/enum.IpAddr.html#variant.V4 /// [IPv6 address]: ../../std/net/enum.IpAddr.html#variant.V6 /// /// # Examples @@ -446,10 +446,10 @@ impl SocketAddrV6 { /// Returns the flow information associated with this address. /// - /// This information corresponds to the `sin6_flowinfo` field in C, as specified in - /// [IETF RFC 2553, Section 3.3]. It combines information about the flow label and - /// the traffic class as specified in [IETF RFC 2460], respectively [Section 6] and - /// [Section 7]. + /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. + /// It combines information about the flow label and the traffic class as specified + /// in [IETF RFC 2460], respectively [Section 6] and [Section 7]. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460 @@ -491,8 +491,8 @@ impl SocketAddrV6 { /// Returns the scope ID associated with this address. /// - /// This information corresponds to the `sin6_scope_id` field in C, as specified in - /// [IETF RFC 2553, Section 3.3]. + /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`, + /// as specified in [IETF RFC 2553, Section 3.3]. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// @@ -743,12 +743,6 @@ pub trait ToSocketAddrs { /// /// Note that this function may block the current thread while resolution is /// performed. - /// - /// # Errors - /// - /// Any errors encountered during resolution will be returned as an [`Err`]. - /// - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[stable(feature = "rust1", since = "1.0.0")] fn to_socket_addrs(&self) -> io::Result; } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 2a1f959b35d0..c46fe4a58c7e 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -114,6 +114,7 @@ pub struct Ipv4Addr { /// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); /// assert_eq!("::1".parse(), Ok(localhost)); /// assert_eq!(localhost.is_loopback(), true); +/// ``` #[derive(Copy)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { @@ -266,13 +267,11 @@ impl IpAddr { } } - /// Returns [`true`] if this address is an [IPv4 address] and [`false`] if it's an - /// [IPv6 address]. + /// Returns [`true`] if this address is an [IPv4 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html /// [IPv4 address]: #variant.V4 - /// [IPv6 address]: #variant.V6 /// /// # Examples /// @@ -293,12 +292,10 @@ impl IpAddr { } } - /// Returns [`true`] if this address is an [IPv6 address] and [`false`] if it's an - /// [IPv4 address]. + /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise. /// /// [`true`]: ../../std/primitive.bool.html /// [`false`]: ../../std/primitive.bool.html - /// [IPv4 address]: #variant.V4 /// [IPv6 address]: #variant.V6 /// /// # Examples diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 3b4808fee251..9fcb93e2032b 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -21,7 +21,7 @@ //! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses //! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`] //! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses -//! * [`ToSocketAddr`] is a trait that used for generic address resolution interacting +//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting //! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] //! * Other types are return or parameter types for various methods in this module //! @@ -33,7 +33,7 @@ //! [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html //! [`TcpListener`]: ../../std/net/struct.TcpListener.html //! [`TcpStream`]: ../../std/net/struct.TcpStream.html -//! [`ToSocketAddr`]: ../../std/net/trait.ToSocketAddr.html +//! [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html //! [`UdpSocket`]: ../../std/net/struct.UdpSocket.html #![stable(feature = "rust1", since = "1.0.0")] From e87dd42cfe3dc384cceb3c8385f7551c3af8edaa Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 27 Mar 2017 13:06:56 -0700 Subject: [PATCH 088/905] appveyor: Downgrade MinGW to 6.2.0 It looks like the 6.3.0 MinGW comes with a gdb which has issues (#40184) that an attempted workaround (#40777) does not actually fix (#40835). The original motivation for upgradin MinGW was to fix build flakiness (#40546) due to newer builds not exhibiting the same bug, so let's hope that 6.2.0 isn't too far back in time and still contains the fix we need. Closes #40835 --- appveyor.yml | 8 ++++---- src/tools/compiletest/src/procsrv.rs | 20 ++------------------ 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0f4d053b6cfe..68b2a239aff1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -46,13 +46,13 @@ environment: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 # 32/64 bit MSVC and GNU deployment @@ -71,14 +71,14 @@ environment: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja SCRIPT: python x.py dist MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 DEPLOY: 1 diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs index f55667f93c03..3d8f2296236a 100644 --- a/src/tools/compiletest/src/procsrv.rs +++ b/src/tools/compiletest/src/procsrv.rs @@ -58,24 +58,8 @@ pub fn run(lib_path: &str, let mut cmd = Command::new(prog); cmd.args(args) .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - // Why oh why do we sometimes make a pipe and sometimes inherit the stdin - // stream, well that's an excellent question! In theory it should suffice to - // always create a pipe here and be done with it. Unfortunately though - // there's apparently something odd with the gdb that comes with gcc 6.3.0 - // on MinGW. Tracked at rust-lang/rust#40184 when stdin is piped here - // (unconditionally) then all gdb tests will fail on MinGW when using gcc - // 6.3.0. WHen using an inherited stdin though they happen to all work! - // - // As to why this fixes the issue, well, I have no idea. If you can remove - // this branch and unconditionally use `piped` and it gets past @bors please - // feel free to send a PR! - if input.is_some() || !cfg!(windows) { - cmd.stdin(Stdio::piped()); - } else { - cmd.stdin(Stdio::inherit()); - } + .stderr(Stdio::piped()) + .stdin(Stdio::piped()); add_target_env(&mut cmd, lib_path, aux_path); for (key, val) in env { From 4806f01d7c1f35a1b6f675ff099b86ec6e6c1540 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Mon, 27 Mar 2017 16:34:13 -0400 Subject: [PATCH 089/905] Fix tidy errors and simplify example --- src/libstd/io/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 773b0964b426..1b0c992ba097 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -145,16 +145,14 @@ //! # } //! ``` //! -//! Note that you cannot use the `?` operator in functions that do not return a `Result` (e.g. `main`). -//! Instead, you can `match` on the return value to catch any possible errors: -//! +//! Note that you cannot use the `?` operator in functions that do not return +//! a `Result` (e.g. `main`). Instead, you can call `.unwrap()` or `match` +//! on the return value to catch any possible errors: +//! //! ``` //! let mut input = String::new(); -//! -//! match io::stdin().read_line(&mut input) { -//! Err(why) => panic!("Failed to read input: {}", why.description()), -//! Ok(_) => println!("You typed: {}", input.trim()), -//! } +//! +//! io::stdin().read_line(&mut input).unwrap(); //! ``` //! //! And a very common source of output is standard output: From 434e601446cfb8fd97731f94aa690528ebef4da0 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 27 Mar 2017 16:04:56 -0400 Subject: [PATCH 090/905] Update various book modules This includes an important fix for rustc contributors in https://github.com/rust-lang/book/pull/571 I'm going to update the other ones as well here while we're at it; no need to spam PRs. --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index 9bd223ca406b..a2c56870d4dc 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 9bd223ca406b1170a24942d6474f9e8a56f4a420 +Subproject commit a2c56870d4dc589237102cc5e0fe7b9ebd0d14a1 diff --git a/src/doc/nomicon b/src/doc/nomicon index d08fe97d12b4..616b98444ff4 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit d08fe97d12b41c1ed8cc7701e545864132783941 +Subproject commit 616b98444ff4eb5260deee95ee3e090dfd98b947 diff --git a/src/doc/reference b/src/doc/reference index 516549972d61..acedc32cacae 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 516549972d61c8946542d1a34afeae97167ff77b +Subproject commit acedc32cacae80cf2f4925753a4ce7f7ffd7c86a From da74e865b5a2400fb44660f989008208eb25d538 Mon Sep 17 00:00:00 2001 From: Micah Tigley Date: Mon, 27 Mar 2017 16:14:13 -0600 Subject: [PATCH 091/905] Review request changes --- src/libcollections/str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index d4480ce77d64..34563e310df3 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -11,10 +11,10 @@ //! Unicode string slices. //! //! The `&str` type is one of the two main string types, the other being `String`. -//! Unlike its `String` counterpart, its contents are borrowed and therefore -//! cannot be moved someplace else. +//! Unlike its `String` counterpart, its contents are borrowed. //! //! # Basic Usage +//! //! A basic string declaration of `&str` type: //! //! ``` @@ -27,7 +27,7 @@ //! We can explicitly specify `hello_world`'s lifetime as well: //! //! ``` -//! let hello_world:&'static str = "Hello, world!"; +//! let hello_world: &'static str = "Hello, world!"; //! ``` //! //! *[See also the `str` primitive type](../../std/primitive.str.html).* From c963d613a2275d5c9b31cd7124dda2f2af61deb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Mar 2017 17:15:16 -0700 Subject: [PATCH 092/905] Simplify error output --- src/libsyntax/parse/parser.rs | 17 ++++++----------- src/test/ui/did_you_mean/issue-40006.stderr | 10 +++------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a19339f8cc1c..2603b3302c61 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4708,26 +4708,21 @@ impl<'a> Parser<'a> { if let Err(mut bang_err) = bang_err { // Given this code `pub path(`, it seems like this is not setting the // visibility of a macro invocation, but rather a mistyped method declaration. - // Keep the macro diagnostic, but also provide a hint that `fn` might be - // missing. Don't complain about the missing `!` as a separate diagnostic, add - // label in the appropriate place as part of one unified diagnostic. + // Create a diagnostic pointing out that `fn` is missing. // // x | pub path(&self) { - // | ^^^- - expected `!` here for a macro invocation - // | | - // | did you mean to write `fn` here for a method declaration? + // | ^ missing `fn` for method declaration + err.cancel(); bang_err.cancel(); - err.span_label(self.span, &"expected `!` here for a macro invocation"); // pub path( // ^^ `sp` below will point to this let sp = mk_sp(prev_span.hi, self.prev_span.lo); - err.span_label(sp, - &"did you mean to write `fn` here for a method declaration?"); + err = self.diagnostic() + .struct_span_err(sp, "missing `fn` for method declaration"); + err.span_label(sp, &"missing `fn`"); } return Err(err); - } else if let Err(bang_err) = bang_err { - return Err(bang_err); } // eat a matched-delimiter token tree: diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 93a0c58f91a5..460958027ad0 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,12 +1,8 @@ -error: can't qualify macro invocation with `pub` - --> $DIR/issue-40006.rs:14:5 +error: missing `fn` for method declaration + --> $DIR/issue-40006.rs:14:8 | 14 | pub hello_method(&self) { - | ^^^- - expected `!` here for a macro invocation - | | - | did you mean to write `fn` here for a method declaration? - | - = help: try adjusting the macro to put `pub` inside the invocation + | ^ missing `fn` error: aborting due to previous error From b477682dca3343eb89a467f0d3c73986a53d49d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 25 Mar 2017 19:06:19 -0700 Subject: [PATCH 093/905] Fix unittests --- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax_pos/lib.rs | 4 ++-- src/test/ui/token/bounds-obj-parens.stderr | 1 + src/test/ui/token/issue-10636-2.stderr | 1 + src/test/ui/token/macro-incomplete-parse.stderr | 1 + src/test/ui/token/trailing-plus-in-bounds.stderr | 3 ++- 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4076368c180b..8177d738dc83 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -571,7 +571,7 @@ impl<'a> Parser<'a> { label_sp }; err.span_label(sp, &label_exp); - if label_sp != self.span { + if !sp.source_equal(&self.span) { err.span_label(self.span, &"unexpected token"); } Err(err) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 07494ff904e9..0662c1c9cfdc 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -81,8 +81,8 @@ impl Span { /// Returns a new span representing the next character after the end-point of this span pub fn next_point(self) -> Span { - let lo = BytePos(cmp::max(self.hi.0, self.lo.0 + 1)); - Span { lo: lo, hi: lo, expn_id: self.expn_id} + let lo = cmp::max(self.hi.0, self.lo.0 + 1); + Span { lo: BytePos(lo), hi: BytePos(lo + 1), expn_id: self.expn_id} } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr index ebee363f278e..4d60be15ecaf 100644 --- a/src/test/ui/token/bounds-obj-parens.stderr +++ b/src/test/ui/token/bounds-obj-parens.stderr @@ -5,3 +5,4 @@ error: expected one of `!` or `::`, found `` | ^^^^ expected one of `!` or `::` here error: aborting due to previous error + diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr index 183ad30c4ef4..b0bae1248b96 100644 --- a/src/test/ui/token/issue-10636-2.stderr +++ b/src/test/ui/token/issue-10636-2.stderr @@ -25,3 +25,4 @@ error: expected expression, found `)` error: main function not found error: aborting due to 4 previous errors + diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr index bea00a6444c4..f23d97586b84 100644 --- a/src/test/ui/token/macro-incomplete-parse.stderr +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -29,3 +29,4 @@ note: caused by the macro expansion here; the usage of `ignored_pat!` is likely | ^^^^^^^^^^^^^^ error: aborting due to 3 previous errors + diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr index 74caf8f5c2b3..c765a434b8ac 100644 --- a/src/test/ui/token/trailing-plus-in-bounds.stderr +++ b/src/test/ui/token/trailing-plus-in-bounds.stderr @@ -1,7 +1,8 @@ error: expected one of `!` or `::`, found `` - --> ../../src/test/ui/token/trailing-plus-in-bounds.rs:19:1 + --> $DIR/trailing-plus-in-bounds.rs:19:1 | 19 | FAIL | ^^^^ expected one of `!` or `::` here error: aborting due to previous error + From 756f2248f73d2ea2703a65855c52086a1262a290 Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 27 Mar 2017 23:55:03 -0400 Subject: [PATCH 094/905] Adding links for Atomics docs #29377 --- src/libcore/sync/atomic.rs | 104 +++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 743e3c41170a..c3e7c9b7c989 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -15,27 +15,37 @@ //! types. //! //! This module defines atomic versions of a select number of primitive -//! types, including `AtomicBool`, `AtomicIsize`, and `AtomicUsize`. +//! types, including [`AtomicBool`], [`AtomicIsize`], and [`AtomicUsize`]. //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! -//! Each method takes an `Ordering` which represents the strength of +//! [`AtomicBool`]: struct.AtomicBool.html +//! [`AtomicIsize`]: struct.AtomicIsize.html +//! [`AtomicUsize`]: struct.AtomicUsize.html +//! +//! Each method takes an [`Ordering`] which represents the strength of //! the memory barrier for that operation. These orderings are the //! same as [LLVM atomic orderings][1]. For more information see the [nomicon][2]. //! +//! [`Ordering`]: enum.Ordering.html +//! //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations //! [2]: ../../../nomicon/atomics.html //! -//! Atomic variables are safe to share between threads (they implement `Sync`) +//! Atomic variables are safe to share between threads (they implement [`Sync`]) //! but they do not themselves provide the mechanism for sharing and follow the //! [threading model](../../../std/thread/index.html#the-threading-model) of rust. -//! The most common way to share an atomic variable is to put it into an `Arc` (an +//! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an //! atomically-reference-counted shared pointer). //! +//! [`Sync`]: ../../marker/trait.Sync.html +//! [arc]: ../struct.Arc.html +//! //! Most atomic types may be stored in static variables, initialized using -//! the provided static initializers like `ATOMIC_BOOL_INIT`. Atomic statics +//! the provided static initializers like [`ATOMIC_BOOL_INIT`]. Atomic statics //! are often used for lazy global initialization. //! +//! [`ATOMIC_BOOL_INIT`]: constant.ATOMIC_BOOL_INIT.html //! //! # Examples //! @@ -149,21 +159,26 @@ unsafe impl Sync for AtomicPtr {} #[derive(Copy, Clone, Debug)] pub enum Ordering { /// No ordering constraints, only atomic operations. Corresponds to LLVM's - /// `Monotonic` ordering. + /// [`Monotonic`][1] ordering. + /// [1]: http://llvm.org/docs/Atomics.html#monotonic #[stable(feature = "rust1", since = "1.0.0")] Relaxed, /// When coupled with a store, all previous writes become visible - /// to the other threads that perform a load with `Acquire` ordering + /// to the other threads that perform a load with [`Acquire`][1] ordering /// on the same value. + /// [1]: http://llvm.org/docs/Atomics.html#acquire #[stable(feature = "rust1", since = "1.0.0")] Release, /// When coupled with a load, all subsequent loads will see data - /// written before a store with `Release` ordering on the same value + /// written before a store with [`Release`][1] ordering on the same value /// in other threads. + /// [1]: 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. + /// When coupled with a load, uses [`Acquire`][1] ordering, and with a store + /// [`Release`][2] ordering. + /// [1]: http://llvm.org/docs/Atomics.html#acquire + /// [2]: http://llvm.org/docs/Atomics.html#release #[stable(feature = "rust1", since = "1.0.0")] AcqRel, /// Like `AcqRel` with the additional guarantee that all threads see all @@ -176,7 +191,8 @@ pub enum Ordering { __Nonexhaustive, } -/// An `AtomicBool` initialized to `false`. +/// An [`AtomicBool`] initialized to `false`. +/// [`AtomicBool`]: struct.AtomicBool.html #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); @@ -241,7 +257,7 @@ impl AtomicBool { /// Loads a value from the bool. /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering + /// `load()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// # Panics @@ -250,7 +266,7 @@ impl AtomicBool { /// /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.Release + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel /// /// # Examples /// @@ -269,7 +285,7 @@ impl AtomicBool { /// Stores a value into the bool. /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering + /// `store()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -287,7 +303,10 @@ impl AtomicBool { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, val: bool, order: Ordering) { @@ -298,7 +317,7 @@ impl AtomicBool { /// Stores a value into the bool, returning the old value. /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering + /// `swap()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -324,7 +343,7 @@ impl AtomicBool { /// 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 + /// `compare_and_swap()` also takes an [`Ordering`] argument which describes the memory /// ordering of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -356,7 +375,7 @@ impl AtomicBool { /// 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 + /// `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 @@ -404,17 +423,18 @@ impl AtomicBool { /// Stores a value into the `bool` if the current value is the same as the `current` value. /// - /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the + /// 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 + /// `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.Release @@ -645,7 +665,7 @@ impl AtomicPtr { /// Loads a value from the pointer. /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering + /// `load()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// # Panics @@ -674,7 +694,7 @@ impl AtomicPtr { /// Stores a value into the pointer. /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering + /// `store()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -694,7 +714,11 @@ impl AtomicPtr { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel + /// #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, ptr: *mut T, order: Ordering) { @@ -705,7 +729,7 @@ impl AtomicPtr { /// Stores a value into the pointer, returning the old value. /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering + /// `swap()` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -733,7 +757,7 @@ impl AtomicPtr { /// 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 + /// `compare_and_swap()` also takes an [`Ordering`] argument which describes the memory /// ordering of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -765,7 +789,7 @@ impl AtomicPtr { /// 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 + /// `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`] @@ -812,18 +836,18 @@ impl AtomicPtr { /// Stores a value into the pointer if the current value is the same as the `current` value. /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the + /// 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 + /// `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 + /// [`compare_exchange()`]: #method.compare_exchange /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel @@ -962,7 +986,7 @@ macro_rules! atomic_int { /// Loads a value from the atomic integer. /// - /// `load` takes an [`Ordering`] argument which describes the memory ordering of this + /// `load()` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. /// /// # Panics @@ -990,7 +1014,7 @@ macro_rules! atomic_int { /// Stores a value into the atomic integer. /// - /// `store` takes an [`Ordering`] argument which describes the memory ordering of this + /// `store()` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. /// /// [`Ordering`]: enum.Ordering.html @@ -1008,7 +1032,11 @@ macro_rules! atomic_int { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// 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) { @@ -1017,7 +1045,7 @@ macro_rules! atomic_int { /// Stores a value into the atomic integer, returning the old value. /// - /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this + /// `swap()` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. /// /// [`Ordering`]: enum.Ordering.html @@ -1043,7 +1071,7 @@ macro_rules! atomic_int { /// 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 + /// `compare_and_swap()` also takes an [`Ordering`] argument which describes the memory /// ordering of this operation. /// /// [`Ordering`]: enum.Ordering.html @@ -1083,7 +1111,7 @@ macro_rules! atomic_int { /// 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 + /// `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 @@ -1125,18 +1153,18 @@ macro_rules! atomic_int { /// 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 + /// 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 + /// `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 + /// [`compare_exchange()`]: #method.compare_exchange /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel From b90936449b161f4aee5ff81bbb4906bf5a27f181 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Tue, 28 Mar 2017 17:43:01 +0300 Subject: [PATCH 095/905] libcore: sort_unstable: remove unnecessary loop. `other` is guaranteed to be less than `2 * len`. --- src/libcore/slice/sort.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 3612ee65bca0..7065fdb79fc4 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -527,7 +527,9 @@ fn break_patterns(v: &mut [T]) { // we first take it modulo a power of two, and then decrease by `len` until it fits // into the range `[0, len - 1]`. let mut other = gen_usize() & (modulus - 1); - while other >= len { + + // `other` is guaranteed to be less than `2 * len`. + if other >= len { other -= len; } From cd2ec7eded8d65b88b4c2fdb26efe1b3c505bd6f Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Tue, 28 Mar 2017 13:27:46 -0400 Subject: [PATCH 096/905] add missing import --- src/libstd/io/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 1b0c992ba097..32ead78f6cd5 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -150,6 +150,8 @@ //! on the return value to catch any possible errors: //! //! ``` +//! use std::io; +//! //! let mut input = String::new(); //! //! io::stdin().read_line(&mut input).unwrap(); From 08a80cbda6d505b845f4d857e8f5770df0ea162a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Mar 2017 01:01:23 +0100 Subject: [PATCH 097/905] Replace hoedown with pull in rustdoc --- src/Cargo.lock | 2 + src/librustdoc/Cargo.toml | 1 + src/librustdoc/html/markdown.rs | 429 +++++++++++++++++++++++--------- src/librustdoc/lib.rs | 1 + 4 files changed, 319 insertions(+), 114 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index a0b47f4f0b2b..946818e7d208 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -772,6 +772,8 @@ dependencies = [ "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.0.0", + "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1c479ce1d015..2222077aae80 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -26,6 +26,7 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } +pulldown-cmark = "0.0.8" [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c7c5aabab97a..a745ccc822cd 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -30,9 +30,9 @@ use libc; use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; -use std::ffi::CString; +//use std::ffi::CString; use std::fmt::{self, Write}; -use std::slice; +//use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; use syntax::codemap::Span; @@ -43,6 +43,8 @@ use html::highlight; use html::escape::Escape; use test; +use pulldown_cmark::{self, Parser}; + /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. @@ -53,7 +55,7 @@ pub struct MarkdownWithToc<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. pub struct MarkdownHtml<'a>(pub &'a str); -const DEF_OUNIT: libc::size_t = 64; +/*const DEF_OUNIT: libc::size_t = 64; const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11; const HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0; const HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1; @@ -179,8 +181,8 @@ extern { fn hoedown_document_free(md: *mut hoedown_document); fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; - fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, - n: libc::size_t); + /*fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, + n: libc::size_t);*/ fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); fn hoedown_buffer_free(b: *mut hoedown_buffer); @@ -191,7 +193,7 @@ impl hoedown_buffer { fn as_bytes(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.data, self.size as usize) } } -} +}*/ /// Returns Some(code) if `s` is a line that should be stripped from /// documentation but used in example code. `code` is the portion of @@ -226,8 +228,8 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, - html_flags: libc::c_uint) -> fmt::Result { - extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, + _html_flags: libc::c_uint) -> fmt::Result { + /*extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, lang: *const hoedown_buffer, data: *const hoedown_renderer_data, line: libc::size_t) { unsafe { @@ -422,76 +424,274 @@ pub fn render(w: &mut fmt::Formatter, } hoedown_buffer_free(ob); ret + }*/ + + fn block(parser: &mut Parser, lang: &str, buffer: &mut String) { + let mut origtext = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::CodeBlock(_)) => break, + pulldown_cmark::Event::Text(ref s) => { + origtext.push_str(s); + } + _ => {} + } + } else { + break + } + } + let origtext = origtext.trim_left(); + debug!("docblock: ==============\n{:?}\n=======", origtext); + let rendered = if lang.is_empty() || origtext.is_empty() { + false + } else { + if !LangString::parse(lang).rust { + /*(my_opaque.dfltblk)(ob, orig_text, lang, + opaque as *const hoedown_renderer_data, + line);*/ + // true + false + } else { + false + } + }; + + let lines = origtext.lines().filter(|l| { + stripped_filtered_line(*l).is_none() + }); + let text = lines.collect::>().join("\n"); + if rendered { return } + PLAYGROUND.with(|play| { + // insert newline to clearly separate it from the + // previous block so we can shorten the html output + let mut s = String::from("\n"); + let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { + if url.is_empty() { + return None; + } + let test = origtext.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }).collect::>().join("\n"); + let krate = krate.as_ref().map(|s| &**s); + let test = test::maketest(&test, krate, false, + &Default::default()); + let channel = if test.contains("#![feature(") { + "&version=nightly" + } else { + "" + }; + // These characters don't need to be escaped in a URI. + // FIXME: use a library function for percent encoding. + fn dont_escape(c: u8) -> bool { + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z') || + (b'0' <= c && c <= b'9') || + c == b'-' || c == b'_' || c == b'.' || + c == b'~' || c == b'!' || c == b'\'' || + c == b'(' || c == b')' || c == b'*' + } + let mut test_escaped = String::new(); + for b in test.bytes() { + if dont_escape(b) { + test_escaped.push(char::from(b)); + } else { + write!(test_escaped, "%{:02X}", b).unwrap(); + } + } + Some(format!( + r#"Run"#, + url, test_escaped, channel + )) + }); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + buffer.push_str(&s); + }); } + + fn header(parser: &mut Parser, level: i32, toc_builder: &mut Option, + buffer: &mut String) { + let mut ret = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Header(_)) => break, + pulldown_cmark::Event::Text(ref s) => { + ret.push_str(s); + } + _ => {} + } + } else { + break + } + } + + let id = ret.clone(); + // Discard '', '' tags and some escaped characters, + // transform the contents of the header into a hyphenated string + // without non-alphanumeric characters other than '-' and '_'. + // + // This is a terrible hack working around how hoedown gives us rendered + // html for text rather than the raw text. + let id = id.chars().filter_map(|c| { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); + + let id = derive_id(id); + + let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, ret.clone(), id.clone())) + }); + + // Render the HTML + buffer.push_str(&format!("\ + {sec}{}", + ret, lvl = level, id = id, sec = sec)); + } + + fn codespan(parser: &mut Parser, buffer: &mut String) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Code) => break, + pulldown_cmark::Event::Text(ref s) => { + content.push_str(s); + } + _ => {} + } + } else { + break + } + } + buffer.push_str(&format!("{}", Escape(&collapse_whitespace(&content)))); + } + + let mut toc_builder = if print_toc { + Some(TocBuilder::new()) + } else { + None + }; + let mut buffer = String::new(); + let mut parser = Parser::new(s); + loop { + let next_event = parser.next(); + if let Some(event) = next_event { + match event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { + block(&mut parser, &*s, &mut buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { + header(&mut parser, level, &mut toc_builder, &mut buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => { + codespan(&mut parser, &mut buffer); + } + _ => {} + } + } else { + break + } + } + let mut ret = toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); + + if ret.is_ok() { + ret = w.write_str(&buffer); + } + ret } pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { - extern fn block(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - lang: *const hoedown_buffer, - data: *const hoedown_renderer_data, - line: libc::size_t) { - unsafe { - if text.is_null() { return } - let block_info = if lang.is_null() { - LangString::all_false() - } else { - let lang = (*lang).as_bytes(); - let s = str::from_utf8(lang).unwrap(); - LangString::parse(s) - }; - if !block_info.rust { return } - let text = (*text).as_bytes(); - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - let text = str::from_utf8(text).unwrap(); - let lines = text.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }); - let text = lines.collect::>().join("\n"); - let line = tests.get_line() + line; - let filename = tests.get_filename(); - tests.add_test(text.to_owned(), - block_info.should_panic, block_info.no_run, - block_info.ignore, block_info.test_harness, - block_info.compile_fail, block_info.error_codes, - line, filename); - } - } - - extern fn header(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - level: libc::c_int, data: *const hoedown_renderer_data, - _: libc::size_t) { - unsafe { - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - if text.is_null() { - tests.register_header("", level as u32); - } else { - let text = (*text).as_bytes(); - let text = str::from_utf8(text).unwrap(); - tests.register_header(text, level as u32); - } - } - } - tests.set_position(position); - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let renderer = hoedown_html_renderer_new(0, 0); - (*renderer).blockcode = Some(block); - (*renderer).header = Some(header); - (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque - = tests as *mut _ as *mut libc::c_void; - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, doc.as_ptr(), - doc.len() as libc::size_t); - hoedown_document_free(document); - - hoedown_html_renderer_free(renderer); - hoedown_buffer_free(ob); + let mut parser = Parser::new(doc); + let mut prev_offset = 0; + let mut nb_lines = 0; + let mut register_header = None; + 'main: loop { + let next_event = parser.next(); + if let Some(event) = next_event { + match event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { + let block_info = if s.is_empty() { + LangString::all_false() + } else { + LangString::parse(&*s) + }; + let mut test_s = String::new(); + let mut offset = None; + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::CodeBlock(_)) => break, + pulldown_cmark::Event::Text(ref s) => { + test_s.push_str(s); + if offset.is_none() { + offset = Some(parser.get_offset()); + } + } + _ => {} + } + } else { + break 'main; + } + } + let offset = offset.unwrap_or(0); + let lines = test_s.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); + let text = lines.collect::>().join("\n"); + nb_lines += doc[prev_offset..offset].lines().count(); + let line = tests.get_line() + (nb_lines - 1); + let filename = tests.get_filename(); + tests.add_test(text.to_owned(), + block_info.should_panic, block_info.no_run, + block_info.ignore, block_info.test_harness, + block_info.compile_fail, block_info.error_codes, + line, filename); + prev_offset = offset; + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { + register_header = Some(level as u32); + } + pulldown_cmark::Event::Text(ref s) if register_header.is_some() => { + let level = register_header.unwrap(); + if s.is_empty() { + tests.register_header("", level); + } else { + tests.register_header(s, level); + } + register_header = None; + } + _ => {} + } + } else { + break + } } } @@ -589,57 +789,58 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, HOEDOWN_HTML_ESCAPE) + render(fmt, md, false, /*HOEDOWN_HTML_ESCAPE*/0) } } pub fn plain_summary_line(md: &str) -> String { - extern fn link(_ob: *mut hoedown_buffer, - _link: *const hoedown_buffer, - _title: *const hoedown_buffer, - content: *const hoedown_buffer, - data: *const hoedown_renderer_data, - _: libc::size_t) -> libc::c_int - { - unsafe { - if !content.is_null() && (*content).size > 0 { - let ob = (*data).opaque as *mut hoedown_buffer; - hoedown_buffer_put(ob, (*content).data as *const libc::c_char, - (*content).size); + struct ParserWrapper<'a> { + inner: Parser<'a>, + is_in: isize, + is_first: bool, + } + + impl<'a> Iterator for ParserWrapper<'a> { + type Item = String; + + fn next(&mut self) -> Option { + let next_event = self.inner.next(); + if next_event.is_none() { + return None + } + let next_event = next_event.unwrap(); + let (ret, is_in) = match next_event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => (None, 1), + pulldown_cmark::Event::Start( + pulldown_cmark::Tag::Link(_, ref t)) if !self.is_first => (Some(t.as_ref().to_owned()), 1), + pulldown_cmark::Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), + pulldown_cmark::Event::End(pulldown_cmark::Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), + pulldown_cmark::Event::End(pulldown_cmark::Tag::Paragraph) => (None, -1), + _ => (None, 0), + }; + if is_in > 0 || (is_in < 0 && self.is_in > 0) { + self.is_in += is_in; + } + if ret.is_some() { + self.is_first = false; + ret + } else { + Some(String::new()) } } - 1 } - - extern fn normal_text(_ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - data: *const hoedown_renderer_data, - _: libc::size_t) - { - unsafe { - let ob = (*data).opaque as *mut hoedown_buffer; - hoedown_buffer_put(ob, (*text).data as *const libc::c_char, - (*text).size); + let mut s = String::with_capacity(md.len() * 3 / 2); + let mut p = ParserWrapper { + inner: Parser::new(md), + is_in: 0, + is_first: true, + }; + while let Some(t) = p.next() { + if !t.is_empty() { + s.push_str(&t); } } - - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let mut plain_renderer: hoedown_renderer = ::std::mem::zeroed(); - let renderer: *mut hoedown_renderer = &mut plain_renderer; - (*renderer).opaque = ob as *mut libc::c_void; - (*renderer).link = Some(link); - (*renderer).normal_text = Some(normal_text); - - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, md.as_ptr(), - md.len() as libc::size_t); - hoedown_document_free(document); - let plain_slice = (*ob).as_bytes(); - let plain = str::from_utf8(plain_slice).unwrap_or("").to_owned(); - hoedown_buffer_free(ob); - plain - } + s } #[cfg(test)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 8dd03f6edc4d..efb51bdf471f 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -48,6 +48,7 @@ extern crate test as testing; extern crate std_unicode; #[macro_use] extern crate log; extern crate rustc_errors as errors; +extern crate pulldown_cmark; extern crate serialize as rustc_serialize; // used by deriving From c9415eb98ff2a5cf679954e5eaf66274a24db1ee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Mar 2017 23:56:00 +0100 Subject: [PATCH 098/905] Remains to fix tables --- src/librustdoc/html/markdown.rs | 98 +++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a745ccc822cd..a36e99e80dfe 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -43,7 +43,7 @@ use html::highlight; use html::escape::Escape; use test; -use pulldown_cmark::{self, Parser}; +use pulldown_cmark::{self, Event, Parser}; /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered @@ -467,7 +467,7 @@ pub fn render(w: &mut fmt::Formatter, PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output - let mut s = String::from("\n"); + buffer.push('\n'); let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { if url.is_empty() { return None; @@ -506,12 +506,11 @@ pub fn render(w: &mut fmt::Formatter, url, test_escaped, channel )) }); - s.push_str(&highlight::render_with_highlighting( - &text, - Some("rust-example-rendered"), - None, - playground_button.as_ref().map(String::as_str))); - buffer.push_str(&s); + buffer.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); }); } @@ -587,6 +586,74 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", Escape(&collapse_whitespace(&content)))); } + fn link(parser: &mut Parser, buffer: &mut String, url: &str, mut title: String) { + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Link(_, _)) => break, + pulldown_cmark::Event::Text(ref s) => { + title.push_str(s); + } + _ => {} + } + } else { + break + } + } + buffer.push_str(&format!("{}", url, title)); + } + + fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + pulldown_cmark::Event::End( + pulldown_cmark::Tag::Paragraph) => break, + pulldown_cmark::Event::Text(ref s) => { + content.push_str(s); + } + x => { + looper(parser, &mut content, Some(x), toc_builder); + } + } + } else { + break + } + } + buffer.push_str(&format!("

{}

", content)); + } + + fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, + toc_builder: &mut Option) -> bool { + if let Some(event) = next_event { + match event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { + block(parser, &*s, buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { + header(parser, level, toc_builder, buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => { + codespan(parser, buffer); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => { + paragraph(parser, buffer, toc_builder); + } + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link(ref url, ref t)) => { + link(parser, buffer, url, t.as_ref().to_owned()); + } + _ => {} + } + true + } else { + false + } + } + let mut toc_builder = if print_toc { Some(TocBuilder::new()) } else { @@ -596,20 +663,7 @@ pub fn render(w: &mut fmt::Formatter, let mut parser = Parser::new(s); loop { let next_event = parser.next(); - if let Some(event) = next_event { - match event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { - block(&mut parser, &*s, &mut buffer); - } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { - header(&mut parser, level, &mut toc_builder, &mut buffer); - } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => { - codespan(&mut parser, &mut buffer); - } - _ => {} - } - } else { + if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder) { break } } From b96fef8411f26e357e31b8c1b584b6d994efafaa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 10 Mar 2017 14:06:24 +0100 Subject: [PATCH 099/905] End of pulldown switch and remove completely hoedown --- .gitmodules | 4 - src/librustdoc/Cargo.toml | 1 - src/librustdoc/build.rs | 29 -- src/librustdoc/html/markdown.rs | 661 ++++++++++---------------------- src/librustdoc/html/render.rs | 8 +- src/librustdoc/markdown.rs | 2 +- src/rt/hoedown | 1 - 7 files changed, 216 insertions(+), 490 deletions(-) delete mode 100644 src/librustdoc/build.rs delete mode 160000 src/rt/hoedown diff --git a/.gitmodules b/.gitmodules index d2e1fb868a99..53d178749240 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,10 +5,6 @@ [submodule "src/compiler-rt"] path = src/compiler-rt url = https://github.com/rust-lang/compiler-rt.git -[submodule "src/rt/hoedown"] - path = src/rt/hoedown - url = https://github.com/rust-lang/hoedown.git - branch = rust-2015-09-21-do-not-delete [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 2222077aae80..ff18daa7aa09 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -2,7 +2,6 @@ authors = ["The Rust Project Developers"] name = "rustdoc" version = "0.0.0" -build = "build.rs" [lib] name = "rustdoc" diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs deleted file mode 100644 index 9fa6406c1d8b..000000000000 --- a/src/librustdoc/build.rs +++ /dev/null @@ -1,29 +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. - -extern crate build_helper; -extern crate gcc; - -fn main() { - let src_dir = std::path::Path::new("../rt/hoedown/src"); - build_helper::rerun_if_changed_anything_in_dir(src_dir); - let mut cfg = gcc::Config::new(); - cfg.file("../rt/hoedown/src/autolink.c") - .file("../rt/hoedown/src/buffer.c") - .file("../rt/hoedown/src/document.c") - .file("../rt/hoedown/src/escape.c") - .file("../rt/hoedown/src/html.c") - .file("../rt/hoedown/src/html_blocks.c") - .file("../rt/hoedown/src/html_smartypants.c") - .file("../rt/hoedown/src/stack.c") - .file("../rt/hoedown/src/version.c") - .include(src_dir) - .compile("libhoedown.a"); -} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a36e99e80dfe..9ae6c443f9e0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -26,7 +26,7 @@ #![allow(non_camel_case_types)] -use libc; +//use libc; use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; @@ -43,158 +43,19 @@ use html::highlight; use html::escape::Escape; use test; -use pulldown_cmark::{self, Event, Parser}; +use pulldown_cmark::{self, Event, Parser, Tag}; /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. -pub struct Markdown<'a>(pub &'a str); +// The second parameter is whether we need a shorter version or not. +pub struct Markdown<'a>(pub &'a str, pub bool); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. pub struct MarkdownHtml<'a>(pub &'a str); -/*const DEF_OUNIT: libc::size_t = 64; -const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11; -const HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0; -const HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1; -const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; -const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; -const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; -const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; -const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1; - -const HOEDOWN_EXTENSIONS: libc::c_uint = - HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | - HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | - HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_SUPERSCRIPT | - HOEDOWN_EXT_FOOTNOTES; - -enum hoedown_document {} - -type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_renderer_data, - libc::size_t); - -type blockquotefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - libc::c_int, *const hoedown_renderer_data, - libc::size_t); - -type blockhtmlfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t) -> libc::c_int; - -type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t) -> libc::c_int; - -type entityfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -type normaltextfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_renderer_data, libc::size_t); - -#[repr(C)] -struct hoedown_renderer_data { - opaque: *mut libc::c_void, -} - -#[repr(C)] -struct hoedown_renderer { - opaque: *mut libc::c_void, - - blockcode: Option, - blockquote: Option, - header: Option, - - other_block_level_callbacks: [libc::size_t; 11], - - blockhtml: Option, - - /* span level callbacks - NULL or return 0 prints the span verbatim */ - autolink: libc::size_t, // unused - codespan: Option, - other_span_level_callbacks_1: [libc::size_t; 7], - link: Option, - other_span_level_callbacks_2: [libc::size_t; 6], - - /* low level callbacks - NULL copies input directly into the output */ - entity: Option, - normal_text: Option, - - /* header and footer */ - other_callbacks: [libc::size_t; 2], -} - -#[repr(C)] -struct hoedown_html_renderer_state { - opaque: *mut libc::c_void, - toc_data: html_toc_data, - flags: libc::c_uint, - link_attributes: Option, -} - -#[repr(C)] -struct html_toc_data { - header_count: libc::c_int, - current_level: libc::c_int, - level_offset: libc::c_int, - nesting_level: libc::c_int, -} - -struct MyOpaque { - dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, - *const hoedown_buffer, *const hoedown_renderer_data, - libc::size_t), - toc_builder: Option, -} - -#[repr(C)] -struct hoedown_buffer { - data: *const u8, - size: libc::size_t, - asize: libc::size_t, - unit: libc::size_t, -} - -extern { - fn hoedown_html_renderer_new(render_flags: libc::c_uint, - nesting_level: libc::c_int) - -> *mut hoedown_renderer; - fn hoedown_html_renderer_free(renderer: *mut hoedown_renderer); - - fn hoedown_document_new(rndr: *const hoedown_renderer, - extensions: libc::c_uint, - max_nesting: libc::size_t) -> *mut hoedown_document; - fn hoedown_document_render(doc: *mut hoedown_document, - ob: *mut hoedown_buffer, - document: *const u8, - doc_size: libc::size_t); - fn hoedown_document_free(md: *mut hoedown_document); - - fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; - /*fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, - n: libc::size_t);*/ - fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); - fn hoedown_buffer_free(b: *mut hoedown_buffer); - -} - -// hoedown_buffer helpers -impl hoedown_buffer { - fn as_bytes(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.data, self.size as usize) } - } -}*/ - /// Returns Some(code) if `s` is a line that should be stripped from /// documentation but used in example code. `code` is the portion of /// `s` that should be used in tests. (None for lines that should be @@ -228,213 +89,15 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, - _html_flags: libc::c_uint) -> fmt::Result { - /*extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, - lang: *const hoedown_buffer, data: *const hoedown_renderer_data, - line: libc::size_t) { - unsafe { - if orig_text.is_null() { return } - - let opaque = (*data).opaque as *mut hoedown_html_renderer_state; - let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque); - let text = (*orig_text).as_bytes(); - let origtext = str::from_utf8(text).unwrap(); - let origtext = origtext.trim_left(); - debug!("docblock: ==============\n{:?}\n=======", text); - let rendered = if lang.is_null() || origtext.is_empty() { - false - } else { - let rlang = (*lang).as_bytes(); - let rlang = str::from_utf8(rlang).unwrap(); - if !LangString::parse(rlang).rust { - (my_opaque.dfltblk)(ob, orig_text, lang, - opaque as *const hoedown_renderer_data, - line); - true - } else { - false - } - }; - - let lines = origtext.lines().filter(|l| { - stripped_filtered_line(*l).is_none() - }); - let text = lines.collect::>().join("\n"); - if rendered { return } - PLAYGROUND.with(|play| { - // insert newline to clearly separate it from the - // previous block so we can shorten the html output - let mut s = String::from("\n"); - let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { - if url.is_empty() { - return None; - } - let test = origtext.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }).collect::>().join("\n"); - let krate = krate.as_ref().map(|s| &**s); - let test = test::maketest(&test, krate, false, - &Default::default()); - let channel = if test.contains("#![feature(") { - "&version=nightly" - } else { - "" - }; - // These characters don't need to be escaped in a URI. - // FIXME: use a library function for percent encoding. - fn dont_escape(c: u8) -> bool { - (b'a' <= c && c <= b'z') || - (b'A' <= c && c <= b'Z') || - (b'0' <= c && c <= b'9') || - c == b'-' || c == b'_' || c == b'.' || - c == b'~' || c == b'!' || c == b'\'' || - c == b'(' || c == b')' || c == b'*' - } - let mut test_escaped = String::new(); - for b in test.bytes() { - if dont_escape(b) { - test_escaped.push(char::from(b)); - } else { - write!(test_escaped, "%{:02X}", b).unwrap(); - } - } - Some(format!( - r#"Run"#, - url, test_escaped, channel - )) - }); - s.push_str(&highlight::render_with_highlighting( - &text, - Some("rust-example-rendered"), - None, - playground_button.as_ref().map(String::as_str))); - let output = CString::new(s).unwrap(); - hoedown_buffer_puts(ob, output.as_ptr()); - }) - } - } - - extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, - level: libc::c_int, data: *const hoedown_renderer_data, - _: libc::size_t) { - // hoedown does this, we may as well too - unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } - - // Extract the text provided - let s = if text.is_null() { - "".to_owned() - } else { - let s = unsafe { (*text).as_bytes() }; - str::from_utf8(&s).unwrap().to_owned() - }; - - // Discard '', '' tags and some escaped characters, - // transform the contents of the header into a hyphenated string - // without non-alphanumeric characters other than '-' and '_'. - // - // This is a terrible hack working around how hoedown gives us rendered - // html for text rather than the raw text. - let mut id = s.clone(); - let repl_sub = vec!["", "", "", "", - "", "", - "<", ">", "&", "'", """]; - for sub in repl_sub { - id = id.replace(sub, ""); - } - let id = id.chars().filter_map(|c| { - if c.is_alphanumeric() || c == '-' || c == '_' { - if c.is_ascii() { - Some(c.to_ascii_lowercase()) - } else { - Some(c) - } - } else if c.is_whitespace() && c.is_ascii() { - Some('-') - } else { - None - } - }).collect::(); - - let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state }; - let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; - - let id = derive_id(id); - - let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| { - format!("{} ", builder.push(level as u32, s.clone(), id.clone())) - }); - - // Render the HTML - let text = format!("\ - {sec}{}", - s, lvl = level, id = id, sec = sec); - - let text = CString::new(text).unwrap(); - unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } - } - - extern fn codespan( - ob: *mut hoedown_buffer, - text: *const hoedown_buffer, - _: *const hoedown_renderer_data, - _: libc::size_t - ) -> libc::c_int { - let content = if text.is_null() { - "".to_owned() - } else { - let bytes = unsafe { (*text).as_bytes() }; - let s = str::from_utf8(bytes).unwrap(); - collapse_whitespace(s) - }; - - let content = format!("{}", Escape(&content)); - let element = CString::new(content).unwrap(); - unsafe { hoedown_buffer_puts(ob, element.as_ptr()); } - // Return anything except 0, which would mean "also print the code span verbatim". - 1 - } - - unsafe { - let ob = hoedown_buffer_new(DEF_OUNIT); - let renderer = hoedown_html_renderer_new(html_flags, 0); - let mut opaque = MyOpaque { - dfltblk: (*renderer).blockcode.unwrap(), - toc_builder: if print_toc {Some(TocBuilder::new())} else {None} - }; - (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque - = &mut opaque as *mut _ as *mut libc::c_void; - (*renderer).blockcode = Some(block); - (*renderer).header = Some(header); - (*renderer).codespan = Some(codespan); - - let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); - hoedown_document_render(document, ob, s.as_ptr(), - s.len() as libc::size_t); - hoedown_document_free(document); - - hoedown_html_renderer_free(renderer); - - let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { - write!(w, "", builder.into_toc()) - }); - - if ret.is_ok() { - let buf = (*ob).as_bytes(); - ret = w.write_str(str::from_utf8(buf).unwrap()); - } - hoedown_buffer_free(ob); - ret - }*/ - - fn block(parser: &mut Parser, lang: &str, buffer: &mut String) { + shorter: bool) -> fmt::Result { + fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); loop { let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::CodeBlock(_)) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::CodeBlock(_)) => break, + Event::Text(ref s) => { origtext.push_str(s); } _ => {} @@ -445,25 +108,21 @@ pub fn render(w: &mut fmt::Formatter, } let origtext = origtext.trim_left(); debug!("docblock: ==============\n{:?}\n=======", origtext); - let rendered = if lang.is_empty() || origtext.is_empty() { - false - } else { - if !LangString::parse(lang).rust { - /*(my_opaque.dfltblk)(ob, orig_text, lang, - opaque as *const hoedown_renderer_data, - line);*/ - // true - false - } else { - false - } - }; let lines = origtext.lines().filter(|l| { stripped_filtered_line(*l).is_none() }); let text = lines.collect::>().join("\n"); - if rendered { return } + let block_info = if lang.is_empty() { + LangString::all_false() + } else { + LangString::parse(lang) + }; + if !block_info.rust { + buffer.push_str(&format!("
{}
", + lang, text)); + return + } PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output @@ -521,9 +180,8 @@ pub fn render(w: &mut fmt::Formatter, let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Header(_)) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Header(_)) => break, + Event::Text(ref s) => { ret.push_str(s); } _ => {} @@ -561,8 +219,8 @@ pub fn render(w: &mut fmt::Formatter, }); // Render the HTML - buffer.push_str(&format!("\ - {sec}{}", + buffer.push_str(&format!("\ + {sec}{}", ret, lvl = level, id = id, sec = sec)); } @@ -572,9 +230,8 @@ pub fn render(w: &mut fmt::Formatter, let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Code) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Code) => break, + Event::Text(ref s) => { content.push_str(s); } _ => {} @@ -591,9 +248,8 @@ pub fn render(w: &mut fmt::Formatter, let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Link(_, _)) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Link(_, _)) => break, + Event::Text(ref s) => { title.push_str(s); } _ => {} @@ -605,19 +261,19 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", url, title)); } - fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option) { + fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { let mut content = String::new(); loop { let event = parser.next(); if let Some(event) = event { match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::Paragraph) => break, - pulldown_cmark::Event::Text(ref s) => { + Event::End(Tag::Paragraph) => break, + Event::Text(ref s) => { content.push_str(s); } x => { - looper(parser, &mut content, Some(x), toc_builder); + looper(parser, &mut content, Some(x), toc_builder, shorter); } } } else { @@ -627,28 +283,135 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("

{}

", content)); } + fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) | + Event::End(Tag::TableCell) => break, + Event::Text(ref s) => { + content.push_str(s); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } else { + break + } + } + buffer.push_str(&format!("{}", content.trim())); + } + + fn row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } else { + break + } + } + buffer.push_str(&format!("{}", content)); + } + + fn head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } else { + break + } + } + if content.is_empty() { + return + } + buffer.push_str(&format!("{}", content.replace("td>", "th>"))); + } + + fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: bool) { + let mut content = String::new(); + let mut rows = String::new(); + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableHead) => { + head(parser, &mut content, toc_builder, shorter); + } + Event::Start(Tag::TableRow) => { + row(parser, &mut rows, toc_builder, shorter); + } + _ => {} + } + } else { + break + } + } + buffer.push_str(&format!("{}{}
", + content, + if shorter || rows.is_empty() { + String::new() + } else { + format!("{}", rows) + })); + } + fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option) -> bool { + toc_builder: &mut Option, shorter: bool) -> bool { if let Some(event) = next_event { match event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { - block(parser, &*s, buffer); + Event::Start(Tag::CodeBlock(lang)) => { + block(parser, buffer, &*lang); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { + Event::Start(Tag::Header(level)) => { header(parser, level, toc_builder, buffer); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Code) => { + Event::Start(Tag::Code) => { codespan(parser, buffer); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => { - paragraph(parser, buffer, toc_builder); + Event::Start(Tag::Paragraph) => { + paragraph(parser, buffer, toc_builder, shorter); } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link(ref url, ref t)) => { + Event::Start(Tag::Link(ref url, ref t)) => { link(parser, buffer, url, t.as_ref().to_owned()); } + Event::Start(Tag::Table(_)) => { + table(parser, buffer, toc_builder, shorter); + } _ => {} } - true + shorter == false } else { false } @@ -660,10 +423,10 @@ pub fn render(w: &mut fmt::Formatter, None }; let mut buffer = String::new(); - let mut parser = Parser::new(s); + let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); loop { let next_event = parser.next(); - if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder) { + if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter) { break } } @@ -684,67 +447,64 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Sp let mut prev_offset = 0; let mut nb_lines = 0; let mut register_header = None; - 'main: loop { - let next_event = parser.next(); - if let Some(event) = next_event { - match event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(s)) => { - let block_info = if s.is_empty() { - LangString::all_false() - } else { - LangString::parse(&*s) - }; - let mut test_s = String::new(); - let mut offset = None; - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - pulldown_cmark::Event::End( - pulldown_cmark::Tag::CodeBlock(_)) => break, - pulldown_cmark::Event::Text(ref s) => { - test_s.push_str(s); - if offset.is_none() { - offset = Some(parser.get_offset()); - } + 'main: while let Some(event) = parser.next() { + match event { + Event::Start(Tag::CodeBlock(s)) => { + let block_info = if s.is_empty() { + LangString::all_false() + } else { + LangString::parse(&*s) + }; + if !block_info.rust { + continue + } + let mut test_s = String::new(); + let mut offset = None; + loop { + let event = parser.next(); + if let Some(event) = event { + match event { + Event::End(Tag::CodeBlock(_)) => break, + Event::Text(ref s) => { + test_s.push_str(s); + if offset.is_none() { + offset = Some(parser.get_offset()); } - _ => {} } - } else { - break 'main; + _ => {} } - } - let offset = offset.unwrap_or(0); - let lines = test_s.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }); - let text = lines.collect::>().join("\n"); - nb_lines += doc[prev_offset..offset].lines().count(); - let line = tests.get_line() + (nb_lines - 1); - let filename = tests.get_filename(); - tests.add_test(text.to_owned(), - block_info.should_panic, block_info.no_run, - block_info.ignore, block_info.test_harness, - block_info.compile_fail, block_info.error_codes, - line, filename); - prev_offset = offset; - } - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Header(level)) => { - register_header = Some(level as u32); - } - pulldown_cmark::Event::Text(ref s) if register_header.is_some() => { - let level = register_header.unwrap(); - if s.is_empty() { - tests.register_header("", level); } else { - tests.register_header(s, level); + break 'main; } - register_header = None; } - _ => {} + let offset = offset.unwrap_or(0); + let lines = test_s.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); + let text = lines.collect::>().join("\n"); + nb_lines += doc[prev_offset..offset].lines().count(); + let line = tests.get_line() + (nb_lines - 1); + let filename = tests.get_filename(); + tests.add_test(text.to_owned(), + block_info.should_panic, block_info.no_run, + block_info.ignore, block_info.test_harness, + block_info.compile_fail, block_info.error_codes, + line, filename); + prev_offset = offset; } - } else { - break + Event::Start(Tag::Header(level)) => { + register_header = Some(level as u32); + } + Event::Text(ref s) if register_header.is_some() => { + let level = register_header.unwrap(); + if s.is_empty() { + tests.register_header("", level); + } else { + tests.register_header(s, level); + } + register_header = None; + } + _ => {} } } } @@ -824,17 +584,17 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md) = *self; + let Markdown(md, shorter) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, 0) + render(fmt, md, false, shorter) } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let MarkdownWithToc(md) = *self; - render(fmt, md, true, 0) + render(fmt, md, true, false) } } @@ -843,7 +603,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, /*HOEDOWN_HTML_ESCAPE*/0) + render(fmt, md, false, false) } } @@ -864,12 +624,13 @@ pub fn plain_summary_line(md: &str) -> String { } let next_event = next_event.unwrap(); let (ret, is_in) = match next_event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::Paragraph) => (None, 1), - pulldown_cmark::Event::Start( - pulldown_cmark::Tag::Link(_, ref t)) if !self.is_first => (Some(t.as_ref().to_owned()), 1), - pulldown_cmark::Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - pulldown_cmark::Event::End(pulldown_cmark::Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), - pulldown_cmark::Event::End(pulldown_cmark::Tag::Paragraph) => (None, -1), + Event::Start(Tag::Paragraph) => (None, 1), + Event::Start(Tag::Link(_, ref t)) if !self.is_first => { + (Some(t.as_ref().to_owned()), 1) + } + Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), + Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), + Event::End(Tag::Paragraph) => (None, -1), _ => (None, 0), }; if is_in > 0 || (is_in < 0 && self.is_in > 0) { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5c94032c6b9c..8c1416b80979 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1650,7 +1650,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin } else { format!("{}", &plain_summary_line(Some(s))) }; - write!(w, "
{}
", Markdown(&markdown))?; + write!(w, "
{}
", Markdown(&markdown, false))?; } Ok(()) } @@ -1683,7 +1683,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
{}
", - Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), false))?; } Ok(()) } @@ -1871,7 +1871,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value).to_string())), + docs = shorter(Some(&Markdown(doc_value, true).to_string())), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2901,7 +2901,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "
")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
{}
", Markdown(dox))?; + write!(w, "
{}
", Markdown(dox, false))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index c67e2fdc2b02..a048750279e2 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -94,7 +94,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let rendered = if include_toc { format!("{}", MarkdownWithToc(text)) } else { - format!("{}", Markdown(text)) + format!("{}", Markdown(text, false)) }; let err = write!( diff --git a/src/rt/hoedown b/src/rt/hoedown deleted file mode 160000 index da282f1bb727..000000000000 --- a/src/rt/hoedown +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 From f6baea23bad46050e8f0840713c9d13a40edaf68 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 10 Mar 2017 18:35:15 +0100 Subject: [PATCH 100/905] Fix external doc errors --- src/libcore/result.rs | 2 +- src/tools/error_index_generator/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 6ec8a37dfa43..c46b0c1324de 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -838,10 +838,10 @@ impl Result { /// /// assert_eq!(1909, good_year); /// assert_eq!(0, bad_year); + /// ``` /// /// [`parse`]: ../../std/primitive.str.html#method.parse /// [`FromStr`]: ../../std/str/trait.FromStr.html - /// ``` #[inline] #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] pub fn unwrap_or_default(self) -> T { diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index e33df0dfbc8d..2f4a38c16c1d 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, false))?, None => write!(output, "

No description.

\n")?, } From d5b6c046de79bf357683d9db191ed6a97c24187c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 01:43:36 +0100 Subject: [PATCH 101/905] Add missing markdown tags --- src/librustdoc/html/markdown.rs | 381 +++++++++++++++--------- src/librustdoc/html/render.rs | 13 +- src/librustdoc/markdown.rs | 4 +- src/tools/error_index_generator/main.rs | 4 +- 4 files changed, 251 insertions(+), 151 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9ae6c443f9e0..e8c95c4a21c3 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -26,13 +26,10 @@ #![allow(non_camel_case_types)] -//use libc; use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; -//use std::ffi::CString; use std::fmt::{self, Write}; -//use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; use syntax::codemap::Span; @@ -45,11 +42,33 @@ use test; use pulldown_cmark::{self, Event, Parser, Tag}; +#[derive(Copy, Clone)] +pub enum MarkdownOutputStyle { + Compact, + Fancy, +} + +impl MarkdownOutputStyle { + pub fn is_compact(&self) -> bool { + match *self { + MarkdownOutputStyle::Compact => true, + _ => false, + } + } + + pub fn is_fancy(&self) -> bool { + match *self { + MarkdownOutputStyle::Fancy => true, + _ => false, + } + } +} + /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str, pub bool); +pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); @@ -85,25 +104,19 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = RefCell::new(None) }); - pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, - shorter: bool) -> fmt::Result { + shorter: MarkdownOutputStyle) -> fmt::Result { fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::CodeBlock(_)) => break, - Event::Text(ref s) => { - origtext.push_str(s); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::CodeBlock(_)) => break, + Event::Text(ref s) => { + origtext.push_str(s); } - } else { - break + _ => {} } } let origtext = origtext.trim_left(); @@ -176,20 +189,19 @@ pub fn render(w: &mut fmt::Formatter, fn header(parser: &mut Parser, level: i32, toc_builder: &mut Option, buffer: &mut String) { let mut ret = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Header(_)) => break, - Event::Text(ref s) => { - ret.push_str(s); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Header(_)) => break, + Event::Text(ref s) => { + ret.push_str(s); } - } else { - break + Event::SoftBreak | Event::HardBreak if !ret.is_empty() => { + ret.push(' '); + } + _ => {} } } + ret = ret.trim_right().to_owned(); let id = ret.clone(); // Discard '', '' tags and some escaped characters, @@ -226,169 +238,242 @@ pub fn render(w: &mut fmt::Formatter, fn codespan(parser: &mut Parser, buffer: &mut String) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Code) => break, - Event::Text(ref s) => { - content.push_str(s); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Code) => break, + Event::Text(ref s) => { + content.push_str(s); } - } else { - break + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + _ => {} } } - buffer.push_str(&format!("{}", Escape(&collapse_whitespace(&content)))); + buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } - fn link(parser: &mut Parser, buffer: &mut String, url: &str, mut title: String) { - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Link(_, _)) => break, - Event::Text(ref s) => { - title.push_str(s); - } - _ => {} + fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, url: &str, mut title: String) { + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Link(_, _)) => break, + Event::Text(ref s) => { + title.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !title.is_empty() => { + title.push(' '); + } + x => { + looper(parser, &mut title, Some(x), toc_builder, shorter); } - } else { - break } } buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Paragraph) => break, - Event::Text(ref s) => { - content.push_str(s); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Paragraph) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } - buffer.push_str(&format!("

{}

", content)); + buffer.push_str(&format!("

{}

", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) | - Event::End(Tag::TableCell) => break, - Event::Text(ref s) => { - content.push_str(s); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) | + Event::End(Tag::TableCell) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } buffer.push_str(&format!("{}", content.trim())); } fn row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) => break, - Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } buffer.push_str(&format!("{}", content)); } fn head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } + while let Some(event) = parser.next() { + match event { + Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableCell) => { + cell(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); } - } else { - break } } - if content.is_empty() { - return + if !content.is_empty() { + buffer.push_str(&format!("{}", content.replace("td>", "th>"))); } - buffer.push_str(&format!("{}", content.replace("td>", "th>"))); } fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: bool) { + shorter: MarkdownOutputStyle) { let mut content = String::new(); let mut rows = String::new(); - loop { - let event = parser.next(); - if let Some(event) = event { - match event { - Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableHead) => { - head(parser, &mut content, toc_builder, shorter); - } - Event::Start(Tag::TableRow) => { - row(parser, &mut rows, toc_builder, shorter); - } - _ => {} + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Table(_)) => break, + Event::Start(Tag::TableHead) => { + head(parser, &mut content, toc_builder, shorter); } - } else { - break + Event::Start(Tag::TableRow) => { + row(parser, &mut rows, toc_builder, shorter); + } + _ => {} } } buffer.push_str(&format!("{}{}
", content, - if shorter || rows.is_empty() { + if shorter.is_compact() || rows.is_empty() { String::new() } else { format!("{}", rows) })); } + fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::BlockQuote) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("
{}
", content.trim_right())); + } + + fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Item) => break, + Event::Text(ref s) => { + content.push_str(s); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("
  • {}
  • ", content)); + } + + fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::List(_)) => break, + Event::Start(Tag::Item) => { + list_item(parser, &mut content, toc_builder, shorter); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("
      {}
    ", content)); + } + + fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Emphasis) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("{}", content)); + } + + fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { + let mut content = String::new(); + while let Some(event) = parser.next() { + match event { + Event::End(Tag::Strong) => break, + Event::Text(ref s) => { + content.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !content.is_empty() => { + content.push(' '); + } + x => { + looper(parser, &mut content, Some(x), toc_builder, shorter); + } + } + } + buffer.push_str(&format!("{}", content)); + } + fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option, shorter: bool) -> bool { + toc_builder: &mut Option, shorter: MarkdownOutputStyle) -> bool { if let Some(event) = next_event { match event { Event::Start(Tag::CodeBlock(lang)) => { @@ -404,14 +489,26 @@ pub fn render(w: &mut fmt::Formatter, paragraph(parser, buffer, toc_builder, shorter); } Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, url, t.as_ref().to_owned()); + link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned()); } Event::Start(Tag::Table(_)) => { table(parser, buffer, toc_builder, shorter); } + Event::Start(Tag::BlockQuote) => { + blockquote(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::List(_)) => { + list(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::Emphasis) => { + emphasis(parser, buffer, toc_builder, shorter); + } + Event::Start(Tag::Strong) => { + strong(parser, buffer, toc_builder, shorter); + } _ => {} } - shorter == false + shorter.is_fancy() } else { false } @@ -594,7 +691,7 @@ impl<'a> fmt::Display for Markdown<'a> { impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let MarkdownWithToc(md) = *self; - render(fmt, md, true, false) + render(fmt, md, true, MarkdownOutputStyle::Fancy) } } @@ -603,7 +700,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, false) + render(fmt, md, false, MarkdownOutputStyle::Fancy) } } @@ -660,7 +757,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { - use super::{LangString, Markdown, MarkdownHtml}; + use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle}; use super::plain_summary_line; use html::render::reset_ids; @@ -700,14 +797,14 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown)); + format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); assert_eq!(output, expect); reset_ids(true); } @@ -729,7 +826,7 @@ mod tests { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); assert_eq!(output, expect); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8c1416b80979..1fa348a1be4c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -1650,7 +1650,8 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin } else { format!("{}", &plain_summary_line(Some(s))) }; - write!(w, "
    {}
    ", Markdown(&markdown, false))?; + write!(w, "
    {}
    ", + Markdown(&markdown, MarkdownOutputStyle::Fancy))?; } Ok(()) } @@ -1683,7 +1684,8 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
    {}
    ", - Markdown(&format!("{}{}", md_render_assoc_item(item), s), false))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), + MarkdownOutputStyle::Fancy))?; } Ok(()) } @@ -1871,7 +1873,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value, true).to_string())), + docs = shorter(Some(&Markdown(doc_value, + MarkdownOutputStyle::Compact).to_string())), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2901,7 +2904,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "
    ")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
    {}
    ", Markdown(dox, false))?; + write!(w, "
    {}
    ", Markdown(dox, MarkdownOutputStyle::Fancy))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index a048750279e2..d29e98f8fe10 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; use html::markdown; -use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; +use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code}; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `%`. @@ -94,7 +94,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let rendered = if include_toc { format!("{}", MarkdownWithToc(text)) } else { - format!("{}", Markdown(text, false)) + format!("{}", Markdown(text, MarkdownOutputStyle::Fancy)) }; let err = write!( diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 2f4a38c16c1d..1d4f2c60d544 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc, false))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?, None => write!(output, "

    No description.

    \n")?, } From 6d470a9c4a41e97cf7b9d9ab2cc0045d7889d01f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 16:27:54 +0100 Subject: [PATCH 102/905] Add a macro to improve code --- src/librustdoc/html/markdown.rs | 156 ++++++++------------------------ 1 file changed, 39 insertions(+), 117 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e8c95c4a21c3..3cc95260e3bd 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -104,6 +104,25 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = RefCell::new(None) }); +macro_rules! event_loop_break { + ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $($end_event:pat)|*) => {{ + while let Some(event) = $parser.next() { + match event { + $($end_event)|* => break, + Event::Text(ref s) => { + $buf.push_str(s); + } + Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { + $buf.push(' '); + } + x => { + looper($parser, &mut $buf, Some(x), $toc_builder, $shorter); + } + } + } + }} +} + pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, @@ -186,21 +205,10 @@ pub fn render(w: &mut fmt::Formatter, }); } - fn header(parser: &mut Parser, level: i32, toc_builder: &mut Option, - buffer: &mut String) { + fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Header(_)) => break, - Event::Text(ref s) => { - ret.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !ret.is_empty() => { - ret.push(' '); - } - _ => {} - } - } + event_loop_break!(parser, toc_builder, shorter, ret, Event::End(Tag::Header(_))); ret = ret.trim_right().to_owned(); let id = ret.clone(); @@ -236,82 +244,35 @@ pub fn render(w: &mut fmt::Formatter, ret, lvl = level, id = id, sec = sec)); } - fn codespan(parser: &mut Parser, buffer: &mut String) { + fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Code) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - _ => {} - } - } - buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Code)); + buffer.push_str(&format!("{}", + Escape(&collapse_whitespace(content.trim_right())))); } fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String) { - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Link(_, _)) => break, - Event::Text(ref s) => { - title.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !title.is_empty() => { - title.push(' '); - } - x => { - looper(parser, &mut title, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, title, Event::End(Tag::Link(_, _))); buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Paragraph) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) | - Event::End(Tag::TableCell) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, + Event::End(Tag::TableHead) | + Event::End(Tag::Table(_)) | + Event::End(Tag::TableRow) | + Event::End(Tag::TableCell)); buffer.push_str(&format!("{}", content.trim())); } @@ -381,20 +342,7 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::BlockQuote) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } @@ -435,40 +383,14 @@ pub fn render(w: &mut fmt::Formatter, fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Emphasis) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Strong) => break, - Event::Text(ref s) => { - content.push_str(s); - } - Event::SoftBreak | Event::HardBreak if !content.is_empty() => { - content.push(' '); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); - } - } - } + event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Strong)); buffer.push_str(&format!("{}", content)); } @@ -480,10 +402,10 @@ pub fn render(w: &mut fmt::Formatter, block(parser, buffer, &*lang); } Event::Start(Tag::Header(level)) => { - header(parser, level, toc_builder, buffer); + header(parser, buffer, toc_builder, shorter, level); } Event::Start(Tag::Code) => { - codespan(parser, buffer); + codespan(parser, buffer, toc_builder, shorter); } Event::Start(Tag::Paragraph) => { paragraph(parser, buffer, toc_builder, shorter); From 6a2190c18e53398191c9d5d9f37c8bcef296402d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 16:37:35 +0100 Subject: [PATCH 103/905] Remove unneeded comment --- src/librustdoc/html/markdown.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 3cc95260e3bd..09006d9ef829 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -212,12 +212,6 @@ pub fn render(w: &mut fmt::Formatter, ret = ret.trim_right().to_owned(); let id = ret.clone(); - // Discard '', '' tags and some escaped characters, - // transform the contents of the header into a hyphenated string - // without non-alphanumeric characters other than '-' and '_'. - // - // This is a terrible hack working around how hoedown gives us rendered - // html for text rather than the raw text. let id = id.chars().filter_map(|c| { if c.is_alphanumeric() || c == '-' || c == '_' { if c.is_ascii() { From e51f3253beb60a011bfccc0c5a5eaf119993f175 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 11 Mar 2017 18:09:59 +0100 Subject: [PATCH 104/905] Handle html in markdown as well --- src/librustdoc/html/markdown.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 09006d9ef829..d823e2bc1f56 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -422,6 +422,9 @@ pub fn render(w: &mut fmt::Formatter, Event::Start(Tag::Strong) => { strong(parser, buffer, toc_builder, shorter); } + Event::Html(h) | Event::InlineHtml(h) => { + buffer.push_str(&*h); + } _ => {} } shorter.is_fancy() From 474cc0932536c3ade8609fabd9f8fd0c95fd65af Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 12 Mar 2017 20:28:36 +0100 Subject: [PATCH 105/905] Update pulldown version after fix merged --- src/Cargo.lock | 17 ++++++++++++++++- src/librustdoc/Cargo.toml | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 946818e7d208..11c40fd7cd6c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -68,6 +68,11 @@ name = "bitflags" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bootstrap" version = "0.0.0" @@ -358,6 +363,15 @@ dependencies = [ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pulldown-cmark" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "qemu-test-client" version = "0.1.0" @@ -773,7 +787,7 @@ dependencies = [ "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.0.0", - "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1005,6 +1019,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" +"checksum pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ba85e41d8537ec513bee33aecca3f0bceb53c239807faa09800b39017ab4a965" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index ff18daa7aa09..cd996c0ff3af 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -25,7 +25,7 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -pulldown-cmark = "0.0.8" +pulldown-cmark = "0.0.9" [build-dependencies] build_helper = { path = "../build_helper" } From e133821b8914e03dcc80a2ebcf35277d9f11681e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Mar 2017 01:05:21 +0100 Subject: [PATCH 106/905] Update to last pulldown version --- src/Cargo.lock | 62 +++++++++++++++++---------------------- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/lib.rs | 2 +- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 11c40fd7cd6c..e2965a100d55 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -8,7 +8,7 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -27,7 +27,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -65,12 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -80,7 +75,7 @@ dependencies = [ "build_helper 0.1.0", "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -109,12 +104,12 @@ version = "0.1.0" [[package]] name = "clap" -version = "2.21.1" +version = "2.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -127,7 +122,7 @@ name = "cmake" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -145,7 +140,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -193,7 +188,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -202,7 +197,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -220,7 +215,7 @@ version = "0.0.0" [[package]] name = "handlebars" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -277,9 +272,9 @@ name = "mdbook" version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -365,11 +360,10 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.0.9" +version = "0.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -397,7 +391,7 @@ name = "regex" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -430,7 +424,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -607,7 +601,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -783,11 +777,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.0.0", - "pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -834,7 +826,7 @@ dependencies = [ "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", @@ -994,19 +986,19 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -"checksum bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162" -"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" +"checksum clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e17a4a72ffea176f77d6e2db609c6c919ef221f23862c9915e687fb54d833485" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" +"checksum handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "663e1728d8037fb0d4e13bcd1b1909fb5d913690a9929eb385922df157c2ff8f" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" @@ -1018,8 +1010,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" +"checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" -"checksum pulldown-cmark 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ba85e41d8537ec513bee33aecca3f0bceb53c239807faa09800b39017ab4a965" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index cd996c0ff3af..52f5d99838dc 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -25,7 +25,7 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -pulldown-cmark = "0.0.9" +pulldown-cmark = { version = "0.0.14", default-features = false } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index efb51bdf471f..447d60018d91 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -9,7 +9,7 @@ // except according to those terms. #![crate_name = "rustdoc"] -#![unstable(feature = "rustdoc", issue = "27812")] +#![unstable(feature = "rustc_private", issue = "27812")] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", From cba67ad8012c63ddae8b4c540bbb6f70a93c8ddf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 24 Mar 2017 23:53:18 +0100 Subject: [PATCH 107/905] Add feature for rustdoc binary --- src/rustc/rustdoc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rustc/rustdoc.rs b/src/rustc/rustdoc.rs index 6fecd3a27a8a..ccedb9844bba 100644 --- a/src/rustc/rustdoc.rs +++ b/src/rustc/rustdoc.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(rustdoc)] +#![feature(rustc_private)] extern crate rustdoc; From 47e4abf47397438ca86e96ed3f848276dddd5738 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Mar 2017 01:48:33 +0100 Subject: [PATCH 108/905] Fix plain_summary_line function --- src/librustdoc/html/markdown.rs | 84 ++++++++++++++++++++------------- src/rustc/rustdoc.rs | 1 - 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index d823e2bc1f56..4d67e8b53299 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -106,11 +106,19 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = macro_rules! event_loop_break { ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $($end_event:pat)|*) => {{ + event_loop_break($parser, $toc_builder, $shorter, $buf, false, $($end_event:pat)|*); + }}; + ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, + $($end_event:pat)|*) => {{ while let Some(event) = $parser.next() { match event { $($end_event)|* => break, Event::Text(ref s) => { - $buf.push_str(s); + if $escape { + $buf.push_str(&escape(s)); + } else { + $buf.push_str(s); + } } Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { $buf.push(' '); @@ -127,6 +135,13 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { + fn escape(entry: &str) -> String { + entry.replace("<", "<") + .replace("'", "'") + .replace(">", ">") + .replace("&", "&") + } + fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { @@ -208,7 +223,7 @@ pub fn render(w: &mut fmt::Formatter, fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); - event_loop_break!(parser, toc_builder, shorter, ret, Event::End(Tag::Header(_))); + event_loop_break!(parser, toc_builder, shorter, ret, true, Event::End(Tag::Header(_))); ret = ret.trim_right().to_owned(); let id = ret.clone(); @@ -241,28 +256,28 @@ pub fn render(w: &mut fmt::Formatter, fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Code)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Code)); buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String) { - event_loop_break!(parser, toc_builder, shorter, title, Event::End(Tag::Link(_, _))); + event_loop_break!(parser, toc_builder, shorter, title, true, Event::End(Tag::Link(_, _))); buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Paragraph)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) | Event::End(Tag::TableRow) | @@ -336,7 +351,7 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::BlockQuote)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } @@ -347,7 +362,7 @@ pub fn render(w: &mut fmt::Formatter, match event { Event::End(Tag::Item) => break, Event::Text(ref s) => { - content.push_str(s); + content.push_str(&escape(s)); } x => { looper(parser, &mut content, Some(x), toc_builder, shorter); @@ -377,14 +392,14 @@ pub fn render(w: &mut fmt::Formatter, fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Emphasis)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, Event::End(Tag::Strong)); + event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Strong)); buffer.push_str(&format!("{}", content)); } @@ -644,9 +659,12 @@ pub fn plain_summary_line(md: &str) -> String { Event::Start(Tag::Link(_, ref t)) if !self.is_first => { (Some(t.as_ref().to_owned()), 1) } + Event::Start(Tag::Code) => (Some("`".to_owned()), 1), + Event::End(Tag::Code) => (Some("`".to_owned()), -1), + Event::Start(Tag::Header(_)) => (None, 1), Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), - Event::End(Tag::Paragraph) => (None, -1), + Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1), _ => (None, 0), }; if is_in > 0 || (is_in < 0 && self.is_in > 0) { @@ -728,17 +746,17 @@ mod tests { reset_ids(true); } - t("# Foo bar", "\n

    \ - Foo bar

    "); - t("## Foo-bar_baz qux", "\n

    Foo-bar_baz qux

    "); + t("# Foo bar", "

    \ + Foo bar

    "); + t("## Foo-bar_baz qux", "

    Foo-bar_baz qux

    "); t("### **Foo** *bar* baz!?!& -_qux_-%", - "\n

    \ - Foo \ + "

    \ + Foo \ bar baz!?!& -_qux_-%

    "); t("####**Foo?** & \\*bar?!* _`baz`_ ❀ #qux", - "\n

    \ - Foo? & *bar?!* \ + "

    \ + Foo? & *bar?!* \ baz ❀ #qux

    "); } @@ -750,18 +768,18 @@ mod tests { } let test = || { - t("# Example", "\n

    \ - Example

    "); - t("# Panics", "\n

    \ - Panics

    "); - t("# Example", "\n

    \ - Example

    "); - t("# Main", "\n

    \ - Main

    "); - t("# Example", "\n

    \ - Example

    "); - t("# Panics", "\n

    \ - Panics

    "); + t("# Example", "

    \ + Example

    "); + t("# Panics", "

    \ + Panics

    "); + t("# Example", "

    \ + Example

    "); + t("# Main", "

    \ + Main

    "); + t("# Example", "

    \ + Example

    "); + t("# Panics", "

    \ + Panics

    "); }; test(); reset_ids(true); @@ -789,7 +807,7 @@ mod tests { assert_eq!(output, expect); } - t("`Struct<'a, T>`", "

    Struct<'a, T>

    \n"); - t("Struct<'a, T>", "

    Struct<'a, T>

    \n"); + t("`Struct<'a, T>`", "

    Struct<'a, T>

    "); + t("Struct<'a, T>", "

    Struct<'a, T>

    "); } } diff --git a/src/rustc/rustdoc.rs b/src/rustc/rustdoc.rs index ccedb9844bba..a4f43c42623d 100644 --- a/src/rustc/rustdoc.rs +++ b/src/rustc/rustdoc.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustdoc)] #![feature(rustc_private)] extern crate rustdoc; From 286a51da9187971c2aa5bac89834f5be7cc96d86 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Mar 2017 19:07:52 +0100 Subject: [PATCH 109/905] Fix id generation --- src/Cargo.lock | 9 +-- src/librustdoc/html/markdown.rs | 98 +++++++++++++++++---------------- 2 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index e2965a100d55..a9021dc34e20 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -218,7 +218,7 @@ name = "handlebars" version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (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.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -243,7 +243,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -777,8 +777,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1001,7 +1002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "663e1728d8037fb0d4e13bcd1b1909fb5d913690a9929eb385922df157c2ff8f" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" +"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" "checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4d67e8b53299..e55f3fa91dcd 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -105,17 +105,20 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = }); macro_rules! event_loop_break { - ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $($end_event:pat)|*) => {{ - event_loop_break($parser, $toc_builder, $shorter, $buf, false, $($end_event:pat)|*); - }}; - ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, + ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr, $($end_event:pat)|*) => {{ + fn inner(id: &mut Option<&mut String>, s: &str) { + if let Some(ref mut id) = *id { + id.push_str(s); + } + } while let Some(event) = $parser.next() { match event { $($end_event)|* => break, Event::Text(ref s) => { + inner($id, s); if $escape { - $buf.push_str(&escape(s)); + $buf.push_str(&format!("{}", Escape(s))); } else { $buf.push_str(s); } @@ -124,7 +127,7 @@ macro_rules! event_loop_break { $buf.push(' '); } x => { - looper($parser, &mut $buf, Some(x), $toc_builder, $shorter); + looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); } } } @@ -135,13 +138,6 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { - fn escape(entry: &str) -> String { - entry.replace("<", "<") - .replace("'", "'") - .replace(">", ">") - .replace("&", "&") - } - fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { @@ -223,10 +219,11 @@ pub fn render(w: &mut fmt::Formatter, fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); - event_loop_break!(parser, toc_builder, shorter, ret, true, Event::End(Tag::Header(_))); + let mut id = String::new(); + event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), + Event::End(Tag::Header(_))); ret = ret.trim_right().to_owned(); - let id = ret.clone(); let id = id.chars().filter_map(|c| { if c.is_alphanumeric() || c == '-' || c == '_' { if c.is_ascii() { @@ -254,30 +251,33 @@ pub fn render(w: &mut fmt::Formatter, } fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Code)); + event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, url: &str, mut title: String) { - event_loop_break!(parser, toc_builder, shorter, title, true, Event::End(Tag::Link(_, _))); + shorter: MarkdownOutputStyle, url: &str, mut title: String, + id: &mut Option<&mut String>) { + event_loop_break!(parser, toc_builder, shorter, title, true, id, + Event::End(Tag::Link(_, _))); buffer.push_str(&format!("{}", url, title)); } fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Paragraph)); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, + event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) | Event::End(Tag::TableRow) | @@ -297,7 +297,7 @@ pub fn render(w: &mut fmt::Formatter, cell(parser, &mut content, toc_builder, shorter); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -314,7 +314,7 @@ pub fn render(w: &mut fmt::Formatter, cell(parser, &mut content, toc_builder, shorter); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -351,7 +351,8 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::BlockQuote)); + event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, + Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } @@ -362,10 +363,10 @@ pub fn render(w: &mut fmt::Formatter, match event { Event::End(Tag::Item) => break, Event::Text(ref s) => { - content.push_str(&escape(s)); + content.push_str(&format!("{}", Escape(s))); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -382,7 +383,7 @@ pub fn render(w: &mut fmt::Formatter, list_item(parser, &mut content, toc_builder, shorter); } x => { - looper(parser, &mut content, Some(x), toc_builder, shorter); + looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } } @@ -390,21 +391,24 @@ pub fn render(w: &mut fmt::Formatter, } fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Emphasis)); + event_loop_break!(parser, toc_builder, shorter, content, false, id, + Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, Event::End(Tag::Strong)); + event_loop_break!(parser, toc_builder, shorter, content, false, id, + Event::End(Tag::Strong)); buffer.push_str(&format!("{}", content)); } fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) -> bool { + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) -> bool { if let Some(event) = next_event { match event { Event::Start(Tag::CodeBlock(lang)) => { @@ -414,13 +418,13 @@ pub fn render(w: &mut fmt::Formatter, header(parser, buffer, toc_builder, shorter, level); } Event::Start(Tag::Code) => { - codespan(parser, buffer, toc_builder, shorter); + codespan(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Paragraph) => { - paragraph(parser, buffer, toc_builder, shorter); + paragraph(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned()); + link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); } Event::Start(Tag::Table(_)) => { table(parser, buffer, toc_builder, shorter); @@ -432,10 +436,10 @@ pub fn render(w: &mut fmt::Formatter, list(parser, buffer, toc_builder, shorter); } Event::Start(Tag::Emphasis) => { - emphasis(parser, buffer, toc_builder, shorter); + emphasis(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Strong) => { - strong(parser, buffer, toc_builder, shorter); + strong(parser, buffer, toc_builder, shorter, id); } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); @@ -457,7 +461,7 @@ pub fn render(w: &mut fmt::Formatter, let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); loop { let next_event = parser.next(); - if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter) { + if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { break } } @@ -742,7 +746,7 @@ mod tests { fn test_header() { fn t(input: &str, expect: &str) { let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -751,10 +755,10 @@ mod tests { t("## Foo-bar_baz qux", "

    Foo-bar_baz qux

    "); t("### **Foo** *bar* baz!?!& -_qux_-%", - "

    \ - Foo \ - bar baz!?!& -_qux_-%

    "); - t("####**Foo?** & \\*bar?!* _`baz`_ ❀ #qux", + "

    \ + Foo \ + bar baz!?!& -qux-%

    "); + t("#### **Foo?** & \\*bar?!* _`baz`_ ❀ #qux", "

    \ Foo? & *bar?!* \ baz ❀ #qux

    "); @@ -764,7 +768,7 @@ mod tests { fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } let test = || { @@ -790,7 +794,7 @@ mod tests { fn test_plain_summary_line() { fn t(input: &str, expect: &str) { let output = plain_summary_line(input); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); @@ -804,7 +808,7 @@ mod tests { fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let output = format!("{}", MarkdownHtml(input)); - assert_eq!(output, expect); + assert_eq!(output, expect, "original: {}", input); } t("`Struct<'a, T>`", "

    Struct<'a, T>

    "); From a7c6d3e16a71fc0dcce4c9be09d031d746f84a69 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 28 Mar 2017 11:54:11 -0600 Subject: [PATCH 110/905] Improve function naming --- src/librustdoc/html/markdown.rs | 45 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e55f3fa91dcd..117cfbabb52f 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -10,17 +10,16 @@ //! Markdown formatting for rustdoc //! -//! This module implements markdown formatting through the hoedown C-library -//! (bundled into the rust runtime). This module self-contains the C bindings -//! and necessary legwork to render markdown, and exposes all of the +//! This module implements markdown formatting through the pulldown-cmark +//! rust-library. This module exposes all of the //! functionality through a unit-struct, `Markdown`, which has an implementation //! of `fmt::Display`. Example usage: //! //! ```rust,ignore -//! use rustdoc::html::markdown::Markdown; +//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle}; //! //! let s = "My *markdown* _text_"; -//! let html = format!("{}", Markdown(s)); +//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy)); //! // ... something using html //! ``` @@ -138,7 +137,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { - fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { + fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -216,8 +215,8 @@ pub fn render(w: &mut fmt::Formatter, }); } - fn header(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, level: i32) { + fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -250,8 +249,8 @@ pub fn render(w: &mut fmt::Formatter, ret, lvl = level, id = id, sec = sec)); } - fn codespan(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", @@ -274,8 +273,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("

    {}

    ", content.trim_right())); } - fn cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -285,8 +284,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content.trim())); } - fn row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -294,7 +293,7 @@ pub fn render(w: &mut fmt::Formatter, Event::End(Tag::Table(_)) | Event::End(Tag::TableRow) => break, Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); + table_cell(parser, &mut content, toc_builder, shorter); } x => { looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); @@ -304,14 +303,14 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, Event::Start(Tag::TableCell) => { - cell(parser, &mut content, toc_builder, shorter); + table_cell(parser, &mut content, toc_builder, shorter); } x => { looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); @@ -331,10 +330,10 @@ pub fn render(w: &mut fmt::Formatter, match event { Event::End(Tag::Table(_)) => break, Event::Start(Tag::TableHead) => { - head(parser, &mut content, toc_builder, shorter); + table_head(parser, &mut content, toc_builder, shorter); } Event::Start(Tag::TableRow) => { - row(parser, &mut rows, toc_builder, shorter); + table_row(parser, &mut rows, toc_builder, shorter); } _ => {} } @@ -412,13 +411,13 @@ pub fn render(w: &mut fmt::Formatter, if let Some(event) = next_event { match event { Event::Start(Tag::CodeBlock(lang)) => { - block(parser, buffer, &*lang); + code_block(parser, buffer, &*lang); } Event::Start(Tag::Header(level)) => { - header(parser, buffer, toc_builder, shorter, level); + heading(parser, buffer, toc_builder, shorter, level); } Event::Start(Tag::Code) => { - codespan(parser, buffer, toc_builder, shorter, id); + inline_code(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Paragraph) => { paragraph(parser, buffer, toc_builder, shorter, id); From 1fea03548cc9ecba3010c9e75eea0ef533ea44c9 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Fri, 24 Mar 2017 03:50:32 -0700 Subject: [PATCH 111/905] Rustdoc: memoize `pub use`-reexported macros so they don't appear twice in docs --- src/librustdoc/visit_ast.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 279330769785..c89ec5bbe15b 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -21,7 +21,7 @@ use syntax_pos::Span; use rustc::hir::map as hir_map; use rustc::hir::def::Def; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::middle::cstore::LoadedMacro; use rustc::middle::privacy::AccessLevel; use rustc::util::nodemap::FxHashSet; @@ -48,6 +48,7 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> { inlining: bool, /// Is the current module and all of its parents public? inside_public_path: bool, + reexported_macros: FxHashSet, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -62,6 +63,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { view_item_stack: stack, inlining: false, inside_public_path: true, + reexported_macros: FxHashSet(), } } @@ -201,9 +203,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if let Some(exports) = self.cx.tcx.export_map.get(&id) { for export in exports { if let Def::Macro(def_id, ..) = export.def { - if def_id.krate == LOCAL_CRATE { + if def_id.krate == LOCAL_CRATE || self.reexported_macros.contains(&def_id) { continue // These are `krate.exported_macros`, handled in `self.visit()`. } + let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate); let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { LoadedMacro::MacroDef(macro_def) => macro_def, @@ -217,6 +220,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } else { unreachable!() }; + om.macros.push(Macro { def_id: def_id, attrs: def.attrs.clone().into(), @@ -263,6 +267,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { false } + debug!("maybe_inline_local def: {:?}", def); + let tcx = self.cx.tcx; if def == Def::Err { return false; @@ -274,6 +280,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || use_attrs.lists("doc").has_word("hidden"); + // Memoize the non-inlined `pub use`'d macros so we don't push an extra + // declaration in `visit_mod_contents()` + if !def_did.is_local() { + if let Def::Macro(did, _) = def { + if please_inline { return true } + debug!("memoizing non-inlined macro export: {:?}", def); + self.reexported_macros.insert(did); + return false; + } + } + // For cross-crate impl inlining we need to know whether items are // reachable in documentation - a previously nonreachable item can be // made reachable by cross-crate inlining which we're checking here. @@ -294,6 +311,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }, _ => {}, } + return false } From d8fc5b80b61f662dd0d63d236875ade5a3f1129c Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Tue, 28 Mar 2017 00:02:19 -0700 Subject: [PATCH 112/905] Rustdoc: test proper representation for `pub use` macros --- .../auxiliary/pub-use-extern-macros.rs | 30 ++++++++++++++++++ src/test/rustdoc/pub-use-extern-macros.rs | 31 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/pub-use-extern-macros.rs create mode 100644 src/test/rustdoc/pub-use-extern-macros.rs diff --git a/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs new file mode 100644 index 000000000000..70d174a149da --- /dev/null +++ b/src/test/rustdoc/auxiliary/pub-use-extern-macros.rs @@ -0,0 +1,30 @@ +// 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. +#![crate_name="macros"] + +#[macro_export] +macro_rules! foo { + () => {}; +} + +#[macro_export] +macro_rules! bar { + () => {}; +} + +#[macro_export] +macro_rules! baz { + () => {}; +} + +#[macro_export] +macro_rules! quux { + () => {}; +} diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs new file mode 100644 index 000000000000..3f8f6f9544e8 --- /dev/null +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -0,0 +1,31 @@ +// 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. + +// aux-build:pub-use-extern-macros.rs + +#![feature(use_extern_macros, macro_reexport)] + +// @has pub_use_extern_macros/macro.foo.html +// @!has pub_use_extern_macros/index.html 'pub use macros::foo;' +#[macro_reexport(foo)] extern crate macros; + +// @has pub_use_extern_macros/index.html 'pub use macros::bar;' +// @!has pub_use_extern_macros/macro.bar.html +pub use macros::bar; + +// @has pub_use_extern_macros/macro.baz.html +// @!has pub_use_extern_macros/index.html 'pub use macros::baz;' +#[doc(inline)] +pub use macros::baz; + +// @!has pub_use_extern_macros/macro.quux.html +// @!has pub_use_extern_macros/index.html 'pub use macros::quux;' +#[doc(hidden)] +pub use macros::quux; From 8206d0c54e149609617a1de57cad480bbad73970 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 28 Mar 2017 16:49:05 -0500 Subject: [PATCH 113/905] rustdoc: format fns like format rfc 39 --- src/librustdoc/html/format.rs | 36 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fc5507d4d555..3589cc8fac61 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -945,6 +945,10 @@ impl<'a> fmt::Display for Method<'a> { let mut args = String::new(); let mut args_plain = String::new(); for (i, input) in decl.inputs.values.iter().enumerate() { + if i == 0 { + args.push_str("
    "); + } + if let Some(selfty) = input.to_self() { match selfty { clean::SelfValue => { @@ -986,8 +990,8 @@ impl<'a> fmt::Display for Method<'a> { args_plain.push_str(&format!("{:#}", input.type_)); } if i + 1 < decl.inputs.values.len() { - args.push_str(","); - args_plain.push_str(","); + args.push(','); + args_plain.push(','); } } @@ -1003,27 +1007,19 @@ impl<'a> fmt::Display for Method<'a> { format!("{}", decl.output) }; - let mut output: String; - let plain: String; let pad = repeat(" ").take(indent).collect::(); - if arrow.is_empty() { - output = format!("({})", args); - plain = format!("{}({})", pad, args_plain); - } else { - output = format!("({args})
    {arrow}", args = args, arrow = arrow); - plain = format!("{pad}({args}){arrow}", - pad = pad, - args = args_plain, - arrow = arrow_plain); - } + let plain = format!("{pad}({args}){arrow}", + pad = pad, + args = args_plain, + arrow = arrow_plain); - if plain.len() > 80 { - let pad = repeat(" ").take(indent).collect::(); - let pad = format!("
    {}", pad); - output = output.replace("
    ", &pad); + let output = if plain.len() > 80 { + let pad = "
        "; + format!("({args}
    ){arrow}", args = args.replace("
    ", pad), arrow = arrow) } else { - output = output.replace("
    ", ""); - } + format!("({args}){arrow}", args = args.replace("
    ", ""), arrow = arrow) + }; + if f.alternate() { write!(f, "{}", output.replace("
    ", "\n")) } else { From 7efbb69b99cf6b88027b3ec0a3d12771703831e7 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 29 Mar 2017 01:18:39 +0200 Subject: [PATCH 114/905] Changed cmp::Reverse to unstable --- src/libcore/cmp.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 751932a6105a..a43c85328731 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -330,6 +330,7 @@ impl Ordering { /// Example usage: /// /// ``` +/// #![feature(reverse_cmp_key)] /// use std::cmp::Reverse; /// /// let mut v = vec![1, 2, 3, 4, 5, 6]; @@ -337,10 +338,10 @@ impl Ordering { /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` #[derive(PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.18.0")] +#[unstable(feature = "reverse_cmp_key", issue = "40720")] pub struct Reverse(pub T); -#[stable(feature = "rust1", since = "1.18.0")] +#[unstable(feature = "reverse_cmp_key", issue = "40720")] impl PartialOrd for Reverse { #[inline] fn partial_cmp(&self, other: &Reverse) -> Option { @@ -348,7 +349,7 @@ impl PartialOrd for Reverse { } } -#[stable(feature = "rust1", since = "1.18.0")] +#[unstable(feature = "reverse_cmp_key", issue = "40720")] impl Ord for Reverse { #[inline] fn cmp(&self, other: &Reverse) -> Ordering { From 1979f96549fc41b544d2bf05eb868f26941f2b25 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 16 Mar 2017 10:23:33 +0000 Subject: [PATCH 115/905] Move `syntax::ext::hygiene` to `syntax_pos::hygiene`. --- src/librustc/hir/map/def_collector.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/libsyntax/ast.rs | 10 +++++++++- src/libsyntax/ext/expand.rs | 6 +++--- src/libsyntax/ext/placeholders.rs | 4 ++-- src/libsyntax/lib.rs | 2 +- src/{libsyntax/ext => libsyntax_pos}/hygiene.rs | 13 ++++--------- src/libsyntax_pos/lib.rs | 3 +++ 8 files changed, 24 insertions(+), 18 deletions(-) rename src/{libsyntax/ext => libsyntax_pos}/hygiene.rs (95%) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cae358a303e0..afdb9059ea7c 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -92,7 +92,7 @@ impl<'a> DefCollector<'a> { fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) { if let Some(ref mut visit) = self.visit_macro_invoc { visit(MacroInvocationData { - mark: Mark::from_placeholder_id(id), + mark: id.placeholder_to_mark(), const_expr: const_expr, def_index: self.parent_def.unwrap(), }) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 86e0d0039d1a..a15431afc164 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -680,7 +680,7 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { - let mark = Mark::from_placeholder_id(id); + let mark = id.placeholder_to_mark(); self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark); let invocation = self.resolver.invocations[&mark]; invocation.module.set(self.resolver.current_module); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3dd4bdbd14dd..7e2b225193f6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,7 +20,7 @@ pub use util::ThinVec; use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; -use ext::hygiene::SyntaxContext; +use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; use ptr::P; use rustc_data_structures::indexed_vec; @@ -256,6 +256,14 @@ impl NodeId { pub fn as_u32(&self) -> u32 { self.0 } + + pub fn placeholder_from_mark(mark: Mark) -> Self { + NodeId(mark.as_u32()) + } + + pub fn placeholder_to_mark(self) -> Mark { + Mark::from_u32(self.0) + } } impl fmt::Display for NodeId { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 6abeb4b0b280..e258c51a3295 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, Block, Ident, PatKind, Path}; +use ast::{self, Block, Ident, NodeId, PatKind, Path}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; @@ -321,7 +321,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { let derives = derives.remove(&mark).unwrap_or_else(Vec::new); - placeholder_expander.add(mark.as_placeholder_id(), expansion, derives); + placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives); } } @@ -703,7 +703,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ..self.cx.current_expansion.clone() }, }); - placeholder(expansion_kind, mark.as_placeholder_id()) + placeholder(expansion_kind, NodeId::placeholder_from_mark(mark)) } fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 2d0994a7b78f..4fb138d506a8 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast; +use ast::{self, NodeId}; use codemap::{DUMMY_SP, dummy_spanned}; use ext::base::ExtCtxt; use ext::expand::{Expansion, ExpansionKind}; @@ -88,7 +88,7 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { let mut expansion = expansion.fold_with(self); if let Expansion::Items(mut items) = expansion { for derive in derives { - match self.remove(derive.as_placeholder_id()) { + match self.remove(NodeId::placeholder_from_mark(derive)) { Expansion::Items(derived_items) => items.extend(derived_items), _ => unreachable!(), } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 4c9a5d512af0..6c975f3fc402 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -136,12 +136,12 @@ pub mod print { } pub mod ext { + pub use syntax_pos::hygiene; pub mod base; pub mod build; pub mod derive; pub mod expand; pub mod placeholders; - pub mod hygiene; pub mod quote; pub mod source_util; diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax_pos/hygiene.rs similarity index 95% rename from src/libsyntax/ext/hygiene.rs rename to src/libsyntax_pos/hygiene.rs index 57f5ab73d370..feebbcd6f03b 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -15,7 +15,6 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 -use ast::NodeId; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; @@ -47,17 +46,13 @@ impl Mark { Mark(0) } - pub fn from_placeholder_id(id: NodeId) -> Self { - Mark(id.as_u32()) - } - - pub fn as_placeholder_id(self) -> NodeId { - NodeId::from_u32(self.0) - } - pub fn as_u32(self) -> u32 { self.0 } + + pub fn from_u32(raw: u32) -> Mark { + Mark(raw) + } } struct HygieneData { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 3808923e7728..1c9a05dadd15 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -23,6 +23,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] +#![feature(const_fn)] #![feature(custom_attribute)] #![allow(unused_attributes)] #![feature(rustc_private)] @@ -41,6 +42,8 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; extern crate serialize; extern crate serialize as rustc_serialize; // used by deriving +pub mod hygiene; + pub type FileName = String; /// Spans represent a region of code, used for error reporting. Positions in spans From 496996c2af6174cb83a65756249d289f315dff80 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 16 Mar 2017 10:31:36 +0000 Subject: [PATCH 116/905] Remove code in `syntax::codemap`. --- src/libsyntax/codemap.rs | 185 --------------------------------------- src/libsyntax_pos/lib.rs | 4 - 2 files changed, 189 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 0f4b844b0eac..388f3cb73235 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -409,101 +409,6 @@ impl CodeMap { hi.col.to_usize() + 1)).to_string() } - // Returns true if two spans have the same callee - // (Assumes the same ExpnFormat implies same callee) - fn match_callees(&self, sp_a: &Span, sp_b: &Span) -> bool { - let fmt_a = self - .with_expn_info(sp_a.expn_id, - |ei| ei.map(|ei| ei.callee.format.clone())); - - let fmt_b = self - .with_expn_info(sp_b.expn_id, - |ei| ei.map(|ei| ei.callee.format.clone())); - fmt_a == fmt_b - } - - /// Returns a formatted string showing the expansion chain of a span - /// - /// Spans are printed in the following format: - /// - /// filename:start_line:col: end_line:col - /// snippet - /// Callee: - /// Callee span - /// Callsite: - /// Callsite span - /// - /// Callees and callsites are printed recursively (if available, otherwise header - /// and span is omitted), expanding into their own callee/callsite spans. - /// Each layer of recursion has an increased indent, and snippets are truncated - /// to at most 50 characters. Finally, recursive calls to the same macro are squashed, - /// with '...' used to represent any number of recursive calls. - pub fn span_to_expanded_string(&self, sp: Span) -> String { - self.span_to_expanded_string_internal(sp, "") - } - - fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String { - let mut indent = indent.to_owned(); - let mut output = "".to_owned(); - let span_str = self.span_to_string(sp); - let mut span_snip = self.span_to_snippet(sp) - .unwrap_or("Snippet unavailable".to_owned()); - - // Truncate by code points - in worst case this will be more than 50 characters, - // but ensures at least 50 characters and respects byte boundaries. - let char_vec: Vec<(usize, char)> = span_snip.char_indices().collect(); - if char_vec.len() > 50 { - span_snip.truncate(char_vec[49].0); - span_snip.push_str("..."); - } - - output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip)); - - if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN { - return output; - } - - let mut callee = self.with_expn_info(sp.expn_id, - |ei| ei.and_then(|ei| ei.callee.span.clone())); - let mut callsite = self.with_expn_info(sp.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())); - - indent.push_str(" "); - let mut is_recursive = false; - - while callee.is_some() && self.match_callees(&sp, &callee.unwrap()) { - callee = self.with_expn_info(callee.unwrap().expn_id, - |ei| ei.and_then(|ei| ei.callee.span.clone())); - is_recursive = true; - } - if let Some(span) = callee { - output.push_str(&indent); - output.push_str("Callee:\n"); - if is_recursive { - output.push_str(&indent); - output.push_str("...\n"); - } - output.push_str(&(self.span_to_expanded_string_internal(span, &indent))); - } - - is_recursive = false; - while callsite.is_some() && self.match_callees(&sp, &callsite.unwrap()) { - callsite = self.with_expn_info(callsite.unwrap().expn_id, - |ei| ei.map(|ei| ei.call_site.clone())); - is_recursive = true; - } - if let Some(span) = callsite { - output.push_str(&indent); - output.push_str("Callsite:\n"); - if is_recursive { - output.push_str(&indent); - output.push_str("...\n"); - } - output.push_str(&(self.span_to_expanded_string_internal(span, &indent))); - } - output - } - /// Return the source span - this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(&self, sp: Span) -> Span { @@ -1069,59 +974,6 @@ mod tests { assert_eq!(sstr, "blork.rs:2:1: 2:12"); } - #[test] - fn t10() { - // Test span_to_expanded_string works in base case (no expansion) - let cm = init_code_map(); - let span = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - let sstr = cm.span_to_expanded_string(span); - assert_eq!(sstr, "blork.rs:1:1: 1:12\n`first line.`\n"); - - let span = Span { lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION }; - let sstr = cm.span_to_expanded_string(span); - assert_eq!(sstr, "blork.rs:2:1: 2:12\n`second line`\n"); - } - - #[test] - fn t11() { - // Test span_to_expanded_string works with expansion - let cm = init_code_map(); - let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - let format = ExpnFormat::MacroBang(keywords::Invalid.name()); - let callee = NameAndSpan { format: format, - allow_internal_unstable: false, - span: None }; - - let info = ExpnInfo { call_site: root, callee: callee }; - let id = cm.record_expansion(info); - let sp = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id }; - - let sstr = cm.span_to_expanded_string(sp); - assert_eq!(sstr, - "blork.rs:2:1: 2:12\n`second line`\n Callsite:\n \ - blork.rs:1:1: 1:12\n `first line.`\n"); - } - - /// Test merging two spans on the same line - #[test] - fn span_merging() { - let cm = CodeMap::new(); - let inputtext = "bbbb BB bb CCC\n"; - let selection1 = " ~~ \n"; - let selection2 = " ~~~\n"; - cm.new_filemap_and_lines("blork.rs", None, inputtext); - let span1 = span_from_selection(inputtext, selection1); - let span2 = span_from_selection(inputtext, selection2); - - if let Some(sp) = cm.merge_spans(span1, span2) { - let sstr = cm.span_to_expanded_string(sp); - assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n"); - } - else { - assert!(false); - } - } - /// Test failing to merge two spans on different lines #[test] fn span_merging_fail() { @@ -1221,41 +1073,4 @@ mod tests { let id_end = cm.record_expansion(info_end); Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end } } - - #[test] - fn t12() { - // Test span_to_expanded_string collapses recursive macros and handles - // recursive callsite and callee expansions - let cm = init_code_map(); - let end = init_expansion_chain(&cm); - let sstr = cm.span_to_expanded_string(end); - let res_str = -r"blork2.rs:2:1: 2:12 -`second line` - Callsite: - ... - blork2.rs:1:1: 1:12 - `first line.` - Callee: - blork.rs:2:1: 2:12 - `second line` - Callee: - blork.rs:1:1: 1:12 - `first line.` - Callsite: - blork.rs:1:1: 1:12 - `first line.` - Callsite: - ... - blork.rs:2:1: 2:12 - `second line` - Callee: - blork.rs:1:1: 1:12 - `first line.` - Callsite: - blork.rs:1:1: 1:12 - `first line.` -"; - assert_eq!(sstr, res_str); - } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1c9a05dadd15..1b62d62348bc 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -263,10 +263,6 @@ pub const NO_EXPANSION: ExpnId = ExpnId(!0); // For code appearing from the command line pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); -// For code generated by a procedural macro, without knowing which -// Used in `qquote!` -pub const PROC_EXPN: ExpnId = ExpnId(!2); - impl ExpnId { pub fn from_u32(id: u32) -> ExpnId { ExpnId(id) From ec7c0aece17c9a11bc2eca15b994355a161bf878 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 17 Mar 2017 04:04:41 +0000 Subject: [PATCH 117/905] Merge `ExpnId` and `SyntaxContext`. --- src/librustc/hir/lowering.rs | 7 +- src/librustc/hir/mod.rs | 5 +- src/librustc/ich/caching_codemap_view.rs | 4 - src/librustc/middle/region.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_driver/driver.rs | 4 +- src/librustc_errors/emitter.rs | 22 +- src/librustc_errors/lib.rs | 4 +- .../calculate_svh/svh_visitor.rs | 17 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_plugin/load.rs | 4 +- src/librustc_save_analysis/lib.rs | 7 +- src/librustc_save_analysis/span_utils.rs | 3 +- src/librustc_trans/asm.rs | 4 +- src/librustc_trans/back/write.rs | 6 +- src/librustc_trans/mir/mod.rs | 18 +- src/librustc_typeck/check/mod.rs | 5 +- src/libsyntax/ast.rs | 57 +--- src/libsyntax/codemap.rs | 291 +----------------- src/libsyntax/ext/base.rs | 74 ++--- src/libsyntax/ext/derive.rs | 50 +-- src/libsyntax/ext/expand.rs | 111 +++---- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 14 +- src/libsyntax/feature_gate.rs | 20 +- src/libsyntax/json.rs | 2 +- src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/parser.rs | 6 +- src/libsyntax/std_inject.rs | 21 +- src/libsyntax/test.rs | 21 +- src/libsyntax/test_snippet.rs | 2 +- src/libsyntax/tokenstream.rs | 16 +- src/libsyntax_ext/asm.rs | 12 +- src/libsyntax_ext/deriving/clone.rs | 2 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 12 +- src/libsyntax_ext/deriving/mod.rs | 34 +- src/libsyntax_ext/format.rs | 3 +- src/libsyntax_ext/proc_macro_registrar.rs | 6 +- src/libsyntax_pos/hygiene.rs | 94 +++++- src/libsyntax_pos/lib.rs | 101 ++++-- src/{libsyntax => libsyntax_pos}/symbol.rs | 57 +++- src/test/compile-fail-fulldeps/qquote.rs | 8 - src/test/run-fail-fulldeps/qquote.rs | 8 - src/test/run-pass-fulldeps/qquote.rs | 8 - 46 files changed, 456 insertions(+), 702 deletions(-) rename src/{libsyntax => libsyntax_pos}/symbol.rs (87%) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6ca0c971ea49..786145f3091d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -57,6 +57,7 @@ use std::mem; use syntax::attr; use syntax::ast::*; use syntax::errors; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::codemap::{self, respan, Spanned}; use syntax::std_inject; @@ -392,7 +393,8 @@ impl<'a> LoweringContext<'a> { } fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span { - span.expn_id = self.sess.codemap().record_expansion(codemap::ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(codemap::ExpnInfo { call_site: span, callee: codemap::NameAndSpan { format: codemap::CompilerDesugaring(Symbol::intern(reason)), @@ -400,6 +402,7 @@ impl<'a> LoweringContext<'a> { allow_internal_unstable: true, }, }); + span.ctxt = SyntaxContext::empty().apply_mark(mark); span } @@ -1986,7 +1989,7 @@ impl<'a> LoweringContext<'a> { volatile: asm.volatile, alignstack: asm.alignstack, dialect: asm.dialect, - expn_id: asm.expn_id, + ctxt: asm.ctxt, }; let outputs = asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f4f2f4cf9211..da7e71ac07d2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,11 +33,12 @@ use hir::def::Def; use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use syntax::abi::Abi; use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; +use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; @@ -1367,7 +1368,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// represents an argument in a function header diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index a71251eedf5d..1278d9f5171b 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -47,10 +47,6 @@ impl<'tcx> CachingCodemapView<'tcx> { } } - pub fn codemap(&self) -> &'tcx CodeMap { - self.codemap - } - pub fn byte_pos_to_line_and_col(&mut self, pos: BytePos) -> Option<(Rc, usize, BytePos)> { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index a19f15a9329f..0676075930dc 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -236,7 +236,7 @@ impl CodeExtent { // (This is the special case aluded to in the // doc-comment for this method) let stmt_span = blk.stmts[r.first_statement_index as usize].span; - Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id }) + Some(Span { lo: stmt_span.hi, hi: blk.span.hi, ctxt: stmt_span.ctxt }) } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4354ed6817ae..2b5ea61d4e85 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -467,7 +467,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) { - if self.sess.codemap().span_allows_unstable(span) { + if span.allows_unstable() { debug!("stability: \ skipping span={:?} since it is internal", span); return; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4873b21c5487..977382b33adf 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -580,7 +580,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate = time(time_passes, "crate injection", || { let alt_std_name = sess.opts.alt_std_name.clone(); - syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name) + syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name) }); let mut addl_plugins = Some(addl_plugins); @@ -798,7 +798,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { - syntax::ext::hygiene::reset_hygiene_data(); + syntax::ext::hygiene::clear_markings(); } Ok(ExpansionResult { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 431edb3c9bc4..367b85ac726d 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,7 +10,7 @@ use self::Destination::*; -use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; @@ -151,7 +151,7 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP { + if span_label.span == DUMMY_SP { continue; } let lo = cm.lookup_char_pos(span_label.span.lo); @@ -615,7 +615,7 @@ impl EmitterWriter { let mut max = 0; if let Some(ref cm) = self.cm { for primary_span in msp.primary_spans() { - if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP { + if primary_span != &DUMMY_SP { let hi = cm.lookup_char_pos(primary_span.hi); if hi.line > max { max = hi.line; @@ -623,7 +623,7 @@ impl EmitterWriter { } } for span_label in msp.span_labels() { - if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP { + if span_label.span != DUMMY_SP { let hi = cm.lookup_char_pos(span_label.span.hi); if hi.line > max { max = hi.line; @@ -659,20 +659,20 @@ impl EmitterWriter { // First, find all the spans in <*macros> and point instead at their use site for sp in span.primary_spans() { - if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) { + if *sp == DUMMY_SP { continue; } if cm.span_to_filename(sp.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp.clone()); + let v = sp.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp.clone(), use_site.call_site.clone())); } } - for trace in cm.macro_backtrace(sp.clone()).iter().rev() { + for trace in sp.macro_backtrace().iter().rev() { // Only show macro locations that are local // and display them like a span_note if let Some(def_site) = trace.def_site_span { - if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) { + if def_site == DUMMY_SP { continue; } // Check to make sure we're not in any <*macros> @@ -689,11 +689,11 @@ impl EmitterWriter { span.push_span_label(label_span, label_text); } for sp_label in span.span_labels() { - if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) { + if sp_label.span == DUMMY_SP { continue; } if cm.span_to_filename(sp_label.span.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp_label.span.clone()); + let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); } @@ -848,7 +848,7 @@ impl EmitterWriter { // Make sure our primary file comes first let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), msp.primary_span().as_ref()) { - if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { + if primary_span != &&DUMMY_SP { cm.lookup_char_pos(primary_span.lo) } else { emit_to_destination(&buffer.render(), level, &mut self.dst)?; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4c889dad8ca5..2efdaa57fba3 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -48,7 +48,6 @@ pub mod styled_buffer; mod lock; use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; -use syntax_pos::MacroBacktrace; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum RenderSpan { @@ -75,7 +74,6 @@ pub trait CodeMapper { fn span_to_lines(&self, sp: Span) -> FileLinesResult; fn span_to_string(&self, sp: Span) -> String; fn span_to_filename(&self, sp: Span) -> FileName; - fn macro_backtrace(&self, span: Span) -> Vec; fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option; } @@ -120,7 +118,7 @@ impl CodeSuggestion { let bounding_span = Span { lo: lo, hi: hi, - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; let lines = cm.span_to_lines(bounding_span).unwrap(); assert!(!lines.lines.is_empty()); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 210803c3f329..5401b371888e 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,9 +17,10 @@ use self::SawTraitOrImplItemComponent::*; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; use syntax::parse::token; use syntax::symbol::InternedString; -use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; +use syntax_pos::{Span, BytePos}; use syntax::tokenstream; use rustc::hir; use rustc::hir::*; @@ -92,10 +93,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let expn_kind = match span.expn_id { - NO_EXPANSION => SawSpanExpnKind::NoExpansion, - COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, - _ => SawSpanExpnKind::SomeExpansion, + let expn_kind = if span.ctxt == SyntaxContext::empty() { + SawSpanExpnKind::NoExpansion + } else { + SawSpanExpnKind::SomeExpansion }; let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); @@ -121,8 +122,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { saw.hash(self.st); if expn_kind == SawSpanExpnKind::SomeExpansion { - let call_site = self.codemap.codemap().source_callsite(span); - self.hash_span(call_site); + self.hash_span(span.source_callsite()); } } @@ -483,7 +483,6 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { #[derive(Clone, Copy, Hash, Eq, PartialEq)] enum SawSpanExpnKind { NoExpansion, - CommandLine, SomeExpansion, } @@ -501,7 +500,7 @@ impl<'a> Hash for StableInlineAsm<'a> { volatile, alignstack, dialect, - expn_id: _, // This is used for error reporting + ctxt: _, // This is used for error reporting } = *self.0; asm.as_str().hash(state); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ba42804c9262..9d236bd013c4 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } // This comes from a macro that has #[allow_internal_unstable]. - if self.tcx.sess.codemap().span_allows_unstable(self.span) { + if self.span.allows_unstable() { return; } @@ -805,7 +805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.def_id.is_local() && // this doesn't come from a macro that has #[allow_internal_unstable] - !self.tcx.sess.codemap().span_allows_unstable(self.span) + !self.span.allows_unstable() { let mut err = self.tcx.sess.struct_span_err(self.span, "const fns are an unstable feature"); diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index efe9963cecc7..e884f3bdbb12 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,7 +20,7 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax_pos::{Span, COMMAND_LINE_SP}; +use syntax_pos::{Span, DUMMY_SP}; /// Pointer to a registrar function. pub type PluginRegistrarFun = @@ -81,7 +81,7 @@ pub fn load_plugins(sess: &Session, if let Some(plugins) = addl_plugins { for plugin in plugins { - loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]); + loader.load_plugin(DUMMY_SP, &plugin, vec![]); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e5c04f6b61ec..fd6803e087a0 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -690,9 +690,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // Note we take care to use the source callsite/callee, to handle // nested expansions and ensure we only generate data for source-visible // macro uses. - let callsite = self.tcx.sess.codemap().source_callsite(span); - let callee = self.tcx.sess.codemap().source_callee(span); - let callee = option_try!(callee); + let callsite = span.source_callsite(); + let callee = option_try!(span.source_callee()); let callee_span = option_try!(callee.span); // Ignore attribute macros, their spans are usually mangled @@ -1013,5 +1012,5 @@ fn escape(s: String) -> String { // Helper function to determine if a span came from a // macro expansion or syntax extension. pub fn generated_code(span: Span) -> bool { - span.expn_id != NO_EXPANSION || span == DUMMY_SP + span.ctxt != NO_EXPANSION || span == DUMMY_SP } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 34402742e6c3..c19f805a2857 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -462,8 +462,7 @@ impl<'a> SpanUtils<'a> { // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root // callsite. This filters out macro internal variables and most malformed spans. - let span = self.sess.codemap().source_callsite(parent); - !(span.contains(parent)) + !parent.source_callsite().contains(parent) } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index b6195765b27c..3e270b7928eb 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -111,14 +111,14 @@ pub fn trans_inline_asm<'a, 'tcx>( bcx.store(v, val, None); } - // Store expn_id in a metadata node so we can map LLVM errors + // 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(bcx.ccx.llcx(), key.as_ptr() as *const c_char, key.len() as c_uint); - let val: llvm::ValueRef = C_i32(bcx.ccx, ia.expn_id.into_u32() as i32); + let val: llvm::ValueRef = C_i32(bcx.ccx, ia.ctxt.outer().as_u32() as i32); llvm::LLVMSetMetadata(r, kind, llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5a017e4fb8a9..ccb3f7ac882a 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -371,14 +371,14 @@ struct HandlerFreeVars<'a> { unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, msg: &'b str, cookie: c_uint) { - use syntax_pos::ExpnId; + use syntax::ext::hygiene::Mark; match cgcx.lto_ctxt { Some((sess, _)) => { - sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info { + match Mark::from_u32(cookie).expn_info() { Some(ei) => sess.span_err(ei.call_site, msg), None => sess.err(msg), - }); + }; } None => { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b6..21bbbea77d44 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -26,7 +26,7 @@ use monomorphize::{self, Instance}; use abi::FnType; use type_of; -use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; +use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; use syntax::symbol::keywords; use std::iter; @@ -124,24 +124,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // 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.expn_id == NO_EXPANSION || - source_info.span.expn_id == COMMAND_LINE_EXPN || - self.ccx.sess().opts.debugging_opts.debug_macros { - + if source_info.span.ctxt == NO_EXPANSION || + self.ccx.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 { - let cm = self.ccx.sess().codemap(); // 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 occurr // at the level above that. let mut span = source_info.span; - while span.expn_id != NO_EXPANSION && - span.expn_id != COMMAND_LINE_EXPN && - span.expn_id != self.mir.span.expn_id { - if let Some(callsite_span) = cm.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite_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; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c62fd486d45..b95e01f4ff60 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4161,12 +4161,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } if let Some(last_stmt) = extra_semi { - let original_span = original_sp(self.tcx.sess.codemap(), - last_stmt.span, blk.span); + let original_span = original_sp(last_stmt.span, blk.span); let span_semi = Span { lo: original_span.hi - BytePos(1), hi: original_span.hi, - expn_id: original_span.expn_id + ctxt: original_span.ctxt, }; err.span_help(span_semi, "consider removing this semicolon:"); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7e2b225193f6..a4bebd311ded 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -14,10 +14,10 @@ pub use self::TyParamBound::*; pub use self::UnsafeSource::*; pub use self::ViewPath_::*; pub use self::PathParameters::*; -pub use symbol::Symbol as Name; +pub use symbol::{Ident, Symbol as Name}; pub use util::ThinVec; -use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; +use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; @@ -27,61 +27,12 @@ use rustc_data_structures::indexed_vec; use symbol::{Symbol, keywords}; use tokenstream::{ThinTokenStream, TokenStream}; +use serialize::{self, Encoder, Decoder}; use std::collections::HashSet; use std::fmt; use std::rc::Rc; use std::u32; -use serialize::{self, Encodable, Decodable, Encoder, Decoder}; - -/// An identifier contains a Name (index into the interner -/// table) and a SyntaxContext to track renaming and -/// macro expansion per Flatt et al., "Macros That Work Together" -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Ident { - pub name: Symbol, - pub ctxt: SyntaxContext -} - -impl Ident { - pub const fn with_empty_ctxt(name: Name) -> Ident { - Ident { name: name, ctxt: SyntaxContext::empty() } - } - - /// Maps a string to an identifier with an empty syntax context. - pub fn from_str(s: &str) -> Ident { - Ident::with_empty_ctxt(Symbol::intern(s)) - } - - pub fn unhygienize(&self) -> Ident { - Ident { name: self.name, ctxt: SyntaxContext::empty() } - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{:?}", self.name, self.ctxt) - } -} - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.name, f) - } -} - -impl Encodable for Ident { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.name.encode(s) - } -} - -impl Decodable for Ident { - fn decode(d: &mut D) -> Result { - Ok(Ident::with_empty_ctxt(Name::decode(d)?)) - } -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, @@ -1445,7 +1396,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// An argument in a function header. diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 388f3cb73235..ba199eacb627 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -17,6 +17,8 @@ //! within the CodeMap, which upon request can be converted to line and column //! information, source code snippets, etc. +pub use syntax_pos::*; +pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan}; pub use self::ExpnFormat::*; use std::cell::RefCell; @@ -26,35 +28,21 @@ use std::rc::Rc; use std::env; use std::fs; use std::io::{self, Read}; -pub use syntax_pos::*; use errors::CodeMapper; -use ast::Name; - /// Return the span itself if it doesn't come from a macro expansion, /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_info` chain. -pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { - let call_site1 = cm.with_expn_info(sp.expn_id, |ei| ei.map(|ei| ei.call_site)); - let call_site2 = cm.with_expn_info(enclosing_sp.expn_id, |ei| ei.map(|ei| ei.call_site)); +pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { + let call_site1 = sp.ctxt.outer().expn_info().map(|ei| ei.call_site); + let call_site2 = enclosing_sp.ctxt.outer().expn_info().map(|ei| ei.call_site); match (call_site1, call_site2) { (None, _) => sp, (Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp, - (Some(call_site1), _) => original_sp(cm, call_site1, enclosing_sp), + (Some(call_site1), _) => original_sp(call_site1, enclosing_sp), } } -/// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] -pub enum ExpnFormat { - /// e.g. #[derive(...)] - MacroAttribute(Name), - /// e.g. `format!()` - MacroBang(Name), - /// Desugaring done by the compiler during HIR lowering. - CompilerDesugaring(Name) -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub struct Spanned { pub node: T, @@ -73,47 +61,6 @@ pub fn dummy_spanned(t: T) -> Spanned { respan(DUMMY_SP, t) } -#[derive(Clone, Hash, Debug)] -pub struct NameAndSpan { - /// The format with which the macro was invoked. - pub format: ExpnFormat, - /// Whether the macro is allowed to use #[unstable]/feature-gated - /// features internally without forcing the whole crate to opt-in - /// to them. - pub allow_internal_unstable: bool, - /// The span of the macro definition itself. The macro may not - /// have a sensible definition span (e.g. something defined - /// completely inside libsyntax) in which case this is None. - pub span: Option -} - -impl NameAndSpan { - pub fn name(&self) -> Name { - match self.format { - ExpnFormat::MacroAttribute(s) | - ExpnFormat::MacroBang(s) | - ExpnFormat::CompilerDesugaring(s) => s, - } - } -} - -/// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Hash, Debug)] -pub struct ExpnInfo { - /// The location of the actual macro invocation or syntax sugar , e.g. - /// `let x = foo!();` or `if let Some(y) = x {}` - /// - /// This may recursively refer to other macro invocations, e.g. if - /// `foo!()` invoked `bar!()` internally, and there was an - /// expression inside `bar!`; the call_site of the expression in - /// the expansion would point to the `bar!` invocation; that - /// call_site span would have its own ExpnInfo, with the call_site - /// pointing to the `foo!` invocation. - pub call_site: Span, - /// Information about the expansion. - pub callee: NameAndSpan -} - // _____________________________________________________________________________ // FileMap, MultiByteChar, FileName, FileLines // @@ -161,7 +108,6 @@ impl FileLoader for RealFileLoader { pub struct CodeMap { pub files: RefCell>>, - expansions: RefCell>, file_loader: Box } @@ -169,7 +115,6 @@ impl CodeMap { pub fn new() -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: Box::new(RealFileLoader) } } @@ -177,7 +122,6 @@ impl CodeMap { pub fn with_file_loader(file_loader: Box) -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: file_loader } } @@ -353,14 +297,14 @@ impl CodeMap { /// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If /// there are gaps between lhs and rhs, the resulting union will cross these gaps. /// For this to work, the spans have to be: - /// * the expn_id of both spans much match + /// * the ctxt of both spans much match /// * the lhs span needs to end on the same line the rhs span begins /// * the lhs span must start at or before the rhs span pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { use std::cmp; // make sure we're at the same expansion id - if sp_lhs.expn_id != sp_rhs.expn_id { + if sp_lhs.ctxt != sp_rhs.ctxt { return None; } @@ -383,7 +327,7 @@ impl CodeMap { Some(Span { lo: cmp::min(sp_lhs.lo, sp_rhs.lo), hi: cmp::max(sp_lhs.hi, sp_rhs.hi), - expn_id: sp_lhs.expn_id, + ctxt: sp_lhs.ctxt, }) } else { None @@ -391,10 +335,6 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { - if sp == COMMAND_LINE_SP { - return "".to_string(); - } - if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) { return "no-location".to_string(); } @@ -409,62 +349,6 @@ impl CodeMap { hi.col.to_usize() + 1)).to_string() } - /// Return the source span - this is either the supplied span, or the span for - /// the macro callsite that expanded to it. - pub fn source_callsite(&self, sp: Span) -> Span { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is the first callsite, which is also source-equivalent to the span. - let mut first = true; - while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN { - if let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return Span { expn_id: NO_EXPANSION, .. span }; - } - } - first = false; - span = callsite; - } - else { - break; - } - } - span - } - - /// Return the source callee. - /// - /// Returns None if the supplied span has no expansion trace, - /// else returns the NameAndSpan for the macro definition - /// corresponding to the source callsite. - pub fn source_callee(&self, sp: Span) -> Option { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is source-equivalent to the span, and the source callee is the first callee. - let mut first = true; - while let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - first = false; - if let Some(_) = self.with_expn_info(callsite.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite; - } - else { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - None - } - pub fn span_to_filename(&self, sp: Span) -> FileName { self.lookup_char_pos(sp.lo).file.name.to_string() } @@ -628,111 +512,9 @@ impl CodeMap { return a; } - pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId { - let mut expansions = self.expansions.borrow_mut(); - expansions.push(expn_info); - let len = expansions.len(); - if len > u32::max_value() as usize { - panic!("too many ExpnInfo's!"); - } - ExpnId(len as u32 - 1) - } - - pub fn with_expn_info(&self, id: ExpnId, f: F) -> T where - F: FnOnce(Option<&ExpnInfo>) -> T, - { - match id { - NO_EXPANSION | COMMAND_LINE_EXPN => f(None), - ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize])) - } - } - - /// Check if a span is "internal" to a macro in which #[unstable] - /// items can be used (that is, a macro marked with - /// `#[allow_internal_unstable]`). - pub fn span_allows_unstable(&self, span: Span) -> bool { - debug!("span_allows_unstable(span = {:?})", span); - let mut allows_unstable = false; - let mut expn_id = span.expn_id; - loop { - let quit = self.with_expn_info(expn_id, |expninfo| { - debug!("span_allows_unstable: expninfo = {:?}", expninfo); - expninfo.map_or(/* hit the top level */ true, |info| { - - let span_comes_from_this_expansion = - info.callee.span.map_or(span.source_equal(&info.call_site), |mac_span| { - mac_span.contains(span) - }); - - debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}", - (span.lo, span.hi), - (info.call_site.lo, info.call_site.hi), - info.callee.span.map(|x| (x.lo, x.hi))); - debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}", - span_comes_from_this_expansion, - info.callee.allow_internal_unstable); - if span_comes_from_this_expansion { - allows_unstable = info.callee.allow_internal_unstable; - // we've found the right place, stop looking - true - } else { - // not the right place, keep looking - expn_id = info.call_site.expn_id; - false - } - }) - }); - if quit { - break - } - } - debug!("span_allows_unstable? {}", allows_unstable); - allows_unstable - } - pub fn count_lines(&self) -> usize { self.files.borrow().iter().fold(0, |a, f| a + f.count_lines()) } - - pub fn macro_backtrace(&self, span: Span) -> Vec { - let mut prev_span = DUMMY_SP; - let mut span = span; - let mut result = vec![]; - loop { - let span_name_span = self.with_expn_info(span.expn_id, |expn_info| { - expn_info.map(|ei| { - let (pre, post) = match ei.callee.format { - MacroAttribute(..) => ("#[", "]"), - MacroBang(..) => ("", "!"), - CompilerDesugaring(..) => ("desugaring of `", "`"), - }; - let macro_decl_name = format!("{}{}{}", - pre, - ei.callee.name(), - post); - let def_site_span = ei.callee.span; - (ei.call_site, macro_decl_name, def_site_span) - }) - }); - - match span_name_span { - None => break, - Some((call_site, macro_decl_name, def_site_span)) => { - // Don't print recursive invocations - if !call_site.source_equal(&prev_span) { - result.push(MacroBacktrace { - call_site: call_site, - macro_decl_name: macro_decl_name, - def_site_span: def_site_span, - }); - } - prev_span = span; - span = call_site; - } - } - } - result - } } impl CodeMapper for CodeMap { @@ -748,9 +530,6 @@ impl CodeMapper for CodeMap { fn span_to_filename(&self, sp: Span) -> FileName { self.span_to_filename(sp) } - fn macro_backtrace(&self, span: Span) -> Vec { - self.macro_backtrace(span) - } fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { self.merge_spans(sp_lhs, sp_rhs) } @@ -763,7 +542,6 @@ impl CodeMapper for CodeMap { #[cfg(test)] mod tests { use super::*; - use symbol::keywords; use std::rc::Rc; #[test] @@ -912,7 +690,7 @@ mod tests { fn t7() { // Test span_to_lines for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let file_lines = cm.span_to_lines(span).unwrap(); assert_eq!(file_lines.file.name, "blork.rs"); @@ -928,7 +706,7 @@ mod tests { assert_eq!(input.len(), selection.len()); let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); - Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } + Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), ctxt: NO_EXPANSION } } /// Test span_to_snippet and span_to_lines for a span coverting 3 @@ -958,7 +736,7 @@ mod tests { fn t8() { // Test span_to_snippet for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let snippet = cm.span_to_snippet(span); assert_eq!(snippet, Ok("second line".to_string())); @@ -968,7 +746,7 @@ mod tests { fn t9() { // Test span_to_str for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let sstr = cm.span_to_string(span); assert_eq!(sstr, "blork.rs:2:1: 2:12"); @@ -1022,7 +800,7 @@ mod tests { let span = Span { lo: BytePos(lo as u32 + file.start_pos.0), hi: BytePos(hi as u32 + file.start_pos.0), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring); @@ -1032,45 +810,4 @@ mod tests { } } } - - fn init_expansion_chain(cm: &CodeMap) -> Span { - // Creates an expansion chain containing two recursive calls - // root -> expA -> expA -> expB -> expB -> end - let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - - let format_root = ExpnFormat::MacroBang(keywords::Invalid.name()); - let callee_root = NameAndSpan { format: format_root, - allow_internal_unstable: false, - span: Some(root) }; - - let info_a1 = ExpnInfo { call_site: root, callee: callee_root }; - let id_a1 = cm.record_expansion(info_a1); - let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 }; - - let format_a = ExpnFormat::MacroBang(keywords::As.name()); - let callee_a = NameAndSpan { format: format_a, - allow_internal_unstable: false, - span: Some(span_a1) }; - - let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() }; - let id_a2 = cm.record_expansion(info_a2); - let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 }; - - let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a }; - let id_b1 = cm.record_expansion(info_b1); - let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 }; - - let format_b = ExpnFormat::MacroBang(keywords::Box.name()); - let callee_b = NameAndSpan { format: format_b, - allow_internal_unstable: false, - span: None }; - - let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() }; - let id_b2 = cm.record_expansion(info_b2); - let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 }; - - let info_end = ExpnInfo { call_site: span_b2, callee: callee_b }; - let id_end = cm.record_expansion(info_end); - Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end } - } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dc7e7673eb03..a2d54b62ec65 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT use ast::{self, Attribute, Name, PatKind, MetaItem}; use attr::HasAttrs; -use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; -use syntax_pos::{Span, ExpnId, NO_EXPANSION}; -use errors::{DiagnosticBuilder, FatalError}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{Span, DUMMY_SP}; +use errors::DiagnosticBuilder; use ext::expand::{self, Expansion, Invocation}; -use ext::hygiene::Mark; +use ext::hygiene::{Mark, SyntaxContext}; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; @@ -56,6 +56,14 @@ impl HasAttrs for Annotatable { } impl Annotatable { + pub fn span(&self) -> Span { + match *self { + Annotatable::Item(ref item) => item.span, + Annotatable::TraitItem(ref trait_item) => trait_item.span, + Annotatable::ImplItem(ref impl_item) => impl_item.span, + } + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -602,7 +610,6 @@ pub struct ModuleData { pub struct ExpansionData { pub mark: Mark, pub depth: usize, - pub backtrace: ExpnId, pub module: Rc, pub directory_ownership: DirectoryOwnership, } @@ -633,7 +640,6 @@ impl<'a> ExtCtxt<'a> { current_expansion: ExpansionData { mark: Mark::root(), depth: 0, - backtrace: NO_EXPANSION, module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), directory_ownership: DirectoryOwnership::Owned, }, @@ -658,30 +664,30 @@ impl<'a> ExtCtxt<'a> { pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } pub fn call_site(&self) -> Span { - self.codemap().with_expn_info(self.backtrace(), |ei| match ei { + match self.current_expansion.mark.expn_info() { Some(expn_info) => expn_info.call_site, - None => self.bug("missing top span") - }) + None => DUMMY_SP, + } + } + pub fn backtrace(&self) -> SyntaxContext { + SyntaxContext::empty().apply_mark(self.current_expansion.mark) } - pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Span { - let mut expn_id = self.backtrace(); + let mut ctxt = self.backtrace(); let mut last_macro = None; loop { - if self.codemap().with_expn_info(expn_id, |info| { - info.map_or(None, |i| { - if i.callee.name() == "include" { - // Stop going up the backtrace once include! is encountered - return None; - } - expn_id = i.call_site.expn_id; - last_macro = Some(i.call_site); - return Some(()); - }) + if ctxt.outer().expn_info().map_or(None, |info| { + if info.callee.name() == "include" { + // Stop going up the backtrace once include! is encountered + return None; + } + ctxt = info.call_site.ctxt; + last_macro = Some(info.call_site); + return Some(()); }).is_none() { break } @@ -689,28 +695,6 @@ impl<'a> ExtCtxt<'a> { last_macro.expect("missing expansion backtrace") } - pub fn bt_push(&mut self, ei: ExpnInfo) { - if self.current_expansion.depth > self.ecfg.recursion_limit { - let suggested_limit = self.ecfg.recursion_limit * 2; - let mut err = self.struct_span_fatal(ei.call_site, - &format!("recursion limit reached while expanding the macro `{}`", - ei.callee.name())); - err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); - err.emit(); - panic!(FatalError); - } - - let mut call_site = ei.call_site; - call_site.expn_id = self.backtrace(); - self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo { - call_site: call_site, - callee: ei.callee - }); - } - pub fn bt_pop(&mut self) {} - pub fn struct_span_warn(&self, sp: Span, msg: &str) @@ -792,9 +776,9 @@ impl<'a> ExtCtxt<'a> { /// compilation on error, merely emits a non-fatal error and returns None. pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) -> Option> { - // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. + // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { - expr.span.expn_id = cx.backtrace(); + expr.span.ctxt = expr.span.ctxt.apply_mark(cx.current_expansion.mark); expr }); diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 1569d9f540b8..c79040424f61 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -9,13 +9,16 @@ // except according to those terms. use attr::HasAttrs; -use {ast, codemap}; +use ast; +use codemap::{ExpnInfo, NameAndSpan, ExpnFormat}; use ext::base::ExtCtxt; use ext::build::AstBuilder; use parse::parser::PathStyle; use symbol::Symbol; use syntax_pos::Span; +use std::collections::HashSet; + pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { @@ -41,36 +44,35 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec result } -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span +pub fn add_derived_markers(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T + where T: HasAttrs, +{ + let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned()); + for (i, path) in traits.iter().enumerate() { + if i > 0 { + pretty_name.push_str(", "); + } + pretty_name.push_str(&path.to_string()); + names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name); } -} + pretty_name.push(')'); -pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T { - let span = match traits.get(0) { - Some(path) => path.span, - None => return item, - }; + cx.current_expansion.mark.set_expn_info(ExpnInfo { + call_site: span, + callee: NameAndSpan { + format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), + span: None, + allow_internal_unstable: true, + }, + }); + let span = Span { ctxt: cx.backtrace(), ..span }; item.map_attrs(|mut attrs| { - if traits.iter().any(|path| *path == "PartialEq") && - traits.iter().any(|path| *path == "Eq") { - let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); + if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) { let meta = cx.meta_word(span, Symbol::intern("structural_match")); attrs.push(cx.attribute(span, meta)); } - if traits.iter().any(|path| *path == "Copy") && - traits.iter().any(|path| *path == "Clone") { - let span = allow_unstable(cx, span, "derive(Copy, Clone)"); + if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) { let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker")); attrs.push(cx.attribute(span, meta)); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e258c51a3295..1b3352f73ade 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,6 +13,7 @@ use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use config::{is_test_or_bench, StripUnconfigured}; +use errors::FatalError; use ext::base::*; use ext::derive::{add_derived_markers, collect_derives}; use ext::hygiene::Mark; @@ -27,7 +28,7 @@ use ptr::P; use std_inject; use symbol::Symbol; use symbol::keywords; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use tokenstream::TokenStream; use util::small_vector::SmallVector; use visit::Visitor; @@ -273,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = item .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = - add_derived_markers(&mut self.cx, &traits, item.clone()); + add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); for path in &traits { @@ -363,11 +364,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { - match invoc.kind { + let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), + }; + + if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { + let info = self.cx.current_expansion.mark.expn_info().unwrap(); + let suggested_limit = self.cx.ecfg.recursion_limit * 2; + let mut err = self.cx.struct_span_fatal(info.call_site, + &format!("recursion limit reached while expanding the macro `{}`", + info.callee.name())); + err.help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); + err.emit(); + panic!(FatalError); } + + result } fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { @@ -378,11 +394,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: attr.span, callee: NameAndSpan { format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: Some(attr.span), + span: None, allow_internal_unstable: false, } }); @@ -403,19 +419,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtension::AttrProcMacro(ref mac) => { let item_toks = stream_for_item(&item, &self.cx.parse_sess); - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: attr.span, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: None, - allow_internal_unstable: false, - }, - }), - ..attr.span - }; - - let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); + let span = Span { ctxt: self.cx.backtrace(), ..attr.span }; + let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks); self.parse_expansion(tok_result, kind, &attr.path, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { @@ -440,8 +445,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let path = &mac.node.path; let ident = ident.unwrap_or(keywords::Invalid.ident()); - let marked_tts = - noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); + let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark)); let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { @@ -451,7 +455,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -470,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -502,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -528,10 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - expanded.fold_with(&mut Marker { - mark: mark, - expn_id: Some(self.cx.backtrace()), - }) + expanded.fold_with(&mut Marker(mark)) } /// Expand a derive invocation. Returns the result of expansion. @@ -550,50 +551,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> { id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, }; - self.cx.bt_push(ExpnInfo { + let mut expn_info = ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroAttribute(pretty_name), span: None, allow_internal_unstable: false, } - }); + }; match *ext { SyntaxExtension::ProcMacroDerive(ref ext, _) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: false, - }, - }), - ..span - }; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this name: keywords::Invalid.name(), span: DUMMY_SP, node: ast::MetaItemKind::Word, }; - return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)); + kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)) } SyntaxExtension::BuiltinDerive(func) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: true, - }, - }), - ..span - }; + expn_info.callee.allow_internal_unstable = true; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let mut items = Vec::new(); func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); - return kind.expect_from_annotatables(items); + kind.expect_from_annotatables(items) } _ => { let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); @@ -753,10 +737,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { // Detect use of feature-gated or invalid attributes on macro invocations // since they will not be detected after macro expansion. fn check_attributes(&mut self, attrs: &[ast::Attribute]) { - let codemap = &self.cx.parse_sess.codemap(); let features = self.cx.ecfg.features.unwrap(); for attr in attrs.iter() { - feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features); + feature_gate::check_attribute(&attr, &self.cx.parse_sess, features); } } } @@ -1065,23 +1048,21 @@ impl<'feat> ExpansionConfig<'feat> { } } -// A Marker adds the given mark to the syntax context and -// sets spans' `expn_id` to the given expn_id (unless it is `None`). -struct Marker { mark: Mark, expn_id: Option } +// A Marker adds the given mark to the syntax context. +struct Marker(Mark); impl Folder for Marker { fn fold_ident(&mut self, mut ident: Ident) -> Ident { - ident.ctxt = ident.ctxt.apply_mark(self.mark); + ident.ctxt = ident.ctxt.apply_mark(self.0); ident } - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - noop_fold_mac(mac, self) - } fn new_span(&mut self, mut span: Span) -> Span { - if let Some(expn_id) = self.expn_id { - span.expn_id = expn_id; - } + span.ctxt = span.ctxt.apply_mark(self.0); span } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + noop_fold_mac(mac, self) + } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 39b92c7d007d..0103d6ea959d 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf { // NB: relative paths are resolved relative to the compilation unit if !arg.is_absolute() { - let callsite = cx.codemap().source_callsite(sp); + let callsite = sp.source_callsite(); let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite)); cu.pop(); cu.push(arg); diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index d56859d805c8..12e746e024d3 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -34,17 +34,19 @@ impl Delimited { } pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9d280a413e66..12d25ca4274f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -28,7 +28,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; -use codemap::{CodeMap, Spanned}; +use codemap::Spanned; use syntax_pos::Span; use errors::{DiagnosticBuilder, Handler, FatalError}; use visit::{self, FnKind, Visitor}; @@ -831,7 +831,7 @@ impl GatedCfg { pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) { + if !has_feature(features) && !self.span.allows_unstable() { let explain = format!("`cfg({})` is experimental and subject to change", cfg); emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); } @@ -841,7 +841,6 @@ impl GatedCfg { struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, - cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], } @@ -850,7 +849,7 @@ macro_rules! gate_feature_fn { let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain); let has_feature: bool = has_feature(&$cx.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !cx.cm.span_allows_unstable(span) { + if !has_feature && !span.allows_unstable() { emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain); } }} @@ -908,12 +907,8 @@ impl<'a> Context<'a> { } } -pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, - cm: &CodeMap, features: &Features) { - let cx = Context { - features: features, parse_sess: parse_sess, - cm: cm, plugin_attributes: &[] - }; +pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { + let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] }; cx.check_attribute(attr, true); } @@ -1016,7 +1011,7 @@ struct PostExpansionVisitor<'a> { macro_rules! gate_feature_post { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ let (cx, span) = ($cx, $span); - if !cx.context.cm.span_allows_unstable(span) { + if !span.allows_unstable() { gate_feature!(cx.context, $feature, span, $explain) } }} @@ -1096,7 +1091,7 @@ fn starts_with_digit(s: &str) -> bool { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - if !self.context.cm.span_allows_unstable(attr.span) { + if !attr.span.allows_unstable() { // check for gated attributes self.context.check_attribute(attr, false); } @@ -1530,7 +1525,6 @@ pub fn check_crate(krate: &ast::Crate, let ctx = Context { features: features, parse_sess: sess, - cm: sess.codemap(), plugin_attributes: plugin_attributes, }; visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index fd762552248b..dec1b7d1d87b 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -202,7 +202,7 @@ impl DiagnosticSpan { // backtrace ourselves, but the `macro_backtrace` helper makes // some decision, such as dropping some frames, and I don't // want to duplicate that logic here. - let backtrace = je.cm.macro_backtrace(span).into_iter(); + let backtrace = span.macro_backtrace().into_iter(); DiagnosticSpan::from_span_full(span, is_primary, label, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6c975f3fc402..86ee1c5336df 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -125,7 +125,7 @@ pub mod ptr; pub mod show_span; pub mod std_inject; pub mod str; -pub mod symbol; +pub use syntax_pos::symbol; pub mod test; pub mod tokenstream; pub mod visit; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43a9d8c5f787..e9eb4fbcc916 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5036,11 +5036,7 @@ impl<'a> Parser<'a> { the path:", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` - let sp = Span { - lo: start_span.lo, - hi: self.prev_span.hi, - expn_id: start_span.expn_id, - }; + let sp = start_span.to(self.prev_span); let mut err = self.span_fatal_help(sp, &msg, &suggestion); err.span_suggestion(path_span, &help_msg, format!("in {}", path)); err.emit(); // emit diagnostic, but continue with public visibility diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index c541df9230a6..c7820a15fb3d 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -10,29 +10,27 @@ use ast; use attr; +use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute}; -use parse::ParseSess; use ptr::P; use tokenstream::TokenStream; /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. /// The expanded code uses the unstable `#[prelude_import]` attribute. -fn ignored_span(sess: &ParseSess, sp: Span) -> Span { - let info = ExpnInfo { +fn ignored_span(sp: Span) -> Span { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("std_inject")), span: None, allow_internal_unstable: true, } - }; - let expn_id = sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + }); + Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp } } pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { @@ -45,10 +43,7 @@ pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { } } -pub fn maybe_inject_crates_ref(sess: &ParseSess, - mut krate: ast::Crate, - alt_std_name: Option) - -> ast::Crate { +pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { let name = match injected_crate_name(&krate) { Some(name) => name, None => return krate, @@ -67,7 +62,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, span: DUMMY_SP, })); - let span = ignored_span(sess, DUMMY_SP); + let span = ignored_span(DUMMY_SP); krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6fb6db9ca028..50380626d7f0 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -31,6 +31,7 @@ use entry::{self, EntryPointType}; use ext::base::{ExtCtxt, Resolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; +use ext::hygiene::{Mark, SyntaxContext}; use fold::Folder; use util::move_map::MoveMap; use fold; @@ -62,6 +63,7 @@ struct TestCtxt<'a> { testfns: Vec, reexport_test_harness_main: Option, is_test_crate: bool, + ctxt: SyntaxContext, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -275,6 +277,7 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); + let mark = Mark::fresh(); let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, @@ -284,15 +287,16 @@ fn generate_test_harness(sess: &ParseSess, reexport_test_harness_main: reexport_test_harness_main, is_test_crate: is_test_crate(&krate), toplevel_reexport: None, + ctxt: SyntaxContext::empty().apply_mark(mark), }; cx.ext_cx.crate_root = Some("std"); - cx.ext_cx.bt_push(ExpnInfo { + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("test")), span: None, - allow_internal_unstable: false, + allow_internal_unstable: true, } }); @@ -307,18 +311,7 @@ fn generate_test_harness(sess: &ParseSess, /// call to codemap's is_internal check. /// The expanded code calls some unstable functions in the test crate. fn ignored_span(cx: &TestCtxt, sp: Span) -> Span { - let info = ExpnInfo { - call_site: sp, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern("test")), - span: None, - allow_internal_unstable: true, - } - }; - let expn_id = cx.sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + Span { ctxt: cx.ctxt, ..sp } } #[derive(PartialEq)] diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index c6d6e6237f2e..c537a0ee1664 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -83,7 +83,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { Span { lo: BytePos(start as u32), hi: BytePos(end as u32), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index b75b3efda36c..86bfdebe42b0 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -56,18 +56,20 @@ impl Delimited { /// Returns the opening delimiter as a token tree. pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } /// Returns the closing delimiter as a token tree. pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } @@ -425,7 +427,7 @@ mod tests { Span { lo: BytePos(a), hi: BytePos(b), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 767ec94a0ce6..923e8072f434 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -13,7 +13,6 @@ use self::State::*; use syntax::ast; -use syntax::codemap; use syntax::ext::base; use syntax::ext::base::*; use syntax::feature_gate; @@ -240,15 +239,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, } } - let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: sp, - callee: codemap::NameAndSpan { - format: codemap::MacroBang(Symbol::intern("asm")), - span: None, - allow_internal_unstable: false, - }, - }); - MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::InlineAsm(P(ast::InlineAsm { @@ -260,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, volatile: volatile, alignstack: alignstack, dialect: dialect, - expn_id: expn_id, + ctxt: cx.backtrace(), })), span: sp, attrs: ast::ThinVec::new(), diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index d14b59d6c70e..1993d6ebe5b4 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -111,7 +111,7 @@ fn cs_clone_shallow(name: &str, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Clone)"); + let span = Span { ctxt: cx.backtrace(), ..span}; let assert_path = cx.path_all(span, true, cx.std_path(&["clone", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 6ab5987a159c..eef21492debc 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -58,7 +58,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Eq)"); + let span = Span { ctxt: cx.backtrace(), ..span }; let assert_path = cx.path_all(span, true, cx.std_path(&["cmp", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index a767716466cb..ec4cb815960d 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -66,8 +66,8 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), }; - // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), ..span }; + // We want to make sure we have the ctxt set so that we can use unstable methods + let span = Span { ctxt: cx.backtrace(), ..span }; let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); let builder = Ident::from_str("builder"); let builder_expr = cx.expr_ident(span, builder.clone()); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 48e7ff0d2437..1ff0fec1c96a 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -375,7 +375,7 @@ fn find_type_parameters(ty: &ast::Ty, } fn visit_mac(&mut self, mac: &ast::Mac) { - let span = Span { expn_id: self.span.expn_id, ..mac.span }; + let span = Span { ctxt: self.span.ctxt, ..mac.span }; self.cx.span_err(span, "`derive` cannot be used on items with type macros"); } } @@ -1458,7 +1458,7 @@ impl<'a> MethodDef<'a> { .iter() .map(|v| { let ident = v.node.name; - let sp = Span { expn_id: trait_.span.expn_id, ..v.span }; + let sp = Span { ctxt: trait_.span.ctxt, ..v.span }; let summary = trait_.summarise_struct(cx, &v.node.data); (ident, sp, summary) }) @@ -1478,7 +1478,7 @@ impl<'a> TraitDef<'a> { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); for field in struct_def.fields() { - let sp = Span { expn_id: self.span.expn_id, ..field.span }; + let sp = Span { ctxt: self.span.ctxt, ..field.span }; match field.ident { Some(ident) => named_idents.push((ident, sp)), _ => just_spans.push(sp), @@ -1523,7 +1523,7 @@ impl<'a> TraitDef<'a> { let mut paths = Vec::new(); let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = Span { expn_id: self.span.expn_id, ..struct_field.span }; + let sp = Span { ctxt: self.span.ctxt, ..struct_field.span }; let ident = cx.ident_of(&format!("{}_{}", prefix, i)); paths.push(codemap::Spanned { span: sp, @@ -1544,7 +1544,7 @@ impl<'a> TraitDef<'a> { cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); } codemap::Spanned { - span: Span { expn_id: self.span.expn_id, ..pat.span }, + span: Span { ctxt: self.span.ctxt, ..pat.span }, node: ast::FieldPat { ident: ident.unwrap(), pat: pat, @@ -1576,7 +1576,7 @@ impl<'a> TraitDef<'a> { mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; - let sp = Span { expn_id: self.span.expn_id, ..variant.span }; + let sp = Span { ctxt: self.span.ctxt, ..variant.span }; let variant_path = cx.path(sp, vec![enum_ident, variant_ident]); self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index b51591bf89d5..b2bb43e41ed9 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,9 +12,9 @@ use std::rc::Rc; use syntax::ast; -use syntax::codemap; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver}; use syntax::ext::build::AstBuilder; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -74,20 +74,6 @@ pub mod ord; pub mod generic; -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span - } -} - macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { pub fn is_builtin_trait(name: ast::Name) -> bool { @@ -177,15 +163,15 @@ fn call_intrinsic(cx: &ExtCtxt, intrinsic: &str, args: Vec>) -> P { - span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern("derive")), - span: Some(span), - allow_internal_unstable: true, - }, - }); - + if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable { + span.ctxt = cx.backtrace(); + } else { // Avoid instability errors with user defined curstom derives, cc #36316 + let mut info = cx.current_expansion.mark.expn_info().unwrap(); + info.callee.allow_internal_unstable = true; + let mark = Mark::fresh(); + mark.set_expn_info(info); + span.ctxt = SyntaxContext::empty().apply_mark(mark); + } let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index d2afa08cadaf..aeb5b1e0a532 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -641,10 +641,11 @@ impl<'a, 'b> Context<'a, 'b> { fn format_arg(ecx: &ExtCtxt, macsp: Span, - sp: Span, + mut sp: Span, ty: &ArgumentType, arg: P) -> P { + sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark); let trait_ = match *ty { Placeholder(ref tyname) => { match &tyname[..] { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 2d815b3f1bb7..bb89caab709b 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -17,6 +17,7 @@ use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::fold::Folder; use syntax::parse::ParseSess; use syntax::ptr::P; @@ -360,7 +361,8 @@ fn mk_registrar(cx: &mut ExtCtxt, custom_derives: &[ProcMacroDerive], custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef]) -> P { - let eid = cx.codemap().record_expansion(ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("proc_macro")), @@ -368,7 +370,7 @@ fn mk_registrar(cx: &mut ExtCtxt, allow_internal_unstable: true, } }); - let span = Span { expn_id: eid, ..DUMMY_SP }; + let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP }; let proc_macro = Ident::from_str("proc_macro"); let krate = cx.item(span, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index feebbcd6f03b..8a9ff647b3ea 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -15,12 +15,16 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 +use Span; +use symbol::Symbol; + +use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SyntaxContext(u32); #[derive(Copy, Clone)] @@ -36,8 +40,8 @@ pub struct Mark(u32); impl Mark { pub fn fresh() -> Self { HygieneData::with(|data| { - let next_mark = Mark(data.next_mark.0 + 1); - ::std::mem::replace(&mut data.next_mark, next_mark) + data.marks.push(None); + Mark(data.marks.len() as u32 - 1) }) } @@ -53,23 +57,31 @@ impl Mark { pub fn from_u32(raw: u32) -> Mark { Mark(raw) } + + pub fn expn_info(self) -> Option { + HygieneData::with(|data| data.marks[self.0 as usize].clone()) + } + + pub fn set_expn_info(self, info: ExpnInfo) { + HygieneData::with(|data| data.marks[self.0 as usize] = Some(info)) + } } struct HygieneData { + marks: Vec>, syntax_contexts: Vec, markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, - next_mark: Mark, } impl HygieneData { fn new() -> Self { HygieneData { + marks: vec![None], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), prev_ctxt: SyntaxContext::empty(), }], markings: HashMap::new(), - next_mark: Mark(1), } } @@ -81,8 +93,8 @@ impl HygieneData { } } -pub fn reset_hygiene_data() { - HygieneData::with(|data| *data = HygieneData::new()) +pub fn clear_markings() { + HygieneData::with(|data| data.markings = HashMap::new()); } impl SyntaxContext { @@ -113,6 +125,10 @@ impl SyntaxContext { }) }) } + + pub fn outer(self) -> Mark { + HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark) + } } impl fmt::Debug for SyntaxContext { @@ -120,3 +136,67 @@ impl fmt::Debug for SyntaxContext { write!(f, "#{}", self.0) } } + +/// Extra information for tracking spans of macro and syntax sugar expansion +#[derive(Clone, Hash, Debug)] +pub struct ExpnInfo { + /// The location of the actual macro invocation or syntax sugar , e.g. + /// `let x = foo!();` or `if let Some(y) = x {}` + /// + /// This may recursively refer to other macro invocations, e.g. if + /// `foo!()` invoked `bar!()` internally, and there was an + /// expression inside `bar!`; the call_site of the expression in + /// the expansion would point to the `bar!` invocation; that + /// call_site span would have its own ExpnInfo, with the call_site + /// pointing to the `foo!` invocation. + pub call_site: Span, + /// Information about the expansion. + pub callee: NameAndSpan +} + +#[derive(Clone, Hash, Debug)] +pub struct NameAndSpan { + /// The format with which the macro was invoked. + pub format: ExpnFormat, + /// Whether the macro is allowed to use #[unstable]/feature-gated + /// features internally without forcing the whole crate to opt-in + /// to them. + pub allow_internal_unstable: bool, + /// The span of the macro definition itself. The macro may not + /// have a sensible definition span (e.g. something defined + /// completely inside libsyntax) in which case this is None. + pub span: Option +} + +impl NameAndSpan { + pub fn name(&self) -> Symbol { + match self.format { + ExpnFormat::MacroAttribute(s) | + ExpnFormat::MacroBang(s) | + ExpnFormat::CompilerDesugaring(s) => s, + } + } +} + +/// The source of expansion. +#[derive(Clone, Hash, Debug, PartialEq, Eq)] +pub enum ExpnFormat { + /// e.g. #[derive(...)] + MacroAttribute(Symbol), + /// e.g. `format!()` + MacroBang(Symbol), + /// Desugaring done by the compiler during HIR lowering. + CompilerDesugaring(Symbol) +} + +impl Encodable for SyntaxContext { + fn encode(&self, _: &mut E) -> Result<(), E::Error> { + Ok(()) // FIXME(jseyfried) intercrate hygiene + } +} + +impl Decodable for SyntaxContext { + fn decode(_: &mut D) -> Result { + Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene + } +} diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1b62d62348bc..9b45e364ecf3 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -25,6 +25,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] @@ -43,6 +44,9 @@ extern crate serialize; extern crate serialize as rustc_serialize; // used by deriving pub mod hygiene; +pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan}; + +pub mod symbol; pub type FileName = String; @@ -60,7 +64,7 @@ pub struct Span { pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. - pub expn_id: ExpnId + pub ctxt: SyntaxContext, } /// A collection of spans. Spans have two orthogonal attributes: @@ -79,7 +83,7 @@ impl Span { /// Returns a new span representing just the end-point of this span pub fn end_point(self) -> Span { let lo = cmp::max(self.hi.0 - 1, self.lo.0); - Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} + Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. @@ -107,6 +111,69 @@ impl Span { None } } + + /// Return the source span - this is either the supplied span, or the span for + /// the macro callsite that expanded to it. + pub fn source_callsite(self) -> Span { + self.ctxt.outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) + } + + /// Return the source callee. + /// + /// Returns None if the supplied span has no expansion trace, + /// else returns the NameAndSpan for the macro definition + /// corresponding to the source callsite. + pub fn source_callee(self) -> Option { + fn source_callee(info: ExpnInfo) -> NameAndSpan { + match info.call_site.ctxt.outer().expn_info() { + Some(info) => source_callee(info), + None => info.callee, + } + } + self.ctxt.outer().expn_info().map(source_callee) + } + + /// Check if a span is "internal" to a macro in which #[unstable] + /// items can be used (that is, a macro marked with + /// `#[allow_internal_unstable]`). + pub fn allows_unstable(&self) -> bool { + match self.ctxt.outer().expn_info() { + Some(info) => info.callee.allow_internal_unstable, + None => false, + } + } + + pub fn macro_backtrace(mut self) -> Vec { + let mut prev_span = DUMMY_SP; + let mut result = vec![]; + loop { + let info = match self.ctxt.outer().expn_info() { + Some(info) => info, + None => break, + }; + + let (pre, post) = match info.callee.format { + ExpnFormat::MacroAttribute(..) => ("#[", "]"), + ExpnFormat::MacroBang(..) => ("", "!"), + ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), + }; + let macro_decl_name = format!("{}{}{}", pre, info.callee.name(), post); + let def_site_span = info.callee.span; + + // Don't print recursive invocations + if !info.call_site.source_equal(&prev_span) { + result.push(MacroBacktrace { + call_site: info.call_site, + macro_decl_name: macro_decl_name, + def_site_span: def_site_span, + }); + } + + prev_span = self; + self = info.call_site; + } + result + } } #[derive(Clone, Debug)] @@ -147,8 +214,8 @@ impl serialize::UseSpecializedDecodable for Span { } fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", - span.lo, span.hi, span.expn_id) + write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}", + span.lo, span.hi, span.ctxt) } impl fmt::Debug for Span { @@ -157,12 +224,7 @@ impl fmt::Debug for Span { } } -pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; - -// Generic span to be used for code originating from the command line -pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0), - hi: BytePos(0), - expn_id: COMMAND_LINE_EXPN }; +pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), ctxt: NO_EXPANSION }; impl MultiSpan { pub fn new() -> MultiSpan { @@ -256,22 +318,7 @@ impl From for MultiSpan { } } -#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)] -pub struct ExpnId(pub u32); - -pub const NO_EXPANSION: ExpnId = ExpnId(!0); -// For code appearing from the command line -pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); - -impl ExpnId { - pub fn from_u32(id: u32) -> ExpnId { - ExpnId(id) - } - - pub fn into_u32(self) -> u32 { - self.0 - } -} +pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty(); /// Identifies an offset of a multi-byte character in a FileMap #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)] @@ -651,7 +698,7 @@ thread_local!(pub static SPAN_DEBUG: Cell fmt:: /* assuming that we're not in macro expansion */ pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span {lo: lo, hi: hi, expn_id: NO_EXPANSION} + Span {lo: lo, hi: hi, ctxt: NO_EXPANSION} } pub struct MacroBacktrace { diff --git a/src/libsyntax/symbol.rs b/src/libsyntax_pos/symbol.rs similarity index 87% rename from src/libsyntax/symbol.rs rename to src/libsyntax_pos/symbol.rs index 2acbeee426be..b866652c49f8 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -12,11 +12,58 @@ //! allows bidirectional lookup; i.e. given a value, one can easily find the //! type, and vice versa. +use hygiene::SyntaxContext; + use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct Ident { + pub name: Symbol, + pub ctxt: SyntaxContext, +} + +impl Ident { + pub const fn with_empty_ctxt(name: Symbol) -> Ident { + Ident { name: name, ctxt: SyntaxContext::empty() } + } + + /// Maps a string to an identifier with an empty syntax context. + pub fn from_str(string: &str) -> Ident { + Ident::with_empty_ctxt(Symbol::intern(string)) + } + + pub fn unhygienize(self) -> Ident { + Ident { name: self.name, ctxt: SyntaxContext::empty() } + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{:?}", self.name, self.ctxt) + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, f) + } +} + +impl Encodable for Ident { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.name.encode(s) + } +} + +impl Decodable for Ident { + fn decode(d: &mut D) -> Result { + Ok(Ident::with_empty_ctxt(Symbol::decode(d)?)) + } +} + /// A symbol is an interned or gensymed string. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Symbol(u32); @@ -128,19 +175,19 @@ macro_rules! declare_keywords {( $( ($index: expr, $konst: ident, $string: expr) )* ) => { pub mod keywords { - use ast; + use super::{Symbol, Ident}; #[derive(Clone, Copy, PartialEq, Eq)] pub struct Keyword { - ident: ast::Ident, + ident: Ident, } impl Keyword { - #[inline] pub fn ident(self) -> ast::Ident { self.ident } - #[inline] pub fn name(self) -> ast::Name { self.ident.name } + #[inline] pub fn ident(self) -> Ident { self.ident } + #[inline] pub fn name(self) -> Symbol { self.ident.name } } $( #[allow(non_upper_case_globals)] pub const $konst: Keyword = Keyword { - ident: ast::Ident::with_empty_ctxt(super::Symbol($index)) + ident: Ident::with_empty_ctxt(super::Symbol($index)) }; )* } diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index bd25561065be..272bf1150cac 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -27,14 +27,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23"); diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index d692bb519c14..5518ab47c2bd 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -30,14 +30,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23))); diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index b4ed57192ccf..4a8246ec429c 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -26,14 +26,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; macro_rules! check { From 0347ff58230af512c9521bdda7877b8bef9e9d34 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Thu, 23 Mar 2017 23:33:15 +0000 Subject: [PATCH 118/905] Attempt to cache git modules --- .travis.yml | 22 ++++++++++---- appveyor.yml | 4 ++- src/ci/docker/run.sh | 1 + src/ci/init_repo.sh | 71 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 7 deletions(-) create mode 100755 src/ci/init_repo.sh diff --git a/.travis.yml b/.travis.yml index b16957344ae1..51e4440d5874 100644 --- a/.travis.yml +++ b/.travis.yml @@ -133,13 +133,14 @@ before_script: script: - > if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then - echo skipping, not a full build; - elif [ "$TRAVIS_OS_NAME" = "osx" ]; then - travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && - stamp src/ci/run.sh; + echo skipping, not a full build else - travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && - stamp src/ci/docker/run.sh $IMAGE; + stamp src/ci/init_repo.sh . "$HOME/rustsrc" && + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + stamp src/ci/run.sh; + else + stamp src/ci/docker/run.sh $IMAGE; + fi fi after_success: @@ -157,13 +158,21 @@ after_failure: - cat /tmp/sccache.log # Save tagged docker images we created and load them if they're available +# Travis saves caches whether the build failed or not, nuke rustsrc if +# the failure was while updating it (as it may be in an bad state) +# https://github.com/travis-ci/travis-ci/issues/4472 before_cache: - docker history -q rust-ci | grep -v missing | xargs docker save | gzip > $HOME/docker/rust-ci.tar.gz + - if [ ! -f $HOME/rustsrc/cache_valid1 ]; then + echo "WARNING rustsrc cache was invalid when saving"; + rm -rf $HOME/rustsrc && mkdir $HOME/rustsrc; + fi before_install: - zcat $HOME/docker/rust-ci.tar.gz | docker load || true + - mkdir -p $HOME/rustsrc notifications: email: false @@ -171,6 +180,7 @@ notifications: cache: directories: - $HOME/docker + - $HOME/rustsrc before_deploy: - mkdir -p deploy/$TRAVIS_COMMIT diff --git a/appveyor.yml b/appveyor.yml index 0e7ebf12a2a9..48983513147e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -141,7 +141,8 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' + - mkdir C:\cache\rustsrc + - sh src/ci/init_repo.sh . /c/cache/rustsrc - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh @@ -150,6 +151,7 @@ on_failure: - cat %CD%/sccache.log cache: + - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c418d427b15b..71a4bfae3caf 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -57,6 +57,7 @@ exec docker \ --env DEPLOY_ALT=$DEPLOY_ALT \ --env LOCAL_USER_ID=`id -u` \ --volume "$HOME/.cargo:/cargo" \ + --volume "$HOME/rustsrc:$HOME/rustsrc" \ --privileged \ --rm \ rust-ci \ diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh new file mode 100755 index 000000000000..4e22907d9794 --- /dev/null +++ b/src/ci/init_repo.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# 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. + +set -o errexit +set -o pipefail +set -o nounset + +set -o xtrace + +ci_dir=$(cd $(dirname $0) && pwd) +. "$ci_dir/shared.sh" + +REPO_DIR="$1" +CACHE_DIR="$2" + +cache_src_dir="$CACHE_DIR/src" +# If the layout of the cache directory changes, bump the number here +# (and anywhere else this file is referenced) so the cache is wiped +cache_valid_file="$CACHE_DIR/cache_valid1" + +if [ ! -d "$REPO_DIR" -o ! -d "$REPO_DIR/.git" ]; then + echo "Error: $REPO_DIR does not exist or is not a git repo" + exit 1 +fi +cd $REPO_DIR +if [ ! -d "$CACHE_DIR" ]; then + echo "Error: $CACHE_DIR does not exist or is not an absolute path" + exit 1 +fi + +# Wipe the cache if it's not valid, or mark it as invalid while we update it +if [ ! -f "$cache_valid_file" ]; then + rm -rf "$CACHE_DIR" && mkdir "$CACHE_DIR" +else + rm "$cache_valid_file" +fi + +# Update the cache (a pristine copy of the rust source master) +if [ ! -d "$cache_src_dir/.git" ]; then + retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \ + git clone https://github.com/rust-lang/rust.git $cache_src_dir" +fi +retry sh -c "cd $cache_src_dir && git reset --hard && git pull" +retry sh -c "cd $cache_src_dir && \ + git submodule deinit -f . && git submodule sync && git submodule update --init" + +# Cache was updated without errors, mark it as valid +touch "$cache_valid_file" + +# Update the submodules of the repo we're in, using the pristine repo as +# a cache for any object files +# No, `git submodule foreach` won't work: +# http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository +modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" +for module in $modules; do + if [ ! -d "$cache_src_dir/$module" ]; then + echo "WARNING: $module not found in pristine repo" + retry sh -c "git submodule deinit -f $module && git submodule update --init $module" + continue + fi + retry sh -c "git submodule deinit -f $module && \ + git submodule update --init --reference $cache_src_dir/$module $module" +done From 872d3bc0d713a85f2050f99d0cf33dd060318411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Mar 2017 14:54:15 -0700 Subject: [PATCH 119/905] Simplify labels and move tests to ui --- src/librustc_typeck/check/method/suggest.rs | 8 +- .../confuse-field-and-method}/issue-18343.rs | 2 +- .../issue-18343.stderr | 10 +++ .../confuse-field-and-method}/issue-2392.rs | 22 ++--- .../issue-2392.stderr | 90 +++++++++++++++++++ .../confuse-field-and-method}/issue-32128.rs | 2 +- .../issue-32128.stderr | 10 +++ .../confuse-field-and-method}/issue-33784.rs | 0 .../issue-33784.stderr | 26 ++++++ 9 files changed, 150 insertions(+), 20 deletions(-) rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-18343.rs (91%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-2392.rs (81%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-32128.rs (91%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-33784.rs (100%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b458c1af71d0..67ee7ef58653 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -202,19 +202,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { stored in the `{1}` field", expr_string, item_name)); - err.span_label(span, - &format!("`{}` is a field storing a \ - function, not a method", - item_name)); } else { err.help(&format!("did you mean to write `{0}.{1}` \ instead of `{0}.{1}(...)`?", expr_string, item_name)); - err.span_label(span, - &format!("`{}` is a field, not a method", - item_name)); } + err.span_label(span, &"field, not a method"); break; } } diff --git a/src/test/compile-fail/issue-18343.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs similarity index 91% rename from src/test/compile-fail/issue-18343.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs index a095bb481261..fc3c58e5223a 100644 --- a/src/test/compile-fail/issue-18343.rs +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.rs @@ -17,5 +17,5 @@ fn main() { o.closure(); //~^ ERROR no method named `closure` found //~| HELP use `(o.closure)(...)` if you meant to call the function stored in the `closure` field - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method } diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr new file mode 100644 index 000000000000..9e5e4adb180d --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr @@ -0,0 +1,10 @@ +error: no method named `closure` found for type `Obj<[closure@$DIR/issue-18343.rs:16:28: 16:33]>` in the current scope + --> $DIR/issue-18343.rs:17:7 + | +17 | o.closure(); + | ^^^^^^^ field, not a method + | + = help: use `(o.closure)(...)` if you meant to call the function stored in the `closure` field + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-2392.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs similarity index 81% rename from src/test/compile-fail/issue-2392.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs index 12389f885364..f84f35ce84bf 100644 --- a/src/test/compile-fail/issue-2392.rs +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.rs @@ -49,43 +49,43 @@ fn main() { let o_closure = Obj { closure: || 42, not_closure: 42 }; o_closure.closure(); //~ ERROR no method named `closure` found //~^ HELP use `(o_closure.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method o_closure.not_closure(); //~^ ERROR no method named `not_closure` found - //~| NOTE `not_closure` is a field, not a method + //~| NOTE field, not a method //~| HELP did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? let o_func = Obj { closure: func, not_closure: 5 }; o_func.closure(); //~ ERROR no method named `closure` found //~^ HELP use `(o_func.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method let boxed_fn = BoxedObj { boxed_closure: Box::new(func) }; boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found //~^ HELP use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored - //~| NOTE `boxed_closure` is a field storing a function, not a method + //~| NOTE field, not a method let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box u32> }; boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found //~^ HELP use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored - //~| NOTE `boxed_closure` is a field storing a function, not a method + //~| NOTE field, not a method // test expression writing in the notes let w = Wrapper { wrap: o_func }; w.wrap.closure();//~ ERROR no method named `closure` found //~^ HELP use `(w.wrap.closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method w.wrap.not_closure(); //~^ ERROR no method named `not_closure` found - //~| NOTE `not_closure` is a field, not a method + //~| NOTE field, not a method //~| HELP did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? check_expression().closure();//~ ERROR no method named `closure` found //~^ HELP use `(check_expression().closure)(...)` if you meant to call the function stored - //~| NOTE `closure` is a field storing a function, not a method + //~| NOTE field, not a method } impl FuncContainerOuter { @@ -93,13 +93,13 @@ impl FuncContainerOuter { unsafe { (*self.container).f1(1); //~ ERROR no method named `f1` found //~^ HELP use `((*self.container).f1)(...)` - //~| NOTE `f1` is a field storing a function, not a method + //~| NOTE field, not a method (*self.container).f2(1); //~ ERROR no method named `f2` found //~^ HELP use `((*self.container).f2)(...)` - //~| NOTE `f2` is a field storing a function, not a method + //~| NOTE field, not a method (*self.container).f3(1); //~ ERROR no method named `f3` found //~^ HELP use `((*self.container).f3)(...)` - //~| NOTE `f3` is a field storing a function, not a method + //~| NOTE field, not a method } } } diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr new file mode 100644 index 000000000000..56e1060bdb95 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr @@ -0,0 +1,90 @@ +error: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:49:36: 49:41]>` in the current scope + --> $DIR/issue-2392.rs:50:15 + | +50 | o_closure.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(o_closure.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:49:36: 49:41]>` in the current scope + --> $DIR/issue-2392.rs:54:15 + | +54 | o_closure.not_closure(); + | ^^^^^^^^^^^ field, not a method + | + = help: did you mean to write `o_closure.not_closure` instead of `o_closure.not_closure(...)`? + +error: no method named `closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:60:12 + | +60 | o_func.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(o_func.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `boxed_closure` found for type `BoxedObj` in the current scope + --> $DIR/issue-2392.rs:65:14 + | +65 | boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found + | ^^^^^^^^^^^^^ field, not a method + | + = help: use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field + +error: no method named `boxed_closure` found for type `BoxedObj` in the current scope + --> $DIR/issue-2392.rs:70:19 + | +70 | boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found + | ^^^^^^^^^^^^^ field, not a method + | + = help: use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored in the `boxed_closure` field + +error: no method named `closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:77:12 + | +77 | w.wrap.closure();//~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(w.wrap.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `not_closure` found for type `Obj u32 {func}>` in the current scope + --> $DIR/issue-2392.rs:81:12 + | +81 | w.wrap.not_closure(); + | ^^^^^^^^^^^ field, not a method + | + = help: did you mean to write `w.wrap.not_closure` instead of `w.wrap.not_closure(...)`? + +error: no method named `closure` found for type `Obj + 'static>>` in the current scope + --> $DIR/issue-2392.rs:86:24 + | +86 | check_expression().closure();//~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(check_expression().closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `f1` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:94:31 + | +94 | (*self.container).f1(1); //~ ERROR no method named `f1` found + | ^^ field, not a method + | + = help: use `((*self.container).f1)(...)` if you meant to call the function stored in the `f1` field + +error: no method named `f2` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:97:31 + | +97 | (*self.container).f2(1); //~ ERROR no method named `f2` found + | ^^ field, not a method + | + = help: use `((*self.container).f2)(...)` if you meant to call the function stored in the `f2` field + +error: no method named `f3` found for type `FuncContainer` in the current scope + --> $DIR/issue-2392.rs:100:31 + | +100 | (*self.container).f3(1); //~ ERROR no method named `f3` found + | ^^ field, not a method + | + = help: use `((*self.container).f3)(...)` if you meant to call the function stored in the `f3` field + +error: aborting due to 11 previous errors + diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs similarity index 91% rename from src/test/compile-fail/issue-32128.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs index 74fbb33296e4..2fd7dc246c20 100644 --- a/src/test/compile-fail/issue-32128.rs +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.rs @@ -22,6 +22,6 @@ fn main() { demo.example(1); //~^ ERROR no method named `example` //~| HELP use `(demo.example)(...)` - //~| NOTE `example` is a field storing a function, not a method + //~| NOTE field, not a method // (demo.example)(1); } diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr new file mode 100644 index 000000000000..0d2a895bad16 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr @@ -0,0 +1,10 @@ +error: no method named `example` found for type `Example` in the current scope + --> $DIR/issue-32128.rs:22:10 + | +22 | demo.example(1); + | ^^^^^^^ field, not a method + | + = help: use `(demo.example)(...)` if you meant to call the function stored in the `example` field + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-33784.rs b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs similarity index 100% rename from src/test/compile-fail/issue-33784.rs rename to src/test/ui/suggestions/confuse-field-and-method/issue-33784.rs diff --git a/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr new file mode 100644 index 000000000000..70d64e3ffa33 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr @@ -0,0 +1,26 @@ +error: no method named `closure` found for type `&Obj<[closure@$DIR/issue-33784.rs:35:43: 35:48]>` in the current scope + --> $DIR/issue-33784.rs:37:7 + | +37 | p.closure(); //~ ERROR no method named `closure` found + | ^^^^^^^ field, not a method + | + = help: use `(p.closure)(...)` if you meant to call the function stored in the `closure` field + +error: no method named `fn_ptr` found for type `&&Obj<[closure@$DIR/issue-33784.rs:35:43: 35:48]>` in the current scope + --> $DIR/issue-33784.rs:41:7 + | +41 | q.fn_ptr(); //~ ERROR no method named `fn_ptr` found + | ^^^^^^ field, not a method + | + = help: use `(q.fn_ptr)(...)` if you meant to call the function stored in the `fn_ptr` field + +error: no method named `c_fn_ptr` found for type `&D` in the current scope + --> $DIR/issue-33784.rs:46:7 + | +46 | s.c_fn_ptr(); //~ ERROR no method named `c_fn_ptr` found + | ^^^^^^^^ field, not a method + | + = help: use `(s.c_fn_ptr)(...)` if you meant to call the function stored in the `c_fn_ptr` field + +error: aborting due to 3 previous errors + From 2040daee472033ae5a0d369ae05bd07706595854 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 23 Mar 2017 23:05:30 -0400 Subject: [PATCH 120/905] Make the rustdoc sidebar white on `src` pages Fixes #40724 --- src/librustdoc/html/layout.rs | 4 ++-- src/librustdoc/html/static/rustdoc.css | 6 +++--- src/librustdoc/html/static/styles/main.css | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 06a816412969..d6033a69da78 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -54,7 +54,7 @@ r##" {favicon} {in_header} - + $DIR/macro_path_as_generic_bound.rs:17:6 | 17 | foo!(m::m2::A); - | -----^^^^^^^^-- - | | | - | | Use of undeclared type or module `m` - | in this macro invocation + | ^^^^^^^^ Use of undeclared type or module `m` error: cannot continue compilation due to previous error From 3783c44eac713028969ac3cbdad6f30a3dbbbf97 Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Wed, 29 Mar 2017 16:50:09 +0530 Subject: [PATCH 129/905] Fix typo in libcore/char.rs --- src/libcore/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 19e69ca296d8..b27c801cf89d 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -187,7 +187,7 @@ impl From for u32 { /// 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 hypen), +/// 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. /// From 950d669a981bed04dcf9d7c172f468c2fbd1d6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malo=20Jaffr=C3=A9?= Date: Wed, 29 Mar 2017 14:31:00 +0200 Subject: [PATCH 130/905] Remove unused feature from error index generator Remove feature `rustdoc`. --- src/tools/error_index_generator/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 1d4f2c60d544..5db2ad83a0a7 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_private, rustdoc)] +#![feature(rustc_private)] extern crate syntax; extern crate rustdoc; From 4ef554206c060eaa0eb75852a7a59e05478143a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malo=20Jaffr=C3=A9?= Date: Wed, 29 Mar 2017 15:38:47 +0200 Subject: [PATCH 131/905] Avoid linking to a moved page in rust.html --- src/doc/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rust.md b/src/doc/rust.md index 7f02260cd2cd..5008b228c5c8 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1,3 +1,3 @@ % The Rust Reference Manual -The manual has moved, and is now called [the reference](reference.html). +The manual has moved, and is now called [the reference](reference/index.html). From 022bae8a4a9254fbdb4217e86927809f0ad996d6 Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 29 Mar 2017 15:59:22 +0200 Subject: [PATCH 132/905] Add example to std::process::abort --- src/libstd/process.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d46cf7a26daf..32b52d1f77a0 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1056,6 +1056,19 @@ pub fn exit(code: i32) -> ! { /// will be run. If a clean shutdown is needed it is recommended to only call /// this function at a known point where there are no more destructors left /// to run. +/// +/// # Examples +/// ``` +/// use std::process; +/// +/// fn main() { +/// println!("aborting"); +/// +/// process::abort(); +/// +/// // execution never gets here +/// } +/// ``` #[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; From 3ac27c3e54f3f5477ea907246c872523f14ef6df Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 29 Mar 2017 16:19:23 +0200 Subject: [PATCH 133/905] adding /// --- src/libstd/process.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 32b52d1f77a0..83d34f71a70a 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1058,6 +1058,7 @@ pub fn exit(code: i32) -> ! { /// to run. /// /// # Examples +/// /// ``` /// use std::process; /// From 5a7e9ad64a160c9ebfb35969f2bdd1065bc154bb Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 29 Mar 2017 16:30:39 +0200 Subject: [PATCH 134/905] Removing trailing spaces --- src/libstd/process.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 83d34f71a70a..a86dba97f786 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1061,12 +1061,12 @@ pub fn exit(code: i32) -> ! { /// /// ``` /// use std::process; -/// +/// /// fn main() { /// println!("aborting"); -/// +/// /// process::abort(); -/// +/// /// // execution never gets here /// } /// ``` From c033942925baccfed375a75fa5e4c2a26fd7dcc5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 Mar 2017 12:22:38 -0700 Subject: [PATCH 135/905] rustbuild: Update bootstrap compiler Now that we've also updated cargo's release process this commit also changes the download location of Cargo from Cargos archives back to the static.r-l.o archives. This should ensure that the Cargo download is the exact Cargo paired with the rustc that we release. --- src/bootstrap/bootstrap.py | 17 +- src/bootstrap/channel.rs | 2 +- src/librustc/lib.rs | 1 - src/librustc_asan/lib.rs | 4 +- src/librustc_data_structures/lib.rs | 1 - src/librustc_incremental/lib.rs | 1 - src/librustc_lsan/lib.rs | 4 +- src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 3 +- src/librustc_msan/lib.rs | 4 +- src/librustc_privacy/lib.rs | 1 - src/librustc_trans/lib.rs | 1 - src/librustc_tsan/lib.rs | 4 +- src/librustc_typeck/lib.rs | 1 - src/stage0.txt | 3 +- src/tools/cargotest/lockfiles/iron-Cargo.lock | 375 +++++++++++------- src/tools/cargotest/main.rs | 2 +- src/tools/compiletest/src/main.rs | 1 - 18 files changed, 251 insertions(+), 175 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index b326f95e505f..d5bc6127a1e7 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -160,11 +160,8 @@ class RustBuild(object): def download_stage0(self): cache_dst = os.path.join(self.build_dir, "cache") rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date()) - cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev()) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) - if not os.path.exists(cargo_cache): - os.makedirs(cargo_cache) if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): @@ -195,15 +192,15 @@ class RustBuild(object): if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() - filename = "cargo-nightly-{}.tar.gz".format(self.build) - url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev() - tarball = os.path.join(cargo_cache, filename) + filename = "cargo-{}-{}.tar.gz".format(channel, self.build) + url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose) self.fix_executable(self.bin_root() + "/bin/cargo") with open(self.cargo_stamp(), 'w') as f: - f.write(self.stage0_cargo_rev()) + f.write(self.stage0_rustc_date()) def fix_executable(self, fname): # If we're on NixOS we need to change the path to the dynamic loader @@ -258,9 +255,6 @@ class RustBuild(object): print("warning: failed to call patchelf: %s" % e) return - def stage0_cargo_rev(self): - return self._cargo_rev - def stage0_rustc_date(self): return self._rustc_date @@ -283,7 +277,7 @@ class RustBuild(object): if not os.path.exists(self.cargo_stamp()) or self.clean: return True with open(self.cargo_stamp(), 'r') as f: - return self.stage0_cargo_rev() != f.read() + return self.stage0_rustc_date() != f.read() def bin_root(self): return os.path.join(self.build_dir, self.build, "stage0") @@ -578,7 +572,6 @@ def bootstrap(): data = stage0_data(rb.rust_root) rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) - rb._cargo_rev = data['cargo'] # Fetch/build the bootstrap rb.build = rb.build_triple() diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 2607ce412f10..a95bdcb3d260 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -23,7 +23,7 @@ use build_helper::output; use Build; // The version number -pub const CFG_RELEASE_NUM: &'static str = "1.17.0"; +pub const CFG_RELEASE_NUM: &'static str = "1.18.0"; // An optional number to put after the label, e.g. '.2' -> '-beta.2' // Be sure to make this starts with a dot to conform to semver pre-release diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c1c945d4e606..294f80d7d230 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,7 +29,6 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(i128_type)] #![feature(libc)] #![feature(loop_break_value)] diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index 71a166b91ebc..54941362e845 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 8ecfd75dc95a..9ccd95dd8d80 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -27,7 +27,6 @@ #![feature(shared)] #![feature(collections_range)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(nonzero)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 3b61cc1464a9..477777c975db 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -24,7 +24,6 @@ #![feature(rand)] #![feature(core_intrinsics)] #![feature(conservative_impl_trait)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![cfg_attr(stage0, feature(pub_restricted))] extern crate graphviz; diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs index 71a166b91ebc..54941362e845 100644 --- a/src/librustc_lsan/lib.rs +++ b/src/librustc_lsan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 0ce886ce9e9d..2fbdb8c0de67 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -20,7 +20,6 @@ #![feature(box_patterns)] #![feature(conservative_impl_trait)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(i128_type)] #![feature(proc_macro_internals)] #![feature(quote)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 590c6a430b98..8b55cdf06d20 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -23,7 +23,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(associated_consts)] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(i128_type)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -61,4 +60,4 @@ pub fn provide(providers: &mut Providers) { mir_map::provide(providers); shim::provide(providers); transform::qualify_consts::provide(providers); -} \ No newline at end of file +} diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs index 71a166b91ebc..54941362e845 100644 --- a/src/librustc_msan/lib.rs +++ b/src/librustc_msan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 64821f5d44bf..300848fe8f25 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,7 +17,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f3e30ed4839a..5c3b17c88976 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -28,7 +28,6 @@ #![feature(box_syntax)] #![feature(const_fn)] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(field_init_shorthand))] #![allow(unused_attributes)] #![feature(i128_type)] #![feature(libc)] diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs index 71a166b91ebc..54941362e845 100644 --- a/src/librustc_tsan/lib.rs +++ b/src/librustc_tsan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index df1c94dc19b5..4c772843afb2 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,7 +77,6 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(loop_break_value)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/stage0.txt b/src/stage0.txt index 772029ab0c25..60fbcadf4915 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,5 +12,4 @@ # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was # released on `$date` -rustc: beta-2017-02-01 -cargo: 407edef22e894266eb562618cba5ca9757051946 +rustc: beta-2017-03-21 diff --git a/src/tools/cargotest/lockfiles/iron-Cargo.lock b/src/tools/cargotest/lockfiles/iron-Cargo.lock index 843f2dcea512..3aa3883b701d 100644 --- a/src/tools/cargotest/lockfiles/iron-Cargo.lock +++ b/src/tools/cargotest/lockfiles/iron-Cargo.lock @@ -1,23 +1,38 @@ [root] name = "iron" -version = "0.3.0" +version = "0.5.1" dependencies = [ "conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "advapi32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "antidote" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" -version = "0.4.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -25,82 +40,104 @@ name = "conduit-mime-types" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "cookie" -version = "0.2.2" +name = "core-foundation" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "error" -version = "0.1.9" +name = "core-foundation-sys" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "traitobject 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crypt32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "gcc" -version = "0.3.26" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "gdi32-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hpack" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "httparse" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.8.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cookie 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-native-tls" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel32-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -111,41 +148,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.1.15" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.8" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libressl-pnacl-sys" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "matches" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mime" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -154,51 +180,52 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "num_cpus" -version = "0.2.11" +name = "native-tls" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl" -version = "0.7.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys-extras 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.7.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl-sys-extras" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pkg-config" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -210,24 +237,21 @@ dependencies = [ ] [[package]] -name = "pnacl-build-helper" -version = "1.4.10" +name = "rand" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand" -version = "0.3.14" +name = "redox_syscall" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rustc-serialize" -version = "0.3.18" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -238,46 +262,76 @@ dependencies = [ "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "schannel" +version = "0.1.4" +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)", + "crypt32-sys 0.2.0 (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 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "secur32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework-sys" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "semver" version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "solicit" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tempdir" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "traitobject" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "traitobject" -version = "0.0.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -303,15 +357,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-normalization" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -319,42 +373,30 @@ name = "unsafe-any" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "traitobject 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "url" -version = "0.5.7" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "user32-sys" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "uuid" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -362,3 +404,54 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[metadata] +"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" +"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8" +"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" +"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" +"checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" +"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" +"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" +"checksum httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e7a63e511f9edffbab707141fbb8707d1a3098615fb2adbd5769cdfcc9b17d" +"checksum hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "43a15e3273b2133aaac0150478ab443fb89f15c3de41d8d93d8f3bb14bf560f6" +"checksum hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afe68f772f0497a7205e751626bb8e1718568b58534b6108c73a74ef80483409" +"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" +"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" +"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" +"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" +"checksum mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5514f038123342d01ee5f95129e4ef1e0470c93bc29edf058a46f9ee3ba6737e" +"checksum modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58" +"checksum native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b805ee0e8fa268f67a4e5c7f4f80adb8af1fc4428ea0ce5b0ecab1430ef17ec0" +"checksum num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18c392466409c50b87369414a2680c93e739aedeb498eb2bff7d7eb569744e2" +"checksum openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8aa0eb7aad44f0da6f7dda13ddb4559d91a0f40cfab150b1f76ad5b39ec523f" +"checksum openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "14f5bfd12054d764510b887152d564ba11d99ae24ea7d740781778f646620576" +"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" +"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" +"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +"checksum schannel 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b291854e37196c2b67249e09d6bdeff410b19e1acf05558168e9c4413b4e95" +"checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" +"checksum security-framework 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2a8396fe671bb1f80fa3f4ff2aae0e968de16ef18d37a4e5e514771a1f07726e" +"checksum security-framework-sys 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "573b031c5f672b298cca566fac71aceea00e41bc925e75b5ec7b44dc7237180a" +"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" +"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" +"checksum time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "211b63c112206356ef1ff9b19355f43740fc3f85960c598a93d3a3d3ba7beade" +"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" +"checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764" +"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" +"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" +"checksum unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b351086021ebc264aea3ab4f94d61d889d98e5e9ec2d985d993f50133537fd3a" +"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" +"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 786b3192e067..c7113edbf9e6 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -31,7 +31,7 @@ const TEST_REPOS: &'static [Test] = &[ Test { name: "iron", repo: "https://github.com/iron/iron", - sha: "16c858ec2901e2992fe5e529780f59fa8ed12903", + sha: "21c7dae29c3c214c08533c2a55ac649b418f2fe3", lock: Some(include_str!("lockfiles/iron-Cargo.lock")), }, Test { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 657739c65b1f..09d21221a839 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -12,7 +12,6 @@ #![feature(box_syntax)] #![feature(rustc_private)] -#![feature(static_in_const)] #![feature(test)] #![feature(libc)] From 19b98f3027181a81d168f5f3648fa055ed862539 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Wed, 29 Mar 2017 13:21:31 -0400 Subject: [PATCH 136/905] Linked str in from_utf_unchecked --- src/libcore/str/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 0d66d0e93aa8..857eeb26af07 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -327,7 +327,9 @@ unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { /// /// This function is unsafe because it does not check that the bytes passed to /// it are valid UTF-8. If this constraint is violated, undefined behavior -/// results, as the rest of Rust assumes that `&str`s are valid UTF-8. +/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. +/// +/// [`&str`]: ../../std/primitive.str.html /// /// # Examples /// From 1eaa113581f39d41bc179e300d275cfaab91bd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Wed, 29 Mar 2017 20:43:01 +0200 Subject: [PATCH 137/905] Emit proper lifetime start intrinsics for personality slots We currently only emit a single call to the lifetime start intrinsic for the personality slot alloca. This happens because we create that call at the time that we create the alloca, instead of creating it each time we start using it. Because LLVM usually removes the alloca before the lifetime intrinsics are even considered, this didn't cause any problems yet, but we should fix this anyway. --- src/librustc_trans/mir/block.rs | 2 +- src/test/codegen/personality_lifetimes.rs | 39 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/personality_lifetimes.rs diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 226d40948c4d..d69f31a45048 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -762,7 +762,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); let slot = bcx.alloca(llretty, "personalityslot"); self.llpersonalityslot = Some(slot); - Lifetime::Start.call(bcx, slot); slot } } @@ -794,6 +793,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.llfn); bcx.set_cleanup(llretval); let slot = self.get_personality_slot(&bcx); + Lifetime::Start.call(&bcx, slot); bcx.store(llretval, slot, None); bcx.br(target_bb); bcx.llbb() diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs new file mode 100644 index 000000000000..1d07a2f10408 --- /dev/null +++ b/src/test/codegen/personality_lifetimes.rs @@ -0,0 +1,39 @@ +// 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: -O -C no-prepopulate-passes + +#![crate_type="lib"] + +struct S; + +impl Drop for S { + fn drop(&mut self) { + } +} + +fn might_unwind() { +} + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test() { + let _s = S; + // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just + // in the first one. + // CHECK-LABEL: cleanup: + // CHECK: bitcast{{.*}}personalityslot + // CHECK-NEXT: call void @llvm.lifetime.start + // CHECK-LABEL: cleanup1: + // CHECK: bitcast{{.*}}personalityslot + // CHECK-NEXT: call void @llvm.lifetime.start + might_unwind(); + might_unwind(); +} From 1e3bc5ac4fcacac584a39a061e9b1cffbcb9f713 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 29 Mar 2017 23:01:34 +0300 Subject: [PATCH 138/905] Allow using Vec::::place_back for T: !Clone The place_back was likely put into block with `T: Clone` bound by mistake. --- src/libcollections/vec.rs | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e0034..59186a2d5018 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -972,6 +972,29 @@ 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. /// @@ -1266,29 +1289,6 @@ impl Vec { pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) } - - /// 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 } - } } // Set the length of the vec when the `SetLenOnDrop` value goes out of scope. From b36cff5c4f9dd65cc48e7cc2f833dd4d6b449749 Mon Sep 17 00:00:00 2001 From: Camille TJHOA Date: Mon, 27 Mar 2017 22:42:29 +0200 Subject: [PATCH 139/905] Improve os::linux documentation (#29367) --- src/libstd/os/linux/fs.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index 11c41816cec8..7ebda5ed744f 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -34,36 +34,55 @@ pub trait MetadataExt { #[allow(deprecated)] fn as_raw_stat(&self) -> &raw::stat; + /// Returns the device ID on which this file resides. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; + /// Returns the inode number. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ino(&self) -> u64; + /// Returns the file type and mode. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_size(&self) -> u64; + /// Returns the last access time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; + /// Returns the last access time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; + /// Returns the last modification time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; + /// Returns the last status change time, nano seconds part. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" blocksize for efficient filesystem I/O. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; } From e3acebff66c89e2a50c8bfcd08fbe221265b30b0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 30 Mar 2017 12:14:04 +1300 Subject: [PATCH 140/905] save-analysis: track associated types --- src/librustc_save_analysis/dump_visitor.rs | 30 +++++++++++++++++++--- src/test/run-make/save-analysis/foo.rs | 17 ++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f2aa89ba4b66..7a7fa4eda05a 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1149,8 +1149,32 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &trait_item.attrs, trait_item.span); } - ast::TraitItemKind::Const(_, None) | - ast::TraitItemKind::Type(..) | + ast::TraitItemKind::Type(ref _bounds, ref default_ty) => { + // FIXME do something with _bounds (for type refs) + let name = trait_item.ident.name.to_string(); + let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); + let sub_span = self.span.sub_span_after_keyword(trait_item.span, keywords::Type); + + if !self.span.filter_generated(sub_span, trait_item.span) { + self.dumper.typedef(TypeDefData { + span: sub_span.expect("No span found for assoc type"), + name: name, + id: trait_item.id, + qualname: qualname, + value: self.span.snippet(trait_item.span), + visibility: Visibility::Public, + parent: Some(trait_id), + docs: docs_for_attrs(&trait_item.attrs), + sig: None, + attributes: trait_item.attrs.clone(), + }.lower(self.tcx)); + } + + if let &Some(ref default_ty) = default_ty { + self.visit_ty(default_ty) + } + } + ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty), ast::TraitItemKind::Macro(_) => {} } } @@ -1177,7 +1201,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &impl_item.attrs, impl_item.span); } - ast::ImplItemKind::Type(_) | + ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty), ast::ImplItemKind::Macro(_) => {} } } diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index e8b69729af67..3fe1479f5f2e 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -11,6 +11,7 @@ #![ crate_name = "test" ] #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(associated_type_defaults)] extern crate graphviz; // A simple rust project @@ -441,3 +442,19 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +struct FrameBuffer; + +struct SilenceGenerator; + +impl Iterator for SilenceGenerator { + type Item = FrameBuffer; + + fn next(&mut self) -> Option { + panic!(); + } +} + +trait Foo { + type Bar = FrameBuffer; +} From fe0fbbff5c67177e7e39869dc18c33e95bfcf0dc Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Thu, 30 Mar 2017 01:33:45 +0100 Subject: [PATCH 141/905] Disable appveyor cache --- appveyor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fa599a00c4de..68b2a239aff1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -141,8 +141,7 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - mkdir C:\cache\rustsrc - - sh src/ci/init_repo.sh . /c/cache/rustsrc + - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh @@ -151,7 +150,6 @@ on_failure: - cat %CD%/sccache.log cache: - - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" From 08a741eabf3c223650bb29c5df30c8fd414cd86a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 29 Mar 2017 19:48:06 -0600 Subject: [PATCH 142/905] Add support for image, rules and footnotes --- src/librustdoc/html/markdown.rs | 139 ++++++++++++++---- src/test/rustdoc/check-rule-image-footnote.rs | 35 +++++ 2 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 src/test/rustdoc/check-rule-image-footnote.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 117cfbabb52f..6c82dab94bcb 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -133,11 +133,37 @@ macro_rules! event_loop_break { }} } +struct ParserWrapper<'a> { + parser: Parser<'a>, + footnotes: Vec, + current_footnote_id: u16, +} + +impl<'a> ParserWrapper<'a> { + pub fn new(s: &'a str) -> ParserWrapper<'a> { + ParserWrapper { + parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | + pulldown_cmark::OPTION_ENABLE_FOOTNOTES), + footnotes: Vec::new(), + current_footnote_id: 1, + } + } + pub fn next(&mut self) -> Option> { + self.parser.next() + } + + pub fn get_next_footnote_id(&mut self) -> u16 { + let tmp = self.current_footnote_id; + self.current_footnote_id += 1; + tmp + } +} + pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { - fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) { + fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -215,8 +241,8 @@ pub fn render(w: &mut fmt::Formatter, }); } - fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, level: i32) { + fn heading(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -249,32 +275,48 @@ pub fn render(w: &mut fmt::Formatter, ret, lvl = level, id = id, sec = sec)); } - fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", Escape(&collapse_whitespace(content.trim_right())))); } - fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, url: &str, title: &str, + id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Link(_, _))); + if title.is_empty() { + buffer.push_str(&format!("{}", url, content)); + } else { + buffer.push_str(&format!("{}", + url, Escape(title), content)); + } + } + + fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String, id: &mut Option<&mut String>) { event_loop_break!(parser, toc_builder, shorter, title, true, id, - Event::End(Tag::Link(_, _))); - buffer.push_str(&format!("{}", url, title)); + Event::End(Tag::Image(_, _))); + buffer.push_str(&format!("\"{}\"", url, title)); } - fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Paragraph)); buffer.push_str(&format!("

    {}

    ", content.trim_right())); } - fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -284,8 +326,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content.trim())); } - fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_row(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -303,8 +345,8 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn table_head(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -322,7 +364,7 @@ pub fn render(w: &mut fmt::Formatter, } } - fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); let mut rows = String::new(); @@ -347,16 +389,16 @@ pub fn render(w: &mut fmt::Formatter, })); } - fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::BlockQuote)); buffer.push_str(&format!("
    {}
    ", content.trim_right())); } - fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + fn list_item(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -372,7 +414,7 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("
  • {}
  • ", content)); } - fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { let mut content = String::new(); while let Some(event) = parser.next() { @@ -389,15 +431,16 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("
      {}
    ", content)); } - fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Emphasis)); buffer.push_str(&format!("{}", content)); } - fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option, + fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, @@ -405,7 +448,23 @@ pub fn render(w: &mut fmt::Formatter, buffer.push_str(&format!("{}", content)); } - fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option>, + fn footnote(parser: &mut ParserWrapper, buffer: &mut String, + toc_builder: &mut Option, shorter: MarkdownOutputStyle, + mut definition: String, id: &mut Option<&mut String>) { + event_loop_break!(parser, toc_builder, shorter, definition, true, id, + Event::End(Tag::FootnoteDefinition(_))); + buffer.push_str(&definition); + } + + fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, + shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, + Event::End(Tag::Rule)); + buffer.push_str("
    "); + } + + fn looper<'a>(parser: &'a mut ParserWrapper, buffer: &mut String, next_event: Option>, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) -> bool { if let Some(event) = next_event { @@ -423,7 +482,10 @@ pub fn render(w: &mut fmt::Formatter, paragraph(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); + link(parser, buffer, toc_builder, shorter, url, t.as_ref(), id); + } + Event::Start(Tag::Image(ref url, ref t)) => { + image(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); } Event::Start(Tag::Table(_)) => { table(parser, buffer, toc_builder, shorter); @@ -440,6 +502,23 @@ pub fn render(w: &mut fmt::Formatter, Event::Start(Tag::Strong) => { strong(parser, buffer, toc_builder, shorter, id); } + Event::Start(Tag::Rule) => { + rule(parser, buffer, toc_builder, shorter, id); + } + Event::Start(Tag::FootnoteDefinition(ref def)) => { + let mut content = String::new(); + footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(), + id); + let cur_len = parser.footnotes.len() + 1; + parser.footnotes.push(format!("
  • {}↩
  • ", + cur_len, content)); + } + Event::FootnoteReference(_) => { + buffer.push_str(&format!("{0}\ + ", + parser.get_next_footnote_id())); + } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); } @@ -457,13 +536,17 @@ pub fn render(w: &mut fmt::Formatter, None }; let mut buffer = String::new(); - let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); + let mut parser = ParserWrapper::new(s); loop { let next_event = parser.next(); if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { break } } + if !parser.footnotes.is_empty() { + buffer.push_str(&format!("

      {}
    ", + parser.footnotes.join(""))); + } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) }); diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs new file mode 100644 index 000000000000..629e1a64e6fd --- /dev/null +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -0,0 +1,35 @@ +// 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. + +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - '

    hard break: after hard break


    ' +// @has - 'Rust' +// @has - '
  • ' +// @has - '1' +/// markdown test +/// +/// this is a [link]. +/// +/// [link]: https://example.com "this is a title" +/// +/// hard break: +/// after hard break +/// +/// ----------- +/// +/// a footnote[^footnote]. +/// +/// [^footnote]: Thing +/// +/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) +#[deprecated(note = "Struct")] +pub fn f() {} From 8fde04b4a295792249d4a01f87a9f66143aa7c83 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 29 Mar 2017 07:17:18 +0000 Subject: [PATCH 143/905] Improve `Path` spans. --- src/libsyntax/attr.rs | 7 ++-- src/libsyntax/ext/base.rs | 21 ++++++++++- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 13 ++++--- src/libsyntax/ext/tt/transcribe.rs | 9 +---- src/libsyntax/parse/mod.rs | 4 +- src/libsyntax/parse/parser.rs | 56 +++++++++++++++++----------- src/libsyntax/parse/token.rs | 48 ++++++++++++------------ 9 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 5dcce2572af8..6f5f52ff1e95 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -1015,9 +1015,10 @@ impl MetaItem { { let (mut span, name) = match tokens.next() { Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), - Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt { - token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()), - _ => None, + Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match **nt { + token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name), + token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + _ => return None, }, _ => return None, }; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a2d54b62ec65..fda026fec64e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -209,7 +209,26 @@ impl TTMacroExpander for F { fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream) -> Box { - (*self)(ecx, span, &input.trees().collect::>()) + struct AvoidInterpolatedIdents; + + impl Folder for AvoidInterpolatedIdents { + fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree { + if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt { + if let token::NtIdent(ident) = **nt { + return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node)); + } + } + fold::noop_fold_tt(tt, self) + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } + } + + let input: Vec<_> = + input.trees().map(|tt| AvoidInterpolatedIdents.fold_tt(tt)).collect(); + (*self)(ecx, span, &input) } } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 9ee427eed355..6cd1fea2e75e 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -492,7 +492,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { _ => {} } // check at the beginning and the parser checks after each bump - p.check_unknown_macro_variable(); + p.process_potential_macro_variable(); match name { "item" => match panictry!(p.parse_item()) { Some(i) => token::NtItem(i), diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 66f5520b8826..93348c8f0837 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -121,7 +121,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, p.root_module_name = cx.current_expansion.module.mod_path.last() .map(|id| id.name.as_str().to_string()); - p.check_unknown_macro_variable(); + p.process_potential_macro_variable(); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. return Box::new(ParserAnyMacro { diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 12e746e024d3..d216effbd450 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -136,11 +136,14 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => { let span = match trees.next() { Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() { - Some(tokenstream::TokenTree::Token(end_sp, token::Ident(kind))) => { - let span = Span { lo: start_sp.lo, ..end_sp }; - result.push(TokenTree::MetaVarDecl(span, ident, kind)); - continue - } + Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() { + Some(kind) => { + let span = Span { lo: start_sp.lo, ..end_sp }; + result.push(TokenTree::MetaVarDecl(span, ident, kind)); + continue + } + _ => end_sp, + }, tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span), }, tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 24004492be2a..947089b0b9ac 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -12,7 +12,7 @@ use ast::Ident; use errors::Handler; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::quoted; -use parse::token::{self, SubstNt, Token, NtIdent, NtTT}; +use parse::token::{self, SubstNt, Token, NtTT}; use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{TokenStream, TokenTree, Delimited}; use util::small_vector::SmallVector; @@ -154,13 +154,6 @@ pub fn transcribe(sp_diag: &Handler, None => result.push(TokenTree::Token(sp, SubstNt(ident)).into()), Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched { match **nt { - // sidestep the interpolation tricks for ident because - // (a) idents can be in lots of places, so it'd be a pain - // (b) we actually can, since it's a token. - NtIdent(ref sn) => { - let token = TokenTree::Token(sn.span, token::Ident(sn.node)); - result.push(token.into()); - } NtTT(ref tt) => result.push(tt.clone().into()), _ => { let token = TokenTree::Token(sp, token::Interpolated(nt.clone())); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b5d0a46de492..c63a6524f745 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -218,9 +218,7 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc) -> TokenStream /// Given stream and the ParseSess, produce a parser pub fn stream_to_parser<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> { - let mut p = Parser::new(sess, stream, None, false); - p.check_unknown_macro_variable(); - p + Parser::new(sess, stream, None, false) } /// Parse a string representing a character literal into its final form. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b0611d752906..db2878c6b1e7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -160,6 +160,7 @@ pub struct Parser<'a> { /// the span of the current token: pub span: Span, /// the span of the previous token: + pub meta_var_span: Option, pub prev_span: Span, /// the previous token kind prev_token_kind: PrevTokenKind, @@ -417,6 +418,7 @@ impl<'a> Parser<'a> { token: token::Underscore, span: syntax_pos::DUMMY_SP, prev_span: syntax_pos::DUMMY_SP, + meta_var_span: None, prev_token_kind: PrevTokenKind::Other, restrictions: Restrictions::empty(), obsolete_set: HashSet::new(), @@ -443,6 +445,7 @@ impl<'a> Parser<'a> { parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span)); parser.directory.path.pop(); } + parser.process_potential_macro_variable(); parser } @@ -1012,7 +1015,7 @@ impl<'a> Parser<'a> { self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - self.prev_span = self.span; + self.prev_span = self.meta_var_span.take().unwrap_or(self.span); // Record last token kind for possible error recovery. self.prev_token_kind = match self.token { @@ -1028,7 +1031,7 @@ impl<'a> Parser<'a> { self.token = next.tok; self.expected_tokens.clear(); // check after each token - self.check_unknown_macro_variable(); + self.process_potential_macro_variable(); } /// Advance the parser using provided token as a next one. Use this when @@ -1722,7 +1725,7 @@ impl<'a> Parser<'a> { pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |x| x); - let lo = self.span; + let lo = self.meta_var_span.unwrap_or(self.span); let is_global = self.eat(&token::ModSep); // Parse any number of segments and bound sets. A segment is an @@ -1744,13 +1747,9 @@ impl<'a> Parser<'a> { segments.insert(0, PathSegment::crate_root()); } - // Assemble the span. - // FIXME(#39450) This is bogus if part of the path is macro generated. - let span = lo.to(self.prev_span); - // Assemble the result. Ok(ast::Path { - span: span, + span: lo.to(self.prev_span), segments: segments, }) } @@ -1763,8 +1762,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1831,8 +1830,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { @@ -1873,10 +1872,11 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(PathSegment::from_ident(identifier, self.prev_span)); + segments.push(PathSegment::from_ident(identifier, ident_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -1896,8 +1896,9 @@ impl<'a> Parser<'a> { fn expect_lifetime(&mut self) -> Lifetime { match self.token { token::Lifetime(ident) => { + let ident_span = self.span; self.bump(); - Lifetime { name: ident.name, span: self.prev_span, id: ast::DUMMY_NODE_ID } + Lifetime { name: ident.name, span: ident_span, id: ast::DUMMY_NODE_ID } } _ => self.span_bug(self.span, "not a lifetime") } @@ -2568,10 +2569,23 @@ impl<'a> Parser<'a> { return Ok(e); } - pub fn check_unknown_macro_variable(&mut self) { - if let token::SubstNt(name) = self.token { - self.fatal(&format!("unknown macro variable `{}`", name)).emit() - } + pub fn process_potential_macro_variable(&mut self) { + let ident = match self.token { + token::SubstNt(name) => { + self.fatal(&format!("unknown macro variable `{}`", name)).emit(); + return + } + token::Interpolated(ref nt) => { + self.meta_var_span = Some(self.span); + match **nt { + token::NtIdent(ident) => ident, + _ => return, + } + } + _ => return, + }; + self.token = token::Ident(ident.node); + self.span = ident.span; } /// parse a single token tree from the input. @@ -2589,9 +2603,9 @@ impl<'a> Parser<'a> { }, token::CloseDelim(_) | token::Eof => unreachable!(), _ => { - let token = mem::replace(&mut self.token, token::Underscore); + let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span); self.bump(); - TokenTree::Token(self.prev_span, token) + TokenTree::Token(span, token) } } } @@ -3489,9 +3503,9 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_mode: ast::BindingMode) -> PResult<'a, PatKind> { + let ident_span = self.span; let ident = self.parse_ident()?; - let prev_span = self.prev_span; - let name = codemap::Spanned{span: prev_span, node: ident}; + let name = codemap::Spanned{span: ident_span, node: ident}; let sub = if self.eat(&token::At) { Some(self.parse_pat()?) } else { @@ -4364,7 +4378,7 @@ impl<'a> Parser<'a> { fn parse_self_arg(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. - token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) } + token::Ident(ident) => { let sp = this.span; this.bump(); codemap::respan(sp, ident) } _ => unreachable!() }; let isolated_self = |this: &mut Self, n| { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 519d5bd98e47..74aa3984a9a4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -211,9 +211,7 @@ impl Token { ModSep => true, // global path Pound => true, // expression attributes Interpolated(ref nt) => match **nt { - NtExpr(..) => true, - NtBlock(..) => true, - NtPath(..) => true, + NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -236,8 +234,7 @@ impl Token { Lt | BinOp(Shl) => true, // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { - NtTy(..) => true, - NtPath(..) => true, + NtIdent(..) | NtTy(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -252,12 +249,20 @@ impl Token { } } + pub fn ident(&self) -> Option { + match *self { + Ident(ident) => Some(ident), + Interpolated(ref nt) => match **nt { + NtIdent(ident) => Some(ident.node), + _ => None, + }, + _ => None, + } + } + /// Returns `true` if the token is an identifier. pub fn is_ident(&self) -> bool { - match *self { - Ident(..) => true, - _ => false, - } + self.ident().is_some() } /// Returns `true` if the token is a documentation comment. @@ -311,18 +316,15 @@ impl Token { /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { - match *self { - Ident(id) => id.name == kw.name(), - _ => false, - } + self.ident().map(|ident| ident.name == kw.name()).unwrap_or(false) } pub fn is_path_segment_keyword(&self) -> bool { - match *self { - Ident(id) => id.name == keywords::Super.name() || - id.name == keywords::SelfValue.name() || - id.name == keywords::SelfType.name(), - _ => false, + match self.ident() { + Some(id) => id.name == keywords::Super.name() || + id.name == keywords::SelfValue.name() || + id.name == keywords::SelfType.name(), + None => false, } } @@ -333,18 +335,16 @@ impl Token { /// Returns `true` if the token is a strict keyword. pub fn is_strict_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::As.name() && - id.name <= keywords::While.name(), + match self.ident() { + Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(), _ => false, } } /// Returns `true` if the token is a keyword reserved for possible future use. pub fn is_reserved_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::Abstract.name() && - id.name <= keywords::Yield.name(), + match self.ident() { + Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(), _ => false, } } From 1be84cee75687856c0032ad0fd5ea96945c067b7 Mon Sep 17 00:00:00 2001 From: raph Date: Thu, 30 Mar 2017 09:55:44 +0200 Subject: [PATCH 144/905] Update process.rs --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a86dba97f786..7f1a00c707c2 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1059,7 +1059,7 @@ pub fn exit(code: i32) -> ! { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::process; /// /// fn main() { From b3763862280946cab09cbedc4ad5626ebd95a5b2 Mon Sep 17 00:00:00 2001 From: Thomas Jespersen Date: Fri, 17 Mar 2017 23:11:27 +0100 Subject: [PATCH 145/905] Replace hardcoded forward slash with path::MAIN_SEPARATOR Fixes #40149 --- src/libstd/sys_common/backtrace.rs | 4 +-- src/libsyntax/parse/parser.rs | 9 +++--- src/test/parse-fail/mod_file_not_exist.rs | 2 ++ .../parse-fail/mod_file_not_exist_windows.rs | 32 +++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 src/test/parse-fail/mod_file_not_exist_windows.rs diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 99297b781e44..f5c188f7a753 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -19,7 +19,7 @@ use io; use libc; use str; use sync::atomic::{self, Ordering}; -use path::Path; +use path::{self, Path}; use sys::mutex::Mutex; use ptr; @@ -262,7 +262,7 @@ fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int, if let Ok(cwd) = env::current_dir() { if let Ok(stripped) = file_path.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { - write!(w, " at ./{}:{}", s, line)?; + write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; already_printed = true; } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index db2878c6b1e7..c2c3e5a6855a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -59,7 +59,7 @@ use util::ThinVec; use std::collections::HashSet; use std::{cmp, mem, slice}; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; bitflags! { flags Restrictions: u8 { @@ -5146,7 +5146,7 @@ impl<'a> Parser<'a> { pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath { let mod_name = id.to_string(); let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}/mod.rs", mod_name); + let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = codemap.file_exists(&default_path); @@ -5224,8 +5224,9 @@ impl<'a> Parser<'a> { }; err.span_note(id_sp, &format!("maybe move this module `{0}` to its own directory \ - via `{0}/mod.rs`", - this_module)); + via `{0}{1}mod.rs`", + this_module, + path::MAIN_SEPARATOR)); if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ diff --git a/src/test/parse-fail/mod_file_not_exist.rs b/src/test/parse-fail/mod_file_not_exist.rs index 7736394a6f5d..4bc6e706d428 100644 --- a/src/test/parse-fail/mod_file_not_exist.rs +++ b/src/test/parse-fail/mod_file_not_exist.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-windows + // compile-flags: -Z parse-only mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` diff --git a/src/test/parse-fail/mod_file_not_exist_windows.rs b/src/test/parse-fail/mod_file_not_exist_windows.rs new file mode 100644 index 000000000000..c58603b43989 --- /dev/null +++ b/src/test/parse-fail/mod_file_not_exist_windows.rs @@ -0,0 +1,32 @@ +// 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. + +// ignore-gnu +// ignore-android +// ignore-bitrig +// ignore-macos +// ignore-dragonfly +// ignore-freebsd +// ignore-haiku +// ignore-ios +// ignore-linux +// ignore-netbsd +// ignore-openbsd +// ignore-solaris +// ignore-emscripten + +// compile-flags: -Z parse-only + +mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` +//~^ HELP name the file either not_a_real_file.rs or not_a_real_file\mod.rs inside the directory + +fn main() { + assert_eq!(mod_file_aux::bar(), 10); +} From 276bba9039e90a2c06ec0c811d80108a52a26e0b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 09:53:00 -0500 Subject: [PATCH 146/905] refactor if so that the "then type" is an expression --- src/librustc/cfg/construct.rs | 4 +-- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/lowering.rs | 5 +++- src/librustc/hir/mod.rs | 2 +- src/librustc/hir/print.rs | 6 ++--- src/librustc/middle/expr_use_visitor.rs | 4 +-- src/librustc/middle/liveness.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_typeck/check/mod.rs | 35 ++++++++----------------- 9 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 189a7344c313..388d019f654a 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // [..expr..] // let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 + let then_exit = self.expr(&then, cond_exit); // 2 self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4 } @@ -215,7 +215,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // [..expr..] // let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 + let then_exit = self.expr(&then, cond_exit); // 2 let else_exit = self.expr(&otherwise, cond_exit); // 3 self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5 } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f59b8b757f5c..c7ad143c9497 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -960,7 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } ExprIf(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(head_expression); - visitor.visit_block(if_block); + visitor.visit_expr(if_block); walk_list!(visitor, visit_expr, optional_else); } ExprWhile(ref subexpression, ref block, ref opt_sp_name) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 029b27b40f04..fbc8a97dacc4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1856,7 +1856,10 @@ impl<'a> LoweringContext<'a> { } }); - hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) + let then_blk = self.lower_block(blk, None); + let then_expr = self.expr_block(then_blk, ThinVec::new()); + + hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt) } ExprKind::While(ref cond, ref body, opt_ident) => { self.with_loop_scope(e.id, |this| diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 3ca75dc6c00c..59cefa36cbf1 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -994,7 +994,7 @@ pub enum Expr_ { /// An `if` block, with an optional else block /// /// `if expr { block } else { expr }` - ExprIf(P, P, Option>), + ExprIf(P, P, Option>), /// A while loop, with an optional label /// /// `'label: while expr { block }` diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 3411de9bb5df..04a65fd5e3aa 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1036,7 +1036,7 @@ impl<'a> State<'a> { word(&mut self.s, " else if ")?; self.print_expr(&i)?; space(&mut self.s)?; - self.print_block(&then)?; + self.print_expr(&then)?; self.print_else(e.as_ref().map(|e| &**e)) } // "final else" @@ -1058,13 +1058,13 @@ impl<'a> State<'a> { pub fn print_if(&mut self, test: &hir::Expr, - blk: &hir::Block, + blk: &hir::Expr, elseopt: Option<&hir::Expr>) -> io::Result<()> { self.head("if")?; self.print_expr(test)?; space(&mut self.s)?; - self.print_block(blk)?; + self.print_expr(blk)?; self.print_else(elseopt) } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a44679b0b3e0..c7cf4a35a4bc 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -414,9 +414,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_exprs(exprs); } - hir::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => { + hir::ExprIf(ref cond_expr, ref then_expr, ref opt_else_expr) => { self.consume_expr(&cond_expr); - self.walk_block(&then_blk); + self.walk_expr(&then_expr); if let Some(ref else_expr) = *opt_else_expr { self.consume_expr(&else_expr); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 769dc8aeb54d..e146663d4c8d 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -951,7 +951,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // ( succ ) // let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ); - let then_ln = self.propagate_through_block(&then, succ); + let then_ln = self.propagate_through_expr(&then, succ); let ln = self.live_node(expr.id, expr.span); self.init_from_succ(ln, else_ln); self.merge_from_succ(ln, then_ln, false); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 44858a98e36f..d9b8d04ad386 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -636,7 +636,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprIf(ref cond, ref then, ref otherwise) => { ExprKind::If { condition: cond.to_ref(), - then: block::to_expr_ref(cx, then), + then: then.to_ref(), otherwise: otherwise.to_ref(), } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index afa1e0557dc8..54da0b2b0047 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2739,7 +2739,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // or if-else. fn check_then_else(&self, cond_expr: &'gcx hir::Expr, - then_blk: &'gcx hir::Block, + then_expr: &'gcx hir::Expr, opt_else_expr: Option<&'gcx hir::Expr>, sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { @@ -2748,7 +2748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); let expected = expected.adjust_for_branches(self); - let then_ty = self.check_block_with_expected(then_blk, expected); + let then_ty = self.check_expr_with_expectation(then_expr, expected); let then_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -2763,26 +2763,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to assign coercions to, otherwise it's () or diverging. expected_ty = then_ty; found_ty = else_ty; - result = if let Some(ref then) = then_blk.expr { - let res = self.try_find_coercion_lub(&cause, || Some(&**then), - then_ty, else_expr, else_ty); - // In case we did perform an adjustment, we have to update - // the type of the block, because old trans still uses it. - if res.is_ok() { - let adj = self.tables.borrow().adjustments.get(&then.id).cloned(); - if let Some(adj) = adj { - self.write_ty(then_blk.id, adj.target); - } - } - - res - } else { - self.commit_if_ok(|_| { - let trace = TypeTrace::types(&cause, true, then_ty, else_ty); - self.lub(true, trace, &then_ty, &else_ty) - .map(|ok| self.register_infer_ok_obligations(ok)) - }) + let coerce_to = expected.only_has_type(self).unwrap_or(then_ty); + result = { + self.try_coerce(then_expr, then_ty, coerce_to) + .and_then(|t| { + self.try_find_coercion_lub(&cause, || Some(then_expr), t, else_expr, else_ty) + }) }; // We won't diverge unless both branches do (or the condition does). @@ -3587,9 +3574,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_nil() } } - hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => { - self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), - expr.span, expected) + hir::ExprIf(ref cond, ref then_expr, ref opt_else_expr) => { + self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e), + expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { let unified = self.tcx.mk_nil(); From 6c022729264a54f1b90ab8801000dc783cdf1e6d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 09:57:26 -0500 Subject: [PATCH 147/905] update comment --- src/librustc/hir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 59cefa36cbf1..560fa18a4050 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -993,7 +993,7 @@ pub enum Expr_ { ExprType(P, P), /// An `if` block, with an optional else block /// - /// `if expr { block } else { expr }` + /// `if expr { expr } else { expr }` ExprIf(P, P, Option>), /// A while loop, with an optional label /// From 6a47fa1d3d4594ddd3077d0e73d29aa056493b0d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 29 Mar 2017 23:52:45 -0400 Subject: [PATCH 148/905] remove unneeded `&` that now fails to coerce cc https://github.com/rust-lang/rust/issues/40924 --- src/librustc_trans/abi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 1530708b4b88..453f65eb762f 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -369,7 +369,7 @@ impl FnType { match sig.inputs().last().unwrap().sty { ty::TyTuple(ref tupled_arguments, _) => { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - &tupled_arguments + tupled_arguments } _ => { bug!("argument to function with \"rust-call\" ABI \ From 066d44bc0d1680e2094867631920104049fd4948 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 22 Mar 2017 11:40:29 -0400 Subject: [PATCH 149/905] refactor the `targeted_by_break` field In master, this field was an arbitrary node-id (in fact, an id for something that doesn't even exist in the HIR -- the `catch` node). Breaks targeting this block used that id. In the newer system, this field is a boolean, and any breaks targeted this block will use the id of the block. --- src/librustc/cfg/construct.rs | 4 +- src/librustc/hir/lowering.rs | 36 +++--- src/librustc/hir/mod.rs | 8 +- src/librustc/middle/liveness.rs | 4 +- src/librustc_mir/build/block.rs | 172 ++++++++++++++++------------ src/librustc_mir/build/expr/into.rs | 14 +-- src/librustc_mir/hair/cx/block.rs | 1 + src/librustc_mir/hair/mod.rs | 1 + src/librustc_typeck/check/mod.rs | 36 +++--- 9 files changed, 144 insertions(+), 132 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 388d019f654a..20b322ec1895 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -74,11 +74,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { - if let Some(break_to_expr_id) = blk.break_to_expr_id { + if blk.targeted_by_break { let expr_exit = self.add_ast_node(blk.id, &[]); self.breakable_block_scopes.push(BlockScope { - block_expr_id: break_to_expr_id, + block_expr_id: blk.id, break_index: expr_exit, }); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index fbc8a97dacc4..17185a6ab69f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1156,7 +1156,7 @@ impl<'a> LoweringContext<'a> { bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect() } - fn lower_block(&mut self, b: &Block, break_to: Option) -> P { + fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P { let mut expr = None; let mut stmts = vec![]; @@ -1179,7 +1179,7 @@ impl<'a> LoweringContext<'a> { expr: expr, rules: self.lower_block_check_mode(&b.rules), span: b.span, - break_to_expr_id: break_to, + targeted_by_break: targeted_by_break, }) } @@ -1274,7 +1274,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { self.with_new_scopes(|this| { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); hir::ItemFn(this.lower_fn_decl(decl), @@ -1368,7 +1368,7 @@ impl<'a> LoweringContext<'a> { hir::TraitMethod::Required(names)) } TraitItemKind::Method(ref sig, Some(ref body)) => { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::TraitItemKind::Method(this.lower_method_sig(sig), @@ -1424,7 +1424,7 @@ impl<'a> LoweringContext<'a> { hir::ImplItemKind::Const(this.lower_ty(ty), body_id) } ImplItemKind::Method(ref sig, ref body) => { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id) @@ -1848,7 +1848,7 @@ impl<'a> LoweringContext<'a> { id: id, rules: hir::DefaultBlock, span: span, - break_to_expr_id: None, + targeted_by_break: false, }); P(self.expr_block(blk, ThinVec::new())) } @@ -1856,7 +1856,7 @@ impl<'a> LoweringContext<'a> { } }); - let then_blk = self.lower_block(blk, None); + let then_blk = self.lower_block(blk, false); let then_expr = self.expr_block(then_blk, ThinVec::new()); hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt) @@ -1865,18 +1865,18 @@ impl<'a> LoweringContext<'a> { self.with_loop_scope(e.id, |this| hir::ExprWhile( this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), - this.lower_block(body, None), + this.lower_block(body, false), this.lower_opt_sp_ident(opt_ident))) } ExprKind::Loop(ref body, opt_ident) => { self.with_loop_scope(e.id, |this| - hir::ExprLoop(this.lower_block(body, None), + hir::ExprLoop(this.lower_block(body, false), this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } ExprKind::Catch(ref body) => { - self.with_catch_scope(e.id, |this| - hir::ExprBlock(this.lower_block(body, Some(e.id)))) + self.with_catch_scope(body.id, |this| + hir::ExprBlock(this.lower_block(body, true))) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), @@ -1894,7 +1894,7 @@ impl<'a> LoweringContext<'a> { }) }) } - ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), + ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, false)), ExprKind::Assign(ref el, ref er) => { hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) } @@ -2040,7 +2040,7 @@ impl<'a> LoweringContext<'a> { // ` => ` { - let body = self.lower_block(body, None); + let body = self.lower_block(body, false); let body_expr = P(self.expr_block(body, ThinVec::new())); let pat = self.lower_pat(pat); arms.push(self.arm(hir_vec![pat], body_expr)); @@ -2112,7 +2112,7 @@ impl<'a> LoweringContext<'a> { let (guard, body) = if let ExprKind::If(ref cond, ref then, _) = else_expr.node { - let then = self.lower_block(then, None); + let then = self.lower_block(then, false); (Some(cond), self.expr_block(then, ThinVec::new())) } else { @@ -2162,7 +2162,7 @@ impl<'a> LoweringContext<'a> { // Note that the block AND the condition are evaluated in the loop scope. // This is done to allow `break` from inside the condition of the loop. let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( - this.lower_block(body, None), + this.lower_block(body, false), this.expr_break(e.span, ThinVec::new()), this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), )); @@ -2223,7 +2223,7 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::Some() => ` let pat_arm = { let body_block = self.with_loop_scope(e.id, - |this| this.lower_block(body, None)); + |this| this.lower_block(body, false)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); let pat = self.lower_pat(pat); let some_pat = self.pat_some(e.span, pat); @@ -2655,7 +2655,7 @@ impl<'a> LoweringContext<'a> { id: self.next_id(), rules: hir::DefaultBlock, span: span, - break_to_expr_id: None, + targeted_by_break: false, } } @@ -2763,7 +2763,7 @@ impl<'a> LoweringContext<'a> { id: id, stmts: stmts, expr: Some(expr), - break_to_expr_id: None, + targeted_by_break: false, }); self.expr_block(block, attrs) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 560fa18a4050..d5000ac9c186 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -549,9 +549,11 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, pub span: Span, - /// The id of the expression that `break` breaks to if the block can be broken out of. - /// Currently only `Some(_)` for `catch {}` blocks - pub break_to_expr_id: Option, + /// If true, then there may exist `break 'a` values that aim to + /// break out of this block early. As of this writing, this is not + /// currently permitted in Rust itself, but it is generated as + /// part of `catch` statements. + pub targeted_by_break: bool, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index e146663d4c8d..7cae08efc0de 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -821,8 +821,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { - if let Some(break_to_expr_id) = blk.break_to_expr_id { - self.breakable_block_ln.insert(break_to_expr_id, succ); + if blk.targeted_by_break { + self.breakable_block_ln.insert(blk.id, succ); } let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); blk.stmts.iter().rev().fold(succ, |succ, stmt| { diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 3305cfc0dfe1..7739766182cf 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -12,90 +12,116 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; use rustc::mir::*; use rustc::hir; +use syntax_pos::Span; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn ast_block(&mut self, destination: &Lvalue<'tcx>, - mut block: BasicBlock, - ast_block: &'tcx hir::Block) + block: BasicBlock, + ast_block: &'tcx hir::Block, + source_info: SourceInfo) -> BlockAnd<()> { - let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block); + let Block { extent, span, stmts, expr, targeted_by_break } = self.hir.mirror(ast_block); self.in_scope(extent, block, move |this| { - // This convoluted structure is to avoid using recursion as we walk down a list - // of statements. Basically, the structure we get back is something like: - // - // let x = in { - // expr1; - // let y = in { - // expr2; - // expr3; - // ... - // } - // } - // - // The let bindings are valid till the end of block so all we have to do is to pop all - // the let-scopes at the end. - // - // First we build all the statements in the block. - let mut let_extent_stack = Vec::with_capacity(8); - let outer_visibility_scope = this.visibility_scope; - for stmt in stmts { - let Stmt { span: _, kind } = this.hir.mirror(stmt); - match kind { - StmtKind::Expr { scope, expr } => { - unpack!(block = this.in_scope(scope, block, |this| { - let expr = this.hir.mirror(expr); - this.stmt_expr(block, expr) + if targeted_by_break { + // This is a `break`-able block (currently only `catch { ... }`) + let exit_block = this.cfg.start_new_block(); + let block_exit = this.in_breakable_scope(None, exit_block, + destination.clone(), |this| { + this.ast_block_stmts(destination, block, span, stmts, expr) + }); + this.cfg.terminate(unpack!(block_exit), source_info, + TerminatorKind::Goto { target: exit_block }); + exit_block.unit() + } else { + this.ast_block_stmts(destination, block, span, stmts, expr) + } + }) + } + + fn ast_block_stmts(&mut self, + destination: &Lvalue<'tcx>, + mut block: BasicBlock, + span: Span, + stmts: Vec>, + expr: Option>) + -> BlockAnd<()> { + let this = self; + + // This convoluted structure is to avoid using recursion as we walk down a list + // of statements. Basically, the structure we get back is something like: + // + // let x = in { + // expr1; + // let y = in { + // expr2; + // expr3; + // ... + // } + // } + // + // The let bindings are valid till the end of block so all we have to do is to pop all + // the let-scopes at the end. + // + // First we build all the statements in the block. + let mut let_extent_stack = Vec::with_capacity(8); + let outer_visibility_scope = this.visibility_scope; + for stmt in stmts { + let Stmt { span: _, kind } = this.hir.mirror(stmt); + match kind { + StmtKind::Expr { scope, expr } => { + unpack!(block = this.in_scope(scope, block, |this| { + let expr = this.hir.mirror(expr); + this.stmt_expr(block, expr) + })); + } + StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => { + let tcx = this.hir.tcx(); + + // Enter the remainder scope, i.e. the bindings' destruction scope. + this.push_scope(remainder_scope); + let_extent_stack.push(remainder_scope); + + // Declare the bindings, which may create a visibility scope. + let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.hir); + let remainder_span = remainder_span.unwrap_or(span); + let scope = this.declare_bindings(None, remainder_span, &pattern); + + // Evaluate the initializer, if present. + if let Some(init) = initializer { + unpack!(block = this.in_scope(init_scope, block, move |this| { + // FIXME #30046 ^~~~ + this.expr_into_pattern(block, pattern, init) })); + } else { + this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { + this.storage_live_binding(block, node, span); + this.schedule_drop_for_binding(node, span); + }) } - StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => { - let tcx = this.hir.tcx(); - // Enter the remainder scope, i.e. the bindings' destruction scope. - this.push_scope(remainder_scope); - let_extent_stack.push(remainder_scope); - - // Declare the bindings, which may create a visibility scope. - let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.hir); - let remainder_span = remainder_span.unwrap_or(span); - let scope = this.declare_bindings(None, remainder_span, &pattern); - - // Evaluate the initializer, if present. - if let Some(init) = initializer { - unpack!(block = this.in_scope(init_scope, block, move |this| { - // FIXME #30046 ^~~~ - this.expr_into_pattern(block, pattern, init) - })); - } else { - this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { - this.storage_live_binding(block, node, span); - this.schedule_drop_for_binding(node, span); - }) - } - - // Enter the visibility scope, after evaluating the initializer. - if let Some(visibility_scope) = scope { - this.visibility_scope = visibility_scope; - } + // Enter the visibility scope, after evaluating the initializer. + if let Some(visibility_scope) = scope { + this.visibility_scope = visibility_scope; } } } - // Then, the block may have an optional trailing expression which is a β€œreturn” value - // of the block. - if let Some(expr) = expr { - unpack!(block = this.into(destination, block, expr)); - } else { - let source_info = this.source_info(span); - this.cfg.push_assign_unit(block, source_info, destination); - } - // Finally, we pop all the let scopes before exiting out from the scope of block - // itself. - for extent in let_extent_stack.into_iter().rev() { - unpack!(block = this.pop_scope(extent, block)); - } - // Restore the original visibility scope. - this.visibility_scope = outer_visibility_scope; - block.unit() - }) + } + // Then, the block may have an optional trailing expression which is a β€œreturn” value + // of the block. + if let Some(expr) = expr { + unpack!(block = this.into(destination, block, expr)); + } else { + let source_info = this.source_info(span); + this.cfg.push_assign_unit(block, source_info, destination); + } + // Finally, we pop all the let scopes before exiting out from the scope of block + // itself. + for extent in let_extent_stack.into_iter().rev() { + unpack!(block = this.pop_scope(extent, block)); + } + // Restore the original visibility scope. + this.visibility_scope = outer_visibility_scope; + block.unit() } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index e1b0c6a6f042..a5a114c61bcf 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -40,19 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { - if let Some(_) = ast_block.break_to_expr_id { - // This is a `break`-able block (currently only `catch { ... }`) - let exit_block = this.cfg.start_new_block(); - let block_exit = this.in_breakable_scope(None, exit_block, - destination.clone(), |this| { - this.ast_block(destination, block, ast_block) - }); - this.cfg.terminate(unpack!(block_exit), source_info, - TerminatorKind::Goto { target: exit_block }); - exit_block.unit() - } else { - this.ast_block(destination, block, ast_block) - } + this.ast_block(destination, block, ast_block, source_info) } ExprKind::Match { discriminant, arms } => { this.match_expr(destination, expr_span, block, discriminant, arms) diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index ba6b9361a83f..d2465331df35 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -23,6 +23,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { // in order to get the lexical scoping correctly. let stmts = mirror_stmts(cx, self.id, &*self.stmts); Block { + targeted_by_break: self.targeted_by_break, extent: cx.tcx.region_maps.node_extent(self.id), span: self.span, stmts: stmts, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 2ee375dee08a..a3982efd2d69 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -31,6 +31,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt #[derive(Clone, Debug)] pub struct Block<'tcx> { + pub targeted_by_break: bool, pub extent: CodeExtent, pub span: Span, pub stmts: Vec>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 54da0b2b0047..000398a4bce9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -416,15 +416,11 @@ pub struct EnclosingBreakables<'gcx, 'tcx> { } impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { - fn find_breakable(&mut self, target: hir::ScopeTarget) - -> Option<&mut BreakableCtxt<'gcx, 'tcx>> - { - let opt_index = target.opt_id().and_then(|id| self.by_id.get(&id).cloned()); - if let Some(ix) = opt_index { - Some(&mut self.stack[ix]) - } else { - None - } + fn find_breakable(&mut self, target_id: ast::NodeId) -> &mut BreakableCtxt<'gcx, 'tcx> { + let ix = *self.by_id.get(&target_id).unwrap_or_else(|| { + bug!("could not find enclosing breakable with id {}", target_id); + }); + &mut self.stack[ix] } } @@ -3472,12 +3468,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_nil() } hir::ExprBreak(destination, ref expr_opt) => { - let coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables - .find_breakable(destination.target_id).map(|ctxt| ctxt.coerce_to) - }; - if let Some(coerce_to) = coerce_to { + if let Some(target_id) = destination.target_id.opt_id() { + let coerce_to = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables.find_breakable(target_id).coerce_to + }; + let e_ty; let cause; if let Some(ref e) = *expr_opt { @@ -3492,7 +3488,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(destination.target_id).unwrap(); + let ctxt = enclosing_breakables.find_breakable(target_id); let result = if let Some(ref e) = *expr_opt { // Special-case the first element, as it has no "previous expressions". @@ -4024,7 +4020,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - let mut ty = if let Some(break_to_expr_id) = blk.break_to_expr_id { + let mut ty = if blk.targeted_by_break { let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(blk.span)); let coerce_to = expected.only_has_type(self).unwrap_or(unified); let ctxt = BreakableCtxt { @@ -4034,15 +4030,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { may_break: false, }; - let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(break_to_expr_id, ctxt, || { + let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(blk.id, ctxt, || { for s in &blk.stmts { self.check_stmt(s); } let coerce_to = { let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable( - hir::ScopeTarget::Block(break_to_expr_id) - ).unwrap().coerce_to + enclosing_breakables.find_breakable(blk.id).coerce_to }; let e_ty; let cause; From 4c6c26eba1ca315677b024026a54001a5ab96cd0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 Mar 2017 21:15:26 -0500 Subject: [PATCH 150/905] change the strategy for diverging types The new strategy is as follows. First, the `!` type is assigned in two cases: - a block with a diverging statement and no tail expression (e.g., `{return;}`); - any expression with the type `!` is considered diverging. Second, we track when we are in a diverging state, and we permit a value of any type to be coerced **into** `!` if the expression that produced it is diverging. This means that `fn foo() -> ! { panic!(); 22 }` type-checks, even though the block has a type of `usize`. Finally, coercions **from** the `!` type to any other are always permitted. Fixes #39808. --- src/librustc_typeck/check/demand.rs | 24 +++++++++++++++++- src/librustc_typeck/check/mod.rs | 24 ++++++++++-------- .../diverging-tuple-parts-39485.rs | 25 +++++++++++++++++++ .../compile-fail/never-assign-wrong-type.rs | 1 + src/test/run-pass/issue-39808.rs | 21 ++++++++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/diverging-tuple-parts-39485.rs create mode 100644 src/test/run-pass/issue-39808.rs diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 232c4c4db7c9..25d689b3c2c4 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -67,8 +67,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Checks that the type of `expr` can be coerced to `expected`. - pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { + // + // NB: This code relies on `self.diverges` to be accurate. In + // particular, assignments to `!` will be permitted if the + // diverges flag is currently "always". + pub fn demand_coerce(&self, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); + + // If we are "assigning" to a `!` location, then we can permit + // any type to be assigned there, so long as we are in + // dead-code. This applies to e.g. `fn foo() -> ! { return; 22 + // }` but also `fn foo() { let x: ! = { return; 22 }; }`. + // + // You might imagine that we could just *always* bail if we + // are in dead-code, but we don't want to do that, because + // that leaves a lot of type variables unconstrained. See + // e.g. #39808 and #39984. + let in_dead_code = self.diverges.get().always(); + if expected.is_never() && in_dead_code { + return; + } + if let Err(e) = self.try_coerce(expr, checked_ty, expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 000398a4bce9..5d002dba78c2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1533,18 +1533,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {:?}) in fcx {}", - node_id, ty, self.tag()); + node_id, self.resolve_type_vars_if_possible(&ty), self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); if ty.references_error() { self.has_errors.set(true); self.set_tainted_by_errors(); } - - // FIXME(canndrew): This is_never should probably be an is_uninhabited - if ty.is_never() || self.type_var_diverges(ty) { - self.diverges.set(self.diverges.get() | Diverges::Always); - } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -3282,6 +3277,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => self.warn_if_unreachable(expr.id, expr.span, "expression") } + // Any expression that produces a value of type `!` must have diverged + if ty.is_never() { + self.diverges.set(self.diverges.get() | Diverges::Always); + } + // Record the type, which applies it effects. // We need to do this after the warning above, so that // we don't warn for the diverging expression itself. @@ -3967,7 +3967,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); self.has_errors.set(false); - let (node_id, span) = match stmt.node { + let (node_id, _span) = match stmt.node { hir::StmtDecl(ref decl, id) => { let span = match decl.node { hir::DeclLocal(ref l) => { @@ -3993,9 +3993,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if self.has_errors.get() { self.write_error(node_id); - } else if self.diverges.get().always() { - self.write_ty(node_id, self.next_diverging_ty_var( - TypeVariableOrigin::DivergingStmt(span))); } else { self.write_nil(node_id); } @@ -4046,7 +4043,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause = self.misc(e.span); }, None => { - e_ty = self.tcx.mk_nil(); + e_ty = if self.diverges.get().always() { + self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)) + } else { + self.tcx.mk_nil() + }; cause = self.misc(blk.span); } }; @@ -4054,6 +4055,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (e_ty, cause) }); + if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { let result = if !ctxt.may_break { self.try_coerce(e, e_ty, ctxt.coerce_to) diff --git a/src/test/compile-fail/diverging-tuple-parts-39485.rs b/src/test/compile-fail/diverging-tuple-parts-39485.rs new file mode 100644 index 000000000000..eedad08ab553 --- /dev/null +++ b/src/test/compile-fail/diverging-tuple-parts-39485.rs @@ -0,0 +1,25 @@ +// 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. + +// After #39485, this test used to pass, but that change was reverted +// due to numerous inference failures like #39808, so it now fails +// again. #39485 made it so that diverging types never propagate +// upward; but we now do propagate such types upward in many more +// cases. + +fn g() { + &panic!() //~ ERROR mismatched types +} + +fn f() -> isize { + (return 1, return 2) //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index 53d96aaf4fe8..d854e6eb2038 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -11,6 +11,7 @@ // Test that we can't use another type in place of ! #![feature(never_type)] +#![deny(warnings)] fn main() { let x: ! = "hello"; //~ ERROR mismatched types diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs new file mode 100644 index 000000000000..f83e9328e587 --- /dev/null +++ b/src/test/run-pass/issue-39808.rs @@ -0,0 +1,21 @@ +// 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. + +// Regression test: even though `Ok` is dead-code, its type needs to +// be influenced by the result of `Err` or else we get a "type +// variable unconstrained" error. + +fn main() { + let _ = if false { + Ok(return) + } else { + Err("") + }; +} From 555b6d69b2420862388e36992d7e099625ca6fe4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:35:50 -0400 Subject: [PATCH 151/905] add some debug logs to type_variable.rs --- src/librustc/infer/type_variable.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 9c8419d9546d..5aab0fdf6c95 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -30,6 +30,7 @@ pub struct TypeVariableTable<'tcx> { } /// Reasons to create a type inference variable +#[derive(Debug)] pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), @@ -196,6 +197,7 @@ impl<'tcx> TypeVariableTable<'tcx> { diverging: bool, origin: TypeVariableOrigin, default: Option>,) -> ty::TyVid { + debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); let index = self.values.push(TypeVariableData { value: Bounded { relations: vec![], default: default }, @@ -203,7 +205,7 @@ impl<'tcx> TypeVariableTable<'tcx> { diverging: diverging }); let v = ty::TyVid { index: index as u32 }; - debug!("new_var() -> {:?}", v); + debug!("new_var: diverging={:?} index={:?}", diverging, v); v } From 27f4b57602a01c2b49c09b161e1ddca26752fec8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:36:44 -0400 Subject: [PATCH 152/905] add a `TypeVariableOrigin` we'll use later (`DerivingFn`) --- src/librustc/infer/type_variable.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 5aab0fdf6c95..67f37e5f9272 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -42,6 +42,7 @@ pub enum TypeVariableOrigin { AdjustmentType(Span), DivergingStmt(Span), DivergingBlockExpr(Span), + DivergingFn(Span), LatticeVariable(Span), } From eeb6447bbfbb34ec093b723ff6a9dd40df2287bb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:37:18 -0400 Subject: [PATCH 153/905] add an `ObligationCauseCode` we'll use later (`ReturnNoExpression`) --- src/librustc/traits/error_reporting.rs | 1 + src/librustc/traits/mod.rs | 3 +++ src/librustc/traits/structural_impls.rs | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 27525d550ff2..152dd6ac3000 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -904,6 +904,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::StartFunctionType | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | + ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::MiscObligation => { } ObligationCauseCode::SliceOrArrayElem => { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c71fc28b4d6b..47cbccdd2ab1 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -173,6 +173,9 @@ pub enum ObligationCauseCode<'tcx> { // method receiver MethodReceiver, + + // `return` with no expression + ReturnNoExpression, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 717c171db2ac..44ef461327dd 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -167,6 +167,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { type Lifted = traits::ObligationCauseCode<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { + super::ReturnNoExpression => Some(super::ReturnNoExpression), super::MiscObligation => Some(super::MiscObligation), super::SliceOrArrayElem => Some(super::SliceOrArrayElem), super::TupleElem => Some(super::TupleElem), @@ -489,6 +490,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::StructInitializerSized | super::VariableType(_) | super::ReturnType | + super::ReturnNoExpression | super::RepeatVec | super::FieldSized | super::ConstSized | @@ -533,6 +535,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::StructInitializerSized | super::VariableType(_) | super::ReturnType | + super::ReturnNoExpression | super::RepeatVec | super::FieldSized | super::ConstSized | From dad314040764122fc78a7f8b70ffa9ef77bde3c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:39:13 -0400 Subject: [PATCH 154/905] introduce (but do not yet use) a `CoerceMany` API The existing pattern for coercions is fairly complex. `CoerceMany` enapsulates it better into a helper. --- src/librustc_typeck/check/coercion.rs | 227 ++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c43291557f7f..40ae169a94e0 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -837,3 +837,230 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + +/// CoerceMany encapsulates the pattern you should use when you have +/// many expressions that are all getting coerced to a common +/// type. This arises, for example, when you have a match (the result +/// of each arm is coerced to a common type). It also arises in less +/// obvious places, such as when you have many `break foo` expressions +/// that target the same loop, or the various `return` expressions in +/// a function. +/// +/// The basic protocol is as follows: +/// +/// - Instantiate the `CoerceMany` with an initial `expected_ty`. +/// This will also serve as the "starting LUB". The expectation is +/// that this type is something which all of the expressions *must* +/// be coercible to. Use a fresh type variable if needed. +/// - For each expression whose result is to be coerced, invoke `coerce()` with. +/// - In some cases we wish to coerce "non-expressions" whose types are implicitly +/// unit. This happens for example if you have a `break` with no expression, +/// or an `if` with no `else`. In that case, invoke `coerce_forced_unit()`. +/// - `coerce()` and `coerce_forced_unit()` may report errors. They hide this +/// from you so that you don't have to worry your pretty head about it. +/// But if an error is reported, the final type will be `err`. +/// - Invoking `coerce()` may cause us to go and adjust the "adjustments" on +/// previously coerced expressions. +/// - When all done, invoke `complete()`. This will return the LUB of +/// all your expressions. +/// - WARNING: I don't believe this final type is guaranteed to be +/// related to your initial `expected_ty` in any particular way, +/// although it will typically be a subtype, so you should check it. +/// - Invoking `complete()` may cause us to go and adjust the "adjustments" on +/// previously coerced expressions. +/// +/// Example: +/// +/// ``` +/// let mut coerce = CoerceMany::new(expected_ty); +/// for expr in exprs { +/// let expr_ty = fcx.check_expr_with_expectation(expr, expected); +/// coerce.coerce(fcx, &cause, expr, expr_ty); +/// } +/// let final_ty = coerce.complete(fcx); +/// ``` +#[derive(Clone)] // (*) +pub struct CoerceMany<'gcx: 'tcx, 'tcx> { + expected_ty: Ty<'tcx>, + final_ty: Option>, + expressions: Vec<&'gcx hir::Expr>, +} + +// (*) this is clone because `FnCtxt` is clone, but it seems dubious -- nmatsakis + +impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { + pub fn new(expected_ty: Ty<'tcx>) -> Self { + CoerceMany { + expected_ty, + final_ty: None, + expressions: vec![], + } + } + + pub fn is_empty(&self) -> bool { + self.expressions.is_empty() + } + + /// Return the "expected type" with which this coercion was + /// constructed. This represents the "downward propagated" type + /// that was given to us at the start of typing whatever construct + /// we are typing (e.g., the match expression). + /// + /// Typically, this is used as the expected type when + /// type-checking each of the alternative expressions whose types + /// we are trying to merge. + pub fn expected_ty(&self) -> Ty<'tcx> { + self.expected_ty + } + + /// Returns the current "merged type", representing our best-guess + /// at the LUB of the expressions we've seen so far (if any). This + /// isn't *final* until you call `self.final()`, which will return + /// the merged type. + pub fn merged_ty(&self) -> Ty<'tcx> { + self.final_ty.unwrap_or(self.expected_ty) + } + + /// Indicates that the value generated by `expression`, which is + /// of type `expression_ty`, is one of the possibility that we + /// could coerce from. This will record `expression` and later + /// calls to `coerce` may come back and add adjustments and things + /// if necessary. + pub fn coerce<'a>(&mut self, + fcx: &FnCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + expression: &'gcx hir::Expr, + expression_ty: Ty<'tcx>) + { + self.coerce_inner(fcx, cause, Some(expression), expression_ty) + } + + /// Indicates that one of the inputs is a "forced unit". This + /// occurs in a case like `if foo { ... };`, where the issing else + /// generates a "forced unit". Another example is a `loop { break; + /// }`, where the `break` has no argument expression. We treat + /// these cases slightly differently for error-reporting + /// purposes. Note that these tend to correspond to cases where + /// the `()` expression is implicit in the source, and hence we do + /// not take an expression argument. + pub fn coerce_forced_unit<'a>(&mut self, + fcx: &FnCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>) + { + self.coerce_inner(fcx, + cause, + None, + fcx.tcx.mk_nil()) + } + + /// The inner coercion "engine". If `expression` is `None`, this + /// is a forced-unit case, and hence `expression_ty` must be + /// `Nil`. + fn coerce_inner<'a>(&mut self, + fcx: &FnCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + expression: Option<&'gcx hir::Expr>, + mut expression_ty: Ty<'tcx>) + { + // Incorporate whatever type inference information we have + // until now; in principle we might also want to process + // pending obligations, but doing so should only improve + // compatibility (hopefully that is true) by helping us + // uncover never types better. + if expression_ty.is_ty_var() { + expression_ty = fcx.infcx.shallow_resolve(expression_ty); + } + + // If we see any error types, just propagate that error + // upwards. + if expression_ty.references_error() || self.merged_ty().references_error() { + self.final_ty = Some(fcx.tcx.types.err); + return; + } + + // Handle the actual type unification etc. + let result = if let Some(expression) = expression { + if self.expressions.is_empty() { + // Special-case the first expression we are coercing. + // To be honest, I'm not entirely sure why we do this. + fcx.try_coerce(expression, expression_ty, self.expected_ty) + } else { + fcx.try_find_coercion_lub(cause, + || self.expressions.iter().cloned(), + self.merged_ty(), + expression, + expression_ty) + } + } else { + // this is a hack for cases where we default to `()` because + // the expression etc has been omitted from the source. An + // example is an `if let` without an else: + // + // if let Some(x) = ... { } + // + // we wind up with a second match arm that is like `_ => + // ()`. That is the case we are considering here. We take + // a different path to get the right "expected, found" + // message and so forth (and because we know that + // `expression_ty` will be unit). + // + // Another example is `break` with no argument expression. + assert!(expression_ty.is_nil()); + assert!(expression_ty.is_nil(), "if let hack without unit type"); + fcx.eq_types(true, cause, expression_ty, self.merged_ty()) + .map(|infer_ok| { + fcx.register_infer_ok_obligations(infer_ok); + expression_ty + }) + }; + + match result { + Ok(v) => { + self.final_ty = Some(v); + self.expressions.extend(expression); + } + Err(err) => { + let (expected, found) = if expression.is_none() { + // In the case where this is a "forced unit", like + // `break`, we want to call the `()` "expected" + // since it is implied by the syntax. + assert!(expression_ty.is_nil()); + (expression_ty, self.final_ty.unwrap_or(self.expected_ty)) + } else { + // Otherwise, the "expected" type for error + // reporting is the current unification type, + // which is basically the LUB of the expressions + // we've seen so far (combined with the expected + // type) + (self.final_ty.unwrap_or(self.expected_ty), expression_ty) + }; + + match cause.code { + ObligationCauseCode::ReturnNoExpression => { + struct_span_err!(fcx.tcx.sess, cause.span, E0069, + "`return;` in a function whose return type is not `()`") + .span_label(cause.span, &format!("return type is not ()")) + .emit(); + } + _ => { + fcx.report_mismatched_types(cause, expected, found, err) + .emit(); + } + } + + self.final_ty = Some(fcx.tcx.types.err); + } + } + } + + pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + if let Some(final_ty) = self.final_ty { + final_ty + } else { + // If we only had inputs that were of type `!` (or no + // inputs at all), then the final type is `!`. + assert!(self.expressions.is_empty()); + fcx.tcx.types.never + } + } +} From 56847af9163284f928d5632a3d0d29399716414f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:51:31 -0400 Subject: [PATCH 155/905] port the match code to use `CoerceMany` `match { }` now (correctly?) indicates divergence, which results in more unreachable warnings. We also avoid fallback to `!` if there is just one arm (see new test: `match-unresolved-one-arm.rs`). --- src/librustc_typeck/check/_match.rs | 90 ++++++++----------- src/libsyntax/parse/obsolete.rs | 1 + .../match-no-arms-unreachable-after.rs | 22 +++++ ...eachable-warning-with-diverging-discrim.rs | 16 ++++ .../compile-fail/match-unresolved-one-arm.rs | 17 ++++ 5 files changed, 95 insertions(+), 51 deletions(-) create mode 100644 src/test/compile-fail/match-no-arms-unreachable-after.rs create mode 100644 src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs create mode 100644 src/test/compile-fail/match-unresolved-one-arm.rs diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index feed5752cf8f..f0d2598a0fb2 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -16,6 +16,7 @@ use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; +use check::coercion::CoerceMany; use util::nodemap::FxHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -414,6 +415,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); self.check_expr_has_type(discrim, discrim_ty); }; + + // If the discriminant diverges, the match is pointless (e.g., + // `match (return) { }`). + self.warn_if_unreachable(expr.id, expr.span, "expression"); + + // If there are no arms, that is a diverging match; a special case. + if arms.is_empty() { + self.diverges.set(self.diverges.get() | Diverges::Always); + return tcx.types.never; + } + + // Otherwise, we have to union together the types that the + // arms produce and so forth. + let discrim_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -426,6 +441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&p, discrim_ty); all_pats_diverge &= self.diverges.get(); } + // As discussed with @eddyb, this is for disabling unreachable_code // warnings on patterns (they're now subsumed by unreachable_patterns // warnings). @@ -444,20 +460,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // on any empty type and is therefore unreachable; should the flow // of execution reach it, we will panic, so bottom is an appropriate // type in that case) - let expected = expected.adjust_for_branches(self); - let mut result_ty = self.next_diverging_ty_var( - TypeVariableOrigin::DivergingBlockExpr(expr.span)); let mut all_arms_diverge = Diverges::WarnedAlways; - let coerce_first = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => { - ety - } - _ => result_ty + + let expected = expected.adjust_for_branches(self); + + let mut coercion = { + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, + _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), + }; + CoerceMany::new(coerce_first) }; for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { @@ -470,11 +487,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let arm_ty = self.check_expr_with_expectation(&arm.body, expected); all_arms_diverge &= self.diverges.get(); - if result_ty.references_error() || arm_ty.references_error() { - result_ty = tcx.types.err; - continue; - } - // Handle the fallback arm of a desugared if-let like a missing else. let is_if_let_fallback = match match_src { hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { @@ -483,47 +495,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false }; - let cause = if is_if_let_fallback { - self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse) + if is_if_let_fallback { + let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); + assert!(arm_ty.is_nil()); + coercion.coerce_forced_unit(self, &cause); } else { - self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { arm_span: arm.body.span, source: match_src - }) - }; - - let result = if is_if_let_fallback { - self.eq_types(true, &cause, arm_ty, result_ty) - .map(|infer_ok| { - self.register_infer_ok_obligations(infer_ok); - arm_ty - }) - } else if i == 0 { - // Special-case the first arm, as it has no "previous expressions". - self.try_coerce(&arm.body, arm_ty, coerce_first) - } else { - let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty) - }; - - result_ty = match result { - Ok(ty) => ty, - Err(e) => { - let (expected, found) = if is_if_let_fallback { - (arm_ty, result_ty) - } else { - (result_ty, arm_ty) - }; - self.report_mismatched_types(&cause, expected, found, e).emit(); - self.tcx.types.err - } - }; + }); + coercion.coerce(self, &cause, &arm.body, arm_ty); + } } // We won't diverge unless the discriminant or all arms diverge. self.diverges.set(discrim_diverges | all_arms_diverge); - result_ty + coercion.complete(self) } fn check_pat_struct(&self, diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a46a788ca080..d5baec675e44 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods { impl<'a> ParserObsoleteMethods for parser::Parser<'a> { /// Reports an obsolete syntax non-fatal error. #[allow(unused_variables)] + #[allow(unreachable_code)] fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { let (kind_str, desc, error) = match kind { // Nothing here at the moment diff --git a/src/test/compile-fail/match-no-arms-unreachable-after.rs b/src/test/compile-fail/match-no-arms-unreachable-after.rs new file mode 100644 index 000000000000..db08f5e5e66a --- /dev/null +++ b/src/test/compile-fail/match-no-arms-unreachable-after.rs @@ -0,0 +1,22 @@ +// 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. + +#![allow(warnings)] +#![deny(unreachable_code)] + +enum Void { } + +fn foo(v: Void) { + match v { } + let x = 2; //~ ERROR unreachable +} + +fn main() { +} diff --git a/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs new file mode 100644 index 000000000000..aae0f3135d8f --- /dev/null +++ b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs @@ -0,0 +1,16 @@ +// 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. + +#![allow(unused_parens)] +#![deny(unreachable_code)] + +fn main() { + match (return) { } //~ ERROR unreachable expression +} diff --git a/src/test/compile-fail/match-unresolved-one-arm.rs b/src/test/compile-fail/match-unresolved-one-arm.rs new file mode 100644 index 000000000000..ea0f8db99e89 --- /dev/null +++ b/src/test/compile-fail/match-unresolved-one-arm.rs @@ -0,0 +1,17 @@ +// 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() -> T { panic!("Rocks for my pillow") } + +fn main() { + let x = match () { //~ ERROR type annotations needed + () => foo() // T here should be unresolved + }; +} From b725272b265268fbe4f3220111ae1a053b3a37a7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:52:38 -0400 Subject: [PATCH 156/905] port if-then-else to use `CoerceMany` --- src/librustc_typeck/check/mod.rs | 69 +++++++++++++++----------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5d002dba78c2..69f1466c4751 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,6 +77,7 @@ type parameter). */ pub use self::Expectation::*; +use self::coercion::CoerceMany; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; @@ -299,12 +300,23 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { } } + /// It sometimes happens that we want to turn an expectation into + /// a **hard constraint** (i.e., something that must be satisfied + /// for the program to type-check). `only_has_type` will return + /// such a constraint, if it exists. fn only_has_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { match self.resolve(fcx) { ExpectHasType(ty) => Some(ty), _ => None } } + + /// Like `only_has_type`, but instead of returning `None` if no + /// hard constraint exists, creates a fresh type variable. + fn only_has_type_or_fresh_var(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { + self.only_has_type(fcx) + .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span))) + } } #[derive(Copy, Clone)] @@ -2743,54 +2755,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let then_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); - let unit = self.tcx.mk_nil(); - let (cause, expected_ty, found_ty, result); + // We've already taken the expected type's preferences + // into account when typing the `then` branch. To figure + // out the initial shot at a LUB, we thus only consider + // `expected` if it represents a *hard* constraint + // (`only_has_type`); otherwise, we just go with a + // fresh type variable. + let coerce_to_ty = expected.only_has_type_or_fresh_var(self, sp); + let mut coerce = CoerceMany::new(coerce_to_ty); + + let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); + coerce.coerce(self, &if_cause, then_expr, then_ty); + if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); - cause = self.cause(sp, ObligationCauseCode::IfExpression); - // Only try to coerce-unify if we have a then expression - // to assign coercions to, otherwise it's () or diverging. - expected_ty = then_ty; - found_ty = else_ty; - - let coerce_to = expected.only_has_type(self).unwrap_or(then_ty); - result = { - self.try_coerce(then_expr, then_ty, coerce_to) - .and_then(|t| { - self.try_find_coercion_lub(&cause, || Some(then_expr), t, else_expr, else_ty) - }) - }; + coerce.coerce(self, &if_cause, else_expr, else_ty); // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); } else { + let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); + coerce.coerce_forced_unit(self, &else_cause); + // If the condition is false we can't diverge. self.diverges.set(cond_diverges); - - cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); - expected_ty = unit; - found_ty = then_ty; - result = self.eq_types(true, &cause, unit, then_ty) - .map(|ok| { - self.register_infer_ok_obligations(ok); - unit - }); } - match result { - Ok(ty) => { - if cond_ty.references_error() { - self.tcx.types.err - } else { - ty - } - } - Err(e) => { - self.report_mismatched_types(&cause, expected_ty, found_ty, e).emit(); - self.tcx.types.err - } + let result_ty = coerce.complete(self); + if cond_ty.references_error() { + self.tcx.types.err + } else { + result_ty } } From a6e6be5f88bc773f50016cc1cf1baaa7b3e6cd11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:54:26 -0400 Subject: [PATCH 157/905] port `return` expressions to use `CoerceMany` This slightly affects the error messages in one particular compile-fail test. --- src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/check/mod.rs | 85 +++++++++++++++------ src/librustc_typeck/check/wfcheck.rs | 2 +- src/test/compile-fail/regions-bounds.rs | 10 +-- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 0e9abaf1cf95..905d8688ea19 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -362,7 +362,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); } else { - let fcx = FnCtxt::new(&inh, Some(tcx.types.err), impl_m_body_id); + let fcx = FnCtxt::new(&inh, impl_m_body_id); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 69f1466c4751..619f4fb10c54 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -448,7 +448,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_ty: Option>, + ret_coercion: Option>>, ps: RefCell, @@ -679,7 +679,7 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_fn(&inh, fn_sig, decl, id, body) } else { - let fcx = FnCtxt::new(&inh, None, body.value.id); + let fcx = FnCtxt::new(&inh, body.value.id); let expected_type = tcx.item_type(def_id); let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); @@ -800,15 +800,16 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, None, body.value.id); - let ret_ty = fn_sig.output(); + let mut fcx = FnCtxt::new(inherited, body.value.id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + let ret_ty = fn_sig.output(); fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); - fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty)); + let ret_ty = fcx.instantiate_anon_types(&ret_ty); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), - fcx.ret_ty.unwrap(), + ret_ty, fn_sig.variadic, fn_sig.unsafety, fn_sig.abi @@ -833,7 +834,38 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap()); + fcx.check_return_expr(&body.value); + + // Finalize the return check by taking the LUB of the return types + // we saw and assigning it to the expected return type. This isn't + // really expected to fail, since the coercions would have failed + // earlier when trying to find a LUB. + // + // However, the behavior around `!` is sort of complex. In the + // event that the `actual_return_ty` comes back as `!`, that + // indicates that the fn either does not return or "returns" only + // values of type `!`. In this case, if there is an expected + // return type that is *not* `!`, that should be ok. But if the + // return type is being inferred, we want to "fallback" to `!`: + // + // let x = move || panic!(); + // + // To allow for that, I am creating a type variable with diverging + // fallback. This was deemed ever so slightly better than unifying + // the return value with `!` because it allows for the caller to + // make more assumptions about the return type (e.g., they could do + // + // let y: Option = Some(x()); + // + // which would then cause this return type to become `u32`, not + // `!`). + let coercion = fcx.ret_coercion.take().unwrap().into_inner(); + let mut actual_return_ty = coercion.complete(&fcx); + if actual_return_ty.is_never() { + actual_return_ty = fcx.next_diverging_ty_var( + TypeVariableOrigin::DivergingFn(body.value.span)); + } + fcx.demand_suptype(body.value.span, ret_ty, actual_return_ty); fcx } @@ -1429,14 +1461,13 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, - rty: Option>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { ast_ty_to_ty_cache: RefCell::new(NodeMap()), body_id: body_id, err_count_on_creation: inh.tcx.sess.err_count(), - ret_ty: rty, + ret_coercion: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), @@ -2738,6 +2769,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty } + fn check_return_expr(&self, return_expr: &'gcx hir::Expr) { + let ret_coercion = + self.ret_coercion + .as_ref() + .unwrap_or_else(|| span_bug!(return_expr.span, + "check_return_expr called outside fn body")); + + let ret_ty = ret_coercion.borrow().expected_ty(); + let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); + ret_coercion.borrow_mut() + .coerce(self, + &self.misc(return_expr.span), + return_expr, + return_expr_ty); + } + + // A generic function for checking the then and else in an if // or if-else. fn check_then_else(&self, @@ -3522,24 +3570,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { - if self.ret_ty.is_none() { + if self.ret_coercion.is_none() { struct_span_err!(self.tcx.sess, expr.span, E0572, "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { - self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); + self.check_return_expr(e); } else { - match self.eq_types(false, - &self.misc(expr.span), - self.ret_ty.unwrap(), - tcx.mk_nil()) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - struct_span_err!(tcx.sess, expr.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(expr.span, &format!("return type is not ()")) - .emit(); - } - } + let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); + let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); + coercion.coerce_forced_unit(self, &cause); } tcx.types.never } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a4cb4071b4d8..85c87adf9be6 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, None, id); + let fcx = FnCtxt::new(&inh, id); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { tcx: fcx.tcx.global_tcx(), code: code diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 64dbf27b78e4..810a8671c536 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -16,17 +16,11 @@ struct an_enum<'a>(&'a isize); struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { - return e; //~ ERROR mismatched types - //~| expected type `an_enum<'b>` - //~| found type `an_enum<'a>` - //~| lifetime mismatch + return e; //~^ ERROR mismatched types } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { - return e; //~ ERROR mismatched types - //~| expected type `a_class<'b>` - //~| found type `a_class<'a>` - //~| lifetime mismatch + return e; //~^ ERROR mismatched types } fn main() { } From 4967f1ae57120b02639f3d1493e8f0c9e168b0dc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:10:12 -0400 Subject: [PATCH 158/905] document the diverges flag etc --- src/librustc_typeck/check/mod.rs | 43 +++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 619f4fb10c54..e186daf9f408 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -360,11 +360,12 @@ impl UnsafetyState { } } -/// Whether a node ever exits normally or not. -/// Tracked semi-automatically (through type variables -/// marked as diverging), with some manual adjustments -/// for control-flow primitives (approximating a CFG). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Tracks whether executing a node may exit normally (versus +/// return/break/panic, which "diverge", leaving dead code in their +/// wake). Tracked semi-automatically (through type variables marked +/// as diverging), with some manual adjustments for control-flow +/// primitives (approximating a CFG). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] enum Diverges { /// Potentially unknown, some cases converge, /// others require a CFG to determine them. @@ -452,7 +453,37 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ps: RefCell, - /// Whether the last checked node can ever exit. + /// Whether the last checked node generates a divergence (e.g., + /// `return` will set this to Always). In general, this is + /// typically set to *Maybe* on the way **down** the tree, and + /// then values are propagated **up** the tree. In a block, we + /// combine the results from statements and propagate the + /// end-result up. + /// + /// We use this flag for two purposes: + /// + /// - To warn about unreachable code: if, after processing a + /// sub-expression but before we have applied the effects of the + /// current node, we see that the flag is set to `Always`, we + /// can issue a warning. This corresponds to something like + /// `foo(return)`; we warn on the `foo()` expression. (We then + /// update the flag to `WarnedAlways` to suppress duplicate + /// reports.) Similarly, if we traverse to a fresh statement (or + /// tail expression) from a `Always` setting, we will isssue a + /// warning. This corresponds to something like `{return; + /// foo();}` or `{return; 22}`, where we would warn on the + /// `foo()` or `22`. + /// + /// - To permit assignment into a local variable or other lvalue + /// (including the "return slot") of type `!`. This is allowed + /// if **either** the type of value being assigned is `!`, which + /// means the current code is dead, **or** the expression's + /// divering flag is true, which means that a divering value was + /// wrapped (e.g., `let x: ! = foo(return)`). + /// + /// To repeat the last point: an expression represents dead-code + /// if, after checking it, **either** its type is `!` OR the + /// diverges flag is set to something other than `Maybe`. diverges: Cell, /// Whether any child nodes have any type errors. From 1ae620bbebadbe4362a28b37bcecd41cfed66cea Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:48:18 -0400 Subject: [PATCH 159/905] do not eagerly convert `!` to a diverging variable Instead, wait until coercion time. This has some small effects on a few tests (one less temporary, generally better errors when trying to call methods or otherwise "force" the type). --- src/librustc_typeck/check/coercion.rs | 26 +++++++-- src/librustc_typeck/check/mod.rs | 79 +++++++++++++++------------ src/test/compile-fail/index-bot.rs | 2 +- src/test/compile-fail/issue-13847.rs | 2 +- src/test/compile-fail/issue-15207.rs | 2 +- src/test/compile-fail/issue-15965.rs | 2 +- src/test/compile-fail/issue-17373.rs | 2 +- src/test/compile-fail/issue-18532.rs | 3 +- 8 files changed, 71 insertions(+), 47 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 40ae169a94e0..a08faf2610e3 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -169,7 +169,23 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } if a.is_never() { - return success(Adjust::NeverToAny, b, vec![]); + // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound + // type variable, we want `?T` to fallback to `!` if not + // otherwise constrained. An example where this arises: + // + // let _: Option = Some({ return; }); + // + // here, we would coerce from `!` to `?T`. + let b = self.shallow_resolve(b); + return if self.shallow_resolve(b).is_ty_var() { + // micro-optimization: no need for this if `b` is + // already resolved in some way. + let diverging_ty = self.next_diverging_ty_var( + TypeVariableOrigin::AdjustmentType(self.cause.span)); + self.unify_and(&b, &diverging_ty, Adjust::NeverToAny) + } else { + success(Adjust::NeverToAny, b, vec![]) + }; } // Consider coercing the subtype to a DST @@ -687,11 +703,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); - match self.tables.borrow().adjustments.get(&expr.id) { - None | - Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (), - _ => bug!("expr already has an adjustment on it!"), - }; + if self.tables.borrow().adjustments.get(&expr.id).is_some() { + bug!("expr already has an adjustment on it!"); + } self.write_adjustment(expr.id, adjustment); } Ok(adjustment.target) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e186daf9f408..ae0ed81ac778 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2664,7 +2664,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_expr_has_type(&self, expr: &'gcx hir::Expr, expected: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.check_expr_with_hint(expr, expected); + let mut ty = self.check_expr_with_hint(expr, expected); + + // While we don't allow *arbitrary* coercions here, we *do* allow + // coercions from ! to `expected`. + if ty.is_never() { + assert!(!self.tables.borrow().adjustments.contains_key(&expr.id), + "expression with never type wound up being adjusted"); + let adj_ty = self.next_diverging_ty_var( + TypeVariableOrigin::AdjustmentType(expr.span)); + self.write_adjustment(expr.id, adjustment::Adjustment { + kind: adjustment::Adjust::NeverToAny, + target: adj_ty + }); + ty = adj_ty; + } + self.demand_suptype(expr.span, expected, ty); ty } @@ -3370,18 +3385,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("type of {} is...", self.tcx.hir.node_to_string(expr.id)); debug!("... {:?}, expected is {:?}", ty, expected); - // Add adjustments to !-expressions - if ty.is_never() { - if let Some(hir::map::NodeExpr(node_expr)) = self.tcx.hir.find(expr.id) { - let adj_ty = self.next_diverging_ty_var( - TypeVariableOrigin::AdjustmentType(node_expr.span)); - self.write_adjustment(expr.id, adjustment::Adjustment { - kind: adjustment::Adjust::NeverToAny, - target: adj_ty - }); - return adj_ty; - } - } ty } @@ -4072,7 +4075,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { let unit = self.tcx.mk_nil(); let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); - self.demand_suptype(blk.span, unit, ty); + + // if the block produces a `!` value, that can always be + // (effectively) coerced to unit. + if !ty.is_never() { + self.demand_suptype(blk.span, unit, ty); + } } fn check_block_with_expected(&self, @@ -4111,7 +4119,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, None => { e_ty = if self.diverges.get().always() { - self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)) + self.tcx.types.never } else { self.tcx.mk_nil() }; @@ -4135,6 +4143,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(err) => self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(), } + } else if self.diverges.get().always() { + // No tail expression and the body diverges; ignore + // the expected type, and keep `!` as the type of the + // block. } else { self.check_block_no_expr(blk, self.tcx.mk_nil(), e_ty); }; @@ -4147,33 +4159,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut ty = match blk.expr { Some(ref e) => self.check_expr_with_expectation(e, expected), - None => self.tcx.mk_nil() + None => if self.diverges.get().always() { + self.tcx.types.never + } else { + self.tcx.mk_nil() + }, }; - if self.diverges.get().always() { - if let ExpectHasType(ety) = expected { - // Avoid forcing a type (only `!` for now) in unreachable code. - // FIXME(aburka) do we need this special case? and should it be is_uninhabited? - if !ety.is_never() { - if let Some(ref e) = blk.expr { - // Coerce the tail expression to the right type. - self.demand_coerce(e, ty, ety); - } - } - } - - ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span)); - } else if let ExpectHasType(ety) = expected { + if let ExpectHasType(ety) = expected { if let Some(ref e) = blk.expr { // Coerce the tail expression to the right type. self.demand_coerce(e, ty, ety); + + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } else if self.diverges.get().always() { + // No tail expression and the body diverges; ignore + // the expected type, and keep `!` as the type of the + // block. } else { self.check_block_no_expr(blk, ty, ety); - } - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } } ty }; diff --git a/src/test/compile-fail/index-bot.rs b/src/test/compile-fail/index-bot.rs index 70c362303ae3..05b047233004 100644 --- a/src/test/compile-fail/index-bot.rs +++ b/src/test/compile-fail/index-bot.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - (return)[0]; //~ ERROR the type of this value must be known in this context + (return)[0]; //~ ERROR cannot index a value of type `!` } diff --git a/src/test/compile-fail/issue-13847.rs b/src/test/compile-fail/issue-13847.rs index aa823d9a70e7..0314f109a7c8 100644 --- a/src/test/compile-fail/issue-13847.rs +++ b/src/test/compile-fail/issue-13847.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - return.is_failure //~ ERROR the type of this value must be known in this context + return.is_failure //~ ERROR no field `is_failure` on type `!` } diff --git a/src/test/compile-fail/issue-15207.rs b/src/test/compile-fail/issue-15207.rs index 61877775269d..70da8cf4169b 100644 --- a/src/test/compile-fail/issue-15207.rs +++ b/src/test/compile-fail/issue-15207.rs @@ -10,7 +10,7 @@ fn main() { loop { - break.push(1) //~ ERROR the type of this value must be known in this context + break.push(1) //~ ERROR no method named `push` found for type `!` ; } } diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 08b896f387bb..d5d597c190ea 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,7 +11,7 @@ fn main() { return { return () } -//~^ ERROR the type of this value must be known in this context +//~^ ERROR expected function, found `!` () ; } diff --git a/src/test/compile-fail/issue-17373.rs b/src/test/compile-fail/issue-17373.rs index 6895893adc4d..f6e6a8a0852d 100644 --- a/src/test/compile-fail/issue-17373.rs +++ b/src/test/compile-fail/issue-17373.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - *return //~ ERROR the type of this value must be known in this context + *return //~ ERROR type `!` cannot be dereferenced ; } diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 94eab97c42a1..2be5fdcac4ed 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -13,6 +13,5 @@ // into it. fn main() { - (return)((),()); - //~^ ERROR the type of this value must be known + (return)((),()); //~ ERROR expected function, found `!` } From 16a71cce514f29cb8c532248cf749e26972afb01 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:49:53 -0400 Subject: [PATCH 160/905] rework how we handle the type of loops First, we keep a `CoerceMany` now to find the LUB of all the break expressions. Second, this `CoerceMany` is actually an `Option`, and we store `None` for loops where "break with an expression" is disallowed. This avoids silly duplicate errors about a type mismatch, since the loops pass already reports an error that the break cannot have an expression. Finally, since we now detect an invalid break target during HIR lowering, refactor `find_loop` to be infallible. Adjust tests as needed: - some spans from breaks are slightly different - break up a single loop into multiple since `CoerceMany` silences redundant and derived errors - add a ui test that we only give on error for loop-break-value --- src/librustc_typeck/check/mod.rs | 203 ++++++++++-------- src/test/compile-fail/issue-27042.rs | 8 +- src/test/compile-fail/loop-break-value.rs | 23 +- src/test/ui/loop-break-value-no-repeat.rs | 25 +++ src/test/ui/loop-break-value-no-repeat.stderr | 8 + 5 files changed, 159 insertions(+), 108 deletions(-) create mode 100644 src/test/ui/loop-break-value-no-repeat.rs create mode 100644 src/test/ui/loop-break-value-no-repeat.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae0ed81ac778..59f3ac739e0a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -415,15 +415,16 @@ impl Diverges { } #[derive(Clone)] -pub struct BreakableCtxt<'gcx, 'tcx> { - unified: Ty<'tcx>, - coerce_to: Ty<'tcx>, - break_exprs: Vec<&'gcx hir::Expr>, +pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { may_break: bool, + + // this is `null` for loops where break with a value is illegal, + // such as `while`, `for`, and `while let` + coerce: Option>, } #[derive(Clone)] -pub struct EnclosingBreakables<'gcx, 'tcx> { +pub struct EnclosingBreakables<'gcx: 'tcx, 'tcx> { stack: Vec>, by_id: NodeMap, } @@ -3547,60 +3548,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_nil() } hir::ExprBreak(destination, ref expr_opt) => { - if let Some(target_id) = destination.target_id.opt_id() { - let coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable(target_id).coerce_to - }; + if let Some(target_id) = destination.target_id.opt_id() { + let (e_ty, cause); + if let Some(ref e) = *expr_opt { + // If this is a break with a value, we need to type-check + // the expression. Get an expected type from the loop context. + let opt_coerce_to = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + enclosing_breakables.find_breakable(target_id) + .coerce + .as_ref() + .map(|coerce| coerce.expected_ty()) + }; - let e_ty; - let cause; - if let Some(ref e) = *expr_opt { - // Recurse without `enclosing_loops` borrowed. - e_ty = self.check_expr_with_hint(e, coerce_to); - cause = self.misc(e.span); - // Notably, the recursive call may alter coerce_to - must not keep using it! - } else { - // `break` without argument acts like `break ()`. - e_ty = tcx.mk_nil(); - cause = self.misc(expr.span); - } + // If the loop context is not a `loop { }`, then break with + // a value is illegal, and `opt_coerce_to` will be `None`. + // Just set expectation to error in that case. + let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err); - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(target_id); + // Recurse without `enclosing_breakables` borrowed. + e_ty = self.check_expr_with_hint(e, coerce_to); + cause = self.misc(e.span); + } else { + // Otherwise, this is a break *without* a value. That's + // always legal, and is equivalent to `break ()`. + e_ty = tcx.mk_nil(); + cause = self.misc(expr.span); + } - let result = if let Some(ref e) = *expr_opt { - // Special-case the first element, as it has no "previous expressions". - let result = if !ctxt.may_break { - self.try_coerce(e, e_ty, ctxt.coerce_to) - } else { - self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(), - ctxt.unified, e, e_ty) - }; + // Now that we have type-checked `expr_opt`, borrow + // the `enclosing_loops` field and let's coerce the + // type of `expr_opt` into what is expected. + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(target_id); + if let Some(ref mut coerce) = ctxt.coerce { + if let Some(ref e) = *expr_opt { + coerce.coerce(self, &cause, e, e_ty); + } else { + assert!(e_ty.is_nil()); + coerce.coerce_forced_unit(self, &cause); + } + } else { + // If `ctxt.coerce` is `None`, we can just ignore + // the type of the expresison. This is because + // either this was a break *without* a value, in + // which case it is always a legal type (`()`), or + // else an error would have been flagged by the + // `loops` pass for using break with an expression + // where you are not supposed to. + assert!(expr_opt.is_none() || self.tcx.sess.err_count() > 0); + } - ctxt.break_exprs.push(e); - result - } else { - self.eq_types(true, &cause, e_ty, ctxt.unified) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - e_ty - }) - }; - match result { - Ok(ty) => ctxt.unified = ty, - Err(err) => { - self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(); - } - } + ctxt.may_break = true; + } else { + // Otherwise, we failed to find the enclosing loop; this can only happen if the + // `break` was not inside a loop at all, which is caught by the loop-checking pass. + assert!(self.tcx.sess.err_count() > 0); + } - ctxt.may_break = true; - } - // Otherwise, we failed to find the enclosing breakable; this can only happen if the - // `break` target was not found, which is caught in HIR lowering and reported by the - // loop-checking pass. - tcx.types.never + // the type of a `break` is always `!`, since it diverges + tcx.types.never } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { @@ -3645,51 +3652,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { - let unified = self.tcx.mk_nil(); - let coerce_to = unified; - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: true, - }; - self.with_breakable_ctxt(expr.id, ctxt, || { - self.check_expr_has_type(&cond, tcx.types.bool); - let cond_diverging = self.diverges.get(); - self.check_block_no_value(&body); + let ctxt = BreakableCtxt { + // cannot use break with a value from a while loop + coerce: None, + may_break: true, + }; - // We may never reach the body so it diverging means nothing. - self.diverges.set(cond_diverging); - }); + self.with_breakable_ctxt(expr.id, ctxt, || { + self.check_expr_has_type(&cond, tcx.types.bool); + let cond_diverging = self.diverges.get(); + self.check_block_no_value(&body); - if self.has_errors.get() { - tcx.types.err - } else { - tcx.mk_nil() - } + // We may never reach the body so it diverging means nothing. + self.diverges.set(cond_diverging); + }); + + self.tcx.mk_nil() } - hir::ExprLoop(ref body, _, _) => { - let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(body.span)); - let coerce_to = expected.only_has_type(self).unwrap_or(unified); - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: false, - }; + hir::ExprLoop(ref body, _, source) => { + let coerce = match source { + // you can only use break with a value from a normal `loop { }` + hir::LoopSource::Loop => { + let coerce_to = expected.only_has_type_or_fresh_var(self, body.span); + Some(CoerceMany::new(coerce_to)) + } - let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || { - self.check_block_no_value(&body); - }); - if ctxt.may_break { - // No way to know whether it's diverging because - // of a `break` or an outer `break` or `return. - self.diverges.set(Diverges::Maybe); + hir::LoopSource::WhileLet | + hir::LoopSource::ForLoop => { + None + } + }; - ctxt.unified - } else { - tcx.types.never - } + let ctxt = BreakableCtxt { + coerce: coerce, + may_break: false, // will get updated if/when we find a `break` + }; + + let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || { + self.check_block_no_value(&body); + }); + + if ctxt.may_break { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return. + self.diverges.set(Diverges::Maybe); + } + + // If we permit break with a value, then result type is + // the LUB of the breaks (possibly ! if none); else, it + // is nil. This makes sense because infinite loops + // (which would have type !) are only possible iff we + // permit break with a value [1]. + assert!(ctxt.coerce.is_some() || ctxt.may_break); // [1] + ctxt.coerce.map(|c| c.complete(self)).unwrap_or(self.tcx.mk_nil()) } hir::ExprMatch(ref discrim, ref arms, match_src) => { self.check_match(expr, &discrim, arms, expected, match_src) diff --git a/src/test/compile-fail/issue-27042.rs b/src/test/compile-fail/issue-27042.rs index f31389f1337d..23afa4b62963 100644 --- a/src/test/compile-fail/issue-27042.rs +++ b/src/test/compile-fail/issue-27042.rs @@ -12,14 +12,14 @@ fn main() { let _: i32 = - 'a: //~ ERROR mismatched types - loop { break }; + 'a: // in this case, the citation is just the `break`: + loop { break }; //~ ERROR mismatched types let _: i32 = 'b: //~ ERROR mismatched types - while true { break }; + while true { break }; // but here we cite the whole loop let _: i32 = 'c: //~ ERROR mismatched types - for _ in None { break }; + for _ in None { break }; // but here we cite the whole loop let _: i32 = 'd: //~ ERROR mismatched types while let Some(_) = None { break }; diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index d4f295974869..a41432189920 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -40,37 +40,40 @@ fn main() { loop { break 'while_loop 123; //~^ ERROR `break` with value from a `while` loop - //~| ERROR mismatched types break 456; break 789; }; } - 'while_let_loop: while let Some(_) = Some(()) { + while let Some(_) = Some(()) { if break () { //~ ERROR `break` with value from a `while let` loop - break; - break None; - //~^ ERROR `break` with value from a `while let` loop - //~| ERROR mismatched types } + } + + while let Some(_) = Some(()) { + break None; + //~^ ERROR `break` with value from a `while let` loop + } + + 'while_let_loop: while let Some(_) = Some(()) { loop { break 'while_let_loop "nope"; //~^ ERROR `break` with value from a `while let` loop - //~| ERROR mismatched types break 33; }; } - 'for_loop: for _ in &[1,2,3] { + for _ in &[1,2,3] { break (); //~ ERROR `break` with value from a `for` loop break [()]; //~^ ERROR `break` with value from a `for` loop - //~| ERROR mismatched types + } + + 'for_loop: for _ in &[1,2,3] { loop { break Some(3); break 'for_loop Some(17); //~^ ERROR `break` with value from a `for` loop - //~| ERROR mismatched types }; } diff --git a/src/test/ui/loop-break-value-no-repeat.rs b/src/test/ui/loop-break-value-no-repeat.rs new file mode 100644 index 000000000000..790f796fae07 --- /dev/null +++ b/src/test/ui/loop-break-value-no-repeat.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. + +#![feature(loop_break_value)] +#![allow(unused_variables)] + +use std::ptr; + +// Test that we only report **one** error here and that is that +// `break` with an expression is illegal in this context. In +// particular, we don't report any mismatched types error, which is +// besides the point. + +fn main() { + for _ in &[1,2,3] { + break 22 + } +} diff --git a/src/test/ui/loop-break-value-no-repeat.stderr b/src/test/ui/loop-break-value-no-repeat.stderr new file mode 100644 index 000000000000..0d99abd3907d --- /dev/null +++ b/src/test/ui/loop-break-value-no-repeat.stderr @@ -0,0 +1,8 @@ +error[E0571]: `break` with value from a `for` loop + --> $DIR/loop-break-value-no-repeat.rs:23:9 + | +23 | break 22 + | ^^^^^^^^ can only break with a value inside `loop` + +error: aborting due to previous error + From 140165f22e5614a4f14e9f7175c5607dfaf12363 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:52:37 -0400 Subject: [PATCH 161/905] rewrite `ExprArray` processing to use `CoerceMany` --- src/librustc_typeck/check/mod.rs | 49 +++++++++++++------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 59f3ac739e0a..73d4e7db1d84 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3752,36 +3752,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { typ } hir::ExprArray(ref args) => { - let uty = expected.to_option(self).and_then(|uty| { - match uty.sty { - ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), - _ => None - } - }); + let uty = expected.to_option(self).and_then(|uty| { + match uty.sty { + ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), + _ => None + } + }); - let mut unified = self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)); - let coerce_to = uty.unwrap_or(unified); - - for (i, e) in args.iter().enumerate() { - let e_ty = self.check_expr_with_hint(e, coerce_to); - let cause = self.misc(e.span); - - // Special-case the first element, as it has no "previous expressions". - let result = if i == 0 { - self.try_coerce(e, e_ty, coerce_to) - } else { - let prev_elems = || args[..i].iter().map(|e| &*e); - self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty) - }; - - match result { - Ok(ty) => unified = ty, - Err(e) => { - self.report_mismatched_types(&cause, unified, e_ty, e).emit(); - } - } - } - tcx.mk_array(unified, args.len()) + let element_ty = if !args.is_empty() { + let coerce_to = uty.unwrap_or_else( + || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); + let mut coerce = CoerceMany::new(coerce_to); + for e in args { + let e_ty = self.check_expr_with_hint(e, coerce_to); + let cause = self.misc(e.span); + coerce.coerce(self, &cause, e, e_ty); + } + coerce.complete(self) + } else { + self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)) + }; + tcx.mk_array(element_ty, args.len()) } hir::ExprRepeat(ref element, count) => { let count = eval_length(self.tcx.global_tcx(), count, "repeat count") From cecccd9bef2ce56b91b7ac3b067f0afa2e7846db Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:53:02 -0400 Subject: [PATCH 162/905] whitespace changes, debug message --- src/librustc_typeck/check/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 73d4e7db1d84..21eaa0c2120d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1526,6 +1526,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if self.diverges.get() == Diverges::Always { self.diverges.set(Diverges::WarnedAlways); + debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); + self.tables.borrow_mut().lints.add_lint( lint::builtin::UNREACHABLE_CODE, id, span, @@ -2545,8 +2547,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Expectation::rvalue_hint(self, ty) }); - let checked_ty = self.check_expr_with_expectation(&arg, - expected.unwrap_or(ExpectHasType(formal_ty))); + let checked_ty = self.check_expr_with_expectation( + &arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced // to, which is `expected_ty` if `rvalue_hint` returns an // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. From 52e524a3578b7661d6430735c7cd51eeccdacb0b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:53:15 -0400 Subject: [PATCH 163/905] make `try_find_coercion_lub` private; we always use `CoerceMany` --- src/librustc_typeck/check/coercion.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a08faf2610e3..c420449cea09 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -715,13 +715,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Given some expressions, their known unified type and another expression, /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). - pub fn try_find_coercion_lub<'b, E, I>(&self, - cause: &ObligationCause<'tcx>, - exprs: E, - prev_ty: Ty<'tcx>, - new: &'b hir::Expr, - new_ty: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> + /// + /// This is really an internal helper. From outside the coercion + /// module, you should instantiate a `CoerceMany` instance. + fn try_find_coercion_lub<'b, E, I>(&self, + cause: &ObligationCause<'tcx>, + exprs: E, + prev_ty: Ty<'tcx>, + new: &'b hir::Expr, + new_ty: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> where E: Fn() -> I, I: IntoIterator { From 5cd99aa1677075baecbd5224861b36a7719e0f25 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 14:10:00 -0400 Subject: [PATCH 164/905] more detailed tests around diverging type variables --- .../compile-fail/defaulted-unit-warning.rs | 12 +- src/test/compile-fail/never-fallback.rs | 41 ------- .../diverging-fallback-control-flow.rs | 106 ++++++++++++++++++ ....rs => diverging-fallback-method-chain.rs} | 33 ++---- .../run-pass/diverging-fallback-option.rs | 22 ++++ 5 files changed, 140 insertions(+), 74 deletions(-) delete mode 100644 src/test/compile-fail/never-fallback.rs create mode 100644 src/test/run-pass/diverging-fallback-control-flow.rs rename src/test/run-pass/{unit-fallback.rs => diverging-fallback-method-chain.rs} (51%) create mode 100644 src/test/run-pass/diverging-fallback-option.rs diff --git a/src/test/compile-fail/defaulted-unit-warning.rs b/src/test/compile-fail/defaulted-unit-warning.rs index 5213a189714d..ed6263d0fdbd 100644 --- a/src/test/compile-fail/defaulted-unit-warning.rs +++ b/src/test/compile-fail/defaulted-unit-warning.rs @@ -22,16 +22,6 @@ impl Deserialize for () { } } -fn doit() -> Result<(), String> { - let _ = match Deserialize::deserialize() { - //~^ ERROR code relies on type - //~| WARNING previously accepted - Ok(x) => x, - Err(e) => return Err(e), - }; - Ok(()) -} - trait ImplementedForUnitButNotNever {} impl ImplementedForUnitButNotNever for () {} @@ -46,6 +36,6 @@ fn smeg() { } fn main() { - let _ = doit(); + smeg(); } diff --git a/src/test/compile-fail/never-fallback.rs b/src/test/compile-fail/never-fallback.rs deleted file mode 100644 index a43b1a45fe93..000000000000 --- a/src/test/compile-fail/never-fallback.rs +++ /dev/null @@ -1,41 +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. - -// Test that diverging types default to ! when feature(never_type) is enabled. This test is the -// same as run-pass/unit-fallback.rs except that ! is enabled. - -#![feature(never_type)] - -trait Balls: Sized { - fn smeg() -> Result; -} - -impl Balls for () { - fn smeg() -> Result<(), ()> { Ok(()) } -} - -struct Flah; - -impl Flah { - fn flah(&self) -> Result { - T::smeg() - } -} - -fn doit() -> Result<(), ()> { - // The type of _ is unconstrained here and should default to ! - let _ = try!(Flah.flah()); //~ ERROR the trait bound - Ok(()) -} - -fn main() { - let _ = doit(); -} - diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs new file mode 100644 index 000000000000..656e90d2d52d --- /dev/null +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -0,0 +1,106 @@ +// 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. + +// Test various cases where we permit an unconstrained variable +// to fallback based on control-flow. +// +// These represent current behavior, but are pretty dubious. I would +// like to revisit these and potentially change them. --nmatsakis + +#![feature(never_type)] +#![feature(loop_break_value)] + +trait BadDefault { + fn default() -> Self; +} + +impl BadDefault for u32 { + fn default() -> Self { + 0 + } +} + +impl BadDefault for ! { + fn default() -> ! { + panic!() + } +} + +fn assignment() { + let x; + + if true { + x = BadDefault::default(); + } else { + x = return; + } +} + +fn assignment_rev() { + let x; + + if true { + x = return; + } else { + x = BadDefault::default(); + } +} + +fn if_then_else() { + let _x = if true { + BadDefault::default() + } else { + return; + }; +} + +fn if_then_else_rev() { + let _x = if true { + return; + } else { + BadDefault::default() + }; +} + +fn match_arm() { + let _x = match Ok(BadDefault::default()) { + Ok(v) => v, + Err(()) => return, + }; +} + +fn match_arm_rev() { + let _x = match Ok(BadDefault::default()) { + Err(()) => return, + Ok(v) => v, + }; +} + +fn loop_break() { + let _x = loop { + if false { + break return; + } else { + break BadDefault::default(); + } + }; +} + +fn loop_break_rev() { + let _x = loop { + if false { + break return; + } else { + break BadDefault::default(); + } + }; +} + +fn main() { } diff --git a/src/test/run-pass/unit-fallback.rs b/src/test/run-pass/diverging-fallback-method-chain.rs similarity index 51% rename from src/test/run-pass/unit-fallback.rs rename to src/test/run-pass/diverging-fallback-method-chain.rs index 2babc6348e10..664a329c228a 100644 --- a/src/test/run-pass/unit-fallback.rs +++ b/src/test/run-pass/diverging-fallback-method-chain.rs @@ -8,31 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that diverging types default to () (with feature(never_type) disabled). +// Test a regression found when building compiler. The `produce()` +// error type `T` winds up getting unified with result of `x.parse()`; +// the type of the closure given to `unwrap_or_else` needs to be +// inferred to `usize`. -trait Balls: Sized { - fn smeg() -> Result; -} +use std::num::ParseIntError; -impl Balls for () { - fn smeg() -> Result<(), ()> { Ok(()) } -} - -struct Flah; - -impl Flah { - fn flah(&self) -> Result { - T::smeg() - } -} - -fn doit() -> Result<(), ()> { - // The type of _ is unconstrained here and should default to () - let _ = try!(Flah.flah()); - Ok(()) +fn produce() -> Result<&'static str, T> { + Ok("22") } fn main() { - let _ = doit(); + let x: usize = produce() + .and_then(|x| x.parse()) + .unwrap_or_else(|_| panic!()); + println!("{}", x); } - diff --git a/src/test/run-pass/diverging-fallback-option.rs b/src/test/run-pass/diverging-fallback-option.rs new file mode 100644 index 000000000000..49f90e7c91f3 --- /dev/null +++ b/src/test/run-pass/diverging-fallback-option.rs @@ -0,0 +1,22 @@ +// 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. + +#![allow(warnings)] + +// Here the type of `c` is `Option`, where `?T` is unconstrained. +// Because there is data-flow from the `{ return; }` block, which +// diverges and hence has type `!`, into `c`, we will default `?T` to +// `!`, and hence this code compiles rather than failing and requiring +// a type annotation. + +fn main() { + let c = Some({ return; }); + c.unwrap(); +} From 2f526cc89773d3b14c3d909152697678bc8fa7a1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 11:54:23 -0400 Subject: [PATCH 165/905] we now get an extra unreachable code warning in this test --- src/test/compile-fail/never-assign-dead-code.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 57e0bca6a6d7..d8752e1c050f 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -16,5 +16,6 @@ fn main() { let x: ! = panic!("aah"); //~ ERROR unused drop(x); //~ ERROR unreachable + //~^ ERROR unreachable } From f11b7d33bb71a78beb6a4671d53d2e89a2afc0ef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 18 Mar 2017 15:22:48 -0400 Subject: [PATCH 166/905] add regression test for #39808 Fixes #39808 --- src/test/run-pass/issue-39808.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs index f83e9328e587..00c2bdc8cc99 100644 --- a/src/test/run-pass/issue-39808.rs +++ b/src/test/run-pass/issue-39808.rs @@ -8,14 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regression test: even though `Ok` is dead-code, its type needs to -// be influenced by the result of `Err` or else we get a "type -// variable unconstrained" error. +#![allow(unreachable_code)] + +// Regression test for #39808. The type parameter of `Owned` was +// considered to be "unconstrained" because the type resulting from +// `format!` (`String`) was not being propagated upward, owing to the +// fact that the expression diverges. + +use std::borrow::Cow; fn main() { let _ = if false { - Ok(return) + Cow::Owned(format!("{:?}", panic!())) /* as Cow */ // uncomment to fix } else { - Err("") + Cow::Borrowed("") }; } From a60e27e25b88dd7febdb3f878a09bef08c03eb41 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 09:19:49 -0400 Subject: [PATCH 167/905] pacify the mercilous tidy --- src/librustc_typeck/check/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 21eaa0c2120d..65e7e240cc36 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3605,8 +3605,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ctxt.may_break = true; } else { - // Otherwise, we failed to find the enclosing loop; this can only happen if the - // `break` was not inside a loop at all, which is caught by the loop-checking pass. + // Otherwise, we failed to find the enclosing loop; + // this can only happen if the `break` was not + // inside a loop at all, which is caught by the + // loop-checking pass. assert!(self.tcx.sess.err_count() > 0); } From 609bfe82fd1c1207ab59f6c08bbadf45e587bd4a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 09:41:41 -0400 Subject: [PATCH 168/905] cherry-pick over the tests I wrote for the reachability code For the most part, the current code performs similarly, although it differs in some particulars. I'll be nice to have these tests for judging future changes, as well. --- src/test/ui/reachable/README.md | 7 +++ src/test/ui/reachable/expr_add.rs | 28 ++++++++++++ src/test/ui/reachable/expr_add.stderr | 14 ++++++ src/test/ui/reachable/expr_again.rs | 20 +++++++++ src/test/ui/reachable/expr_again.stderr | 15 +++++++ src/test/ui/reachable/expr_andand.rs | 21 +++++++++ src/test/ui/reachable/expr_andand.stderr | 0 src/test/ui/reachable/expr_array.rs | 28 ++++++++++++ src/test/ui/reachable/expr_array.stderr | 20 +++++++++ src/test/ui/reachable/expr_assign.rs | 39 +++++++++++++++++ src/test/ui/reachable/expr_assign.stderr | 26 ++++++++++++ src/test/ui/reachable/expr_block.rs | 41 ++++++++++++++++++ src/test/ui/reachable/expr_block.stderr | 22 ++++++++++ src/test/ui/reachable/expr_box.rs | 18 ++++++++ src/test/ui/reachable/expr_box.stderr | 14 ++++++ src/test/ui/reachable/expr_call.rs | 31 ++++++++++++++ src/test/ui/reachable/expr_call.stderr | 20 +++++++++ src/test/ui/reachable/expr_cast.rs | 23 ++++++++++ src/test/ui/reachable/expr_cast.stderr | 14 ++++++ src/test/ui/reachable/expr_if.rs | 41 ++++++++++++++++++ src/test/ui/reachable/expr_if.stderr | 15 +++++++ src/test/ui/reachable/expr_loop.rs | 44 +++++++++++++++++++ src/test/ui/reachable/expr_loop.stderr | 31 ++++++++++++++ src/test/ui/reachable/expr_match.rs | 54 ++++++++++++++++++++++++ src/test/ui/reachable/expr_match.stderr | 30 +++++++++++++ src/test/ui/reachable/expr_method.rs | 34 +++++++++++++++ src/test/ui/reachable/expr_method.stderr | 20 +++++++++ src/test/ui/reachable/expr_oror.rs | 20 +++++++++ src/test/ui/reachable/expr_oror.stderr | 0 src/test/ui/reachable/expr_repeat.rs | 23 ++++++++++ src/test/ui/reachable/expr_repeat.stderr | 14 ++++++ src/test/ui/reachable/expr_return.rs | 24 +++++++++++ src/test/ui/reachable/expr_return.stderr | 14 ++++++ src/test/ui/reachable/expr_struct.rs | 43 +++++++++++++++++++ src/test/ui/reachable/expr_struct.stderr | 32 ++++++++++++++ src/test/ui/reachable/expr_tup.rs | 28 ++++++++++++ src/test/ui/reachable/expr_tup.stderr | 20 +++++++++ src/test/ui/reachable/expr_type.rs | 23 ++++++++++ src/test/ui/reachable/expr_type.stderr | 14 ++++++ src/test/ui/reachable/expr_unary.rs | 21 +++++++++ src/test/ui/reachable/expr_unary.stderr | 8 ++++ src/test/ui/reachable/expr_while.rs | 38 +++++++++++++++++ src/test/ui/reachable/expr_while.stderr | 31 ++++++++++++++ 43 files changed, 1023 insertions(+) create mode 100644 src/test/ui/reachable/README.md create mode 100644 src/test/ui/reachable/expr_add.rs create mode 100644 src/test/ui/reachable/expr_add.stderr create mode 100644 src/test/ui/reachable/expr_again.rs create mode 100644 src/test/ui/reachable/expr_again.stderr create mode 100644 src/test/ui/reachable/expr_andand.rs create mode 100644 src/test/ui/reachable/expr_andand.stderr create mode 100644 src/test/ui/reachable/expr_array.rs create mode 100644 src/test/ui/reachable/expr_array.stderr create mode 100644 src/test/ui/reachable/expr_assign.rs create mode 100644 src/test/ui/reachable/expr_assign.stderr create mode 100644 src/test/ui/reachable/expr_block.rs create mode 100644 src/test/ui/reachable/expr_block.stderr create mode 100644 src/test/ui/reachable/expr_box.rs create mode 100644 src/test/ui/reachable/expr_box.stderr create mode 100644 src/test/ui/reachable/expr_call.rs create mode 100644 src/test/ui/reachable/expr_call.stderr create mode 100644 src/test/ui/reachable/expr_cast.rs create mode 100644 src/test/ui/reachable/expr_cast.stderr create mode 100644 src/test/ui/reachable/expr_if.rs create mode 100644 src/test/ui/reachable/expr_if.stderr create mode 100644 src/test/ui/reachable/expr_loop.rs create mode 100644 src/test/ui/reachable/expr_loop.stderr create mode 100644 src/test/ui/reachable/expr_match.rs create mode 100644 src/test/ui/reachable/expr_match.stderr create mode 100644 src/test/ui/reachable/expr_method.rs create mode 100644 src/test/ui/reachable/expr_method.stderr create mode 100644 src/test/ui/reachable/expr_oror.rs create mode 100644 src/test/ui/reachable/expr_oror.stderr create mode 100644 src/test/ui/reachable/expr_repeat.rs create mode 100644 src/test/ui/reachable/expr_repeat.stderr create mode 100644 src/test/ui/reachable/expr_return.rs create mode 100644 src/test/ui/reachable/expr_return.stderr create mode 100644 src/test/ui/reachable/expr_struct.rs create mode 100644 src/test/ui/reachable/expr_struct.stderr create mode 100644 src/test/ui/reachable/expr_tup.rs create mode 100644 src/test/ui/reachable/expr_tup.stderr create mode 100644 src/test/ui/reachable/expr_type.rs create mode 100644 src/test/ui/reachable/expr_type.stderr create mode 100644 src/test/ui/reachable/expr_unary.rs create mode 100644 src/test/ui/reachable/expr_unary.stderr create mode 100644 src/test/ui/reachable/expr_while.rs create mode 100644 src/test/ui/reachable/expr_while.stderr diff --git a/src/test/ui/reachable/README.md b/src/test/ui/reachable/README.md new file mode 100644 index 000000000000..8bed5fba7a2e --- /dev/null +++ b/src/test/ui/reachable/README.md @@ -0,0 +1,7 @@ +A variety of tests around reachability. These tests in general check +two things: + +- that we get unreachable code warnings in reasonable locations; +- that we permit coercions **into** `!` from expressions which + diverge, where an expression "diverges" if it must execute some + subexpression of type `!`, or it has type `!` itself. diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs new file mode 100644 index 000000000000..87d017adf681 --- /dev/null +++ b/src/test/ui/reachable/expr_add.rs @@ -0,0 +1,28 @@ +// 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. + +#![feature(never_type)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +use std::ops; + +struct Foo; + +impl ops::Add for Foo { + type Output = !; + fn add(self, rhs: !) -> ! { + unimplemented!() + } +} + +fn main() { + let x = Foo + return; +} diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr new file mode 100644 index 000000000000..1a2cc252051b --- /dev/null +++ b/src/test/ui/reachable/expr_add.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_add.rs:27:13 + | +27 | let x = Foo + return; + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_add.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_again.rs b/src/test/ui/reachable/expr_again.rs new file mode 100644 index 000000000000..cdbdb8dc0dbb --- /dev/null +++ b/src/test/ui/reachable/expr_again.rs @@ -0,0 +1,20 @@ +// 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. + +#![feature(box_syntax)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +fn main() { + let x = loop { + continue; + println!("hi"); + }; +} diff --git a/src/test/ui/reachable/expr_again.stderr b/src/test/ui/reachable/expr_again.stderr new file mode 100644 index 000000000000..bf4e4dc4711c --- /dev/null +++ b/src/test/ui/reachable/expr_again.stderr @@ -0,0 +1,15 @@ +error: unreachable statement + --> $DIR/expr_again.rs:18:9 + | +18 | println!("hi"); + | ^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_again.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_andand.rs b/src/test/ui/reachable/expr_andand.rs new file mode 100644 index 000000000000..af404d03097b --- /dev/null +++ b/src/test/ui/reachable/expr_andand.rs @@ -0,0 +1,21 @@ +// 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. + +#![allow(unused_variables)] +#![allow(dead_code)] +#![deny(unreachable_code)] + +fn foo() { + // No error here. + let x = false && (return); + println!("I am not dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_andand.stderr b/src/test/ui/reachable/expr_andand.stderr new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/ui/reachable/expr_array.rs b/src/test/ui/reachable/expr_array.rs new file mode 100644 index 000000000000..00e8be077254 --- /dev/null +++ b/src/test/ui/reachable/expr_array.rs @@ -0,0 +1,28 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the `22` is unreachable: + let x: [usize; 2] = [return, 22]; +} + +fn b() { + // the `array is unreachable: + let x: [usize; 2] = [22, return]; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_array.stderr b/src/test/ui/reachable/expr_array.stderr new file mode 100644 index 000000000000..f8dbdb5f8bb6 --- /dev/null +++ b/src/test/ui/reachable/expr_array.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_array.rs:20:34 + | +20 | let x: [usize; 2] = [return, 22]; + | ^^ + | +note: lint level defined here + --> $DIR/expr_array.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_array.rs:25:25 + | +25 | let x: [usize; 2] = [22, return]; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs new file mode 100644 index 000000000000..1b9357013d27 --- /dev/null +++ b/src/test/ui/reachable/expr_assign.rs @@ -0,0 +1,39 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + // No error here. + let x; + x = return; +} + +fn bar() { + use std::ptr; + let p: *mut ! = ptr::null_mut::(); + unsafe { + // Here we consider the `return` unreachable because + // "evaluating" the `*p` has type `!`. This is somewhat + // dubious, I suppose. + *p = return; + } +} + +fn baz() { + let mut i = 0; + *{return; &mut i} = 22; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr new file mode 100644 index 000000000000..807f6a1c1d58 --- /dev/null +++ b/src/test/ui/reachable/expr_assign.stderr @@ -0,0 +1,26 @@ +error: unreachable expression + --> $DIR/expr_assign.rs:20:5 + | +20 | x = return; + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_assign.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_assign.rs:30:14 + | +30 | *p = return; + | ^^^^^^ + +error: unreachable expression + --> $DIR/expr_assign.rs:36:15 + | +36 | *{return; &mut i} = 22; + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_block.rs b/src/test/ui/reachable/expr_block.rs new file mode 100644 index 000000000000..093589b4dc83 --- /dev/null +++ b/src/test/ui/reachable/expr_block.rs @@ -0,0 +1,41 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + // Here the tail expression is considered unreachable: + let x = { + return; + 22 + }; +} + +fn b() { + // Here the `x` assignment is considered unreachable, not the block: + let x = { + return; + }; +} + +fn c() { + // Here the `println!` is unreachable: + let x = { + return; + println!("foo"); + 22 + }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr new file mode 100644 index 000000000000..542ce1c3fd9c --- /dev/null +++ b/src/test/ui/reachable/expr_block.stderr @@ -0,0 +1,22 @@ +error: unreachable expression + --> $DIR/expr_block.rs:21:9 + | +21 | 22 + | ^^ + | +note: lint level defined here + --> $DIR/expr_block.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_block.rs:36:9 + | +36 | println!("foo"); + | ^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_box.rs b/src/test/ui/reachable/expr_box.rs new file mode 100644 index 000000000000..6509b608335a --- /dev/null +++ b/src/test/ui/reachable/expr_box.rs @@ -0,0 +1,18 @@ +// 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. + +#![feature(box_syntax)] +#![allow(unused_variables)] +#![deny(unreachable_code)] + +fn main() { + let x = box return; + println!("hi"); +} diff --git a/src/test/ui/reachable/expr_box.stderr b/src/test/ui/reachable/expr_box.stderr new file mode 100644 index 000000000000..78ba231cef9f --- /dev/null +++ b/src/test/ui/reachable/expr_box.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_box.rs:16:13 + | +16 | let x = box return; + | ^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_box.rs:13:9 + | +13 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs new file mode 100644 index 000000000000..8d9f303df7fd --- /dev/null +++ b/src/test/ui/reachable/expr_call.rs @@ -0,0 +1,31 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo(x: !, y: usize) { } + +fn bar(x: !) { } + +fn a() { + // the `22` is unreachable: + foo(return, 22); +} + +fn b() { + // the call is unreachable: + bar(return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr new file mode 100644 index 000000000000..5526827f59fc --- /dev/null +++ b/src/test/ui/reachable/expr_call.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_call.rs:23:17 + | +23 | foo(return, 22); + | ^^ + | +note: lint level defined here + --> $DIR/expr_call.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_call.rs:28:5 + | +28 | bar(return); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs new file mode 100644 index 000000000000..926ef864ebf2 --- /dev/null +++ b/src/test/ui/reachable/expr_cast.rs @@ -0,0 +1,23 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the cast is unreachable: + let x = {return} as !; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_cast.stderr b/src/test/ui/reachable/expr_cast.stderr new file mode 100644 index 000000000000..a22300dcc139 --- /dev/null +++ b/src/test/ui/reachable/expr_cast.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_cast.rs:20:13 + | +20 | let x = {return} as !; + | ^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_cast.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs new file mode 100644 index 000000000000..2a265e772f35 --- /dev/null +++ b/src/test/ui/reachable/expr_if.rs @@ -0,0 +1,41 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + if {return} { + println!("Hello, world!"); + } +} + +fn bar() { + if {true} { + return; + } + println!("I am not dead."); +} + +fn baz() { + if {true} { + return; + } else { + return; + } + // As the next action to be taken after the if arms, we should + // report the `println!` as unreachable: + println!("But I am."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr new file mode 100644 index 000000000000..2cf17474f6e9 --- /dev/null +++ b/src/test/ui/reachable/expr_if.stderr @@ -0,0 +1,15 @@ +error: unreachable statement + --> $DIR/expr_if.rs:38:5 + | +38 | println!("But I am."); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_if.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_loop.rs b/src/test/ui/reachable/expr_loop.rs new file mode 100644 index 000000000000..3ed4b2dcf0cf --- /dev/null +++ b/src/test/ui/reachable/expr_loop.rs @@ -0,0 +1,44 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + loop { return; } + println!("I am dead."); +} + +fn b() { + loop { + break; + } + println!("I am not dead."); +} + +fn c() { + loop { return; } + println!("I am dead."); +} + +fn d() { + 'outer: loop { loop { break 'outer; } } + println!("I am not dead."); +} + +fn e() { + loop { 'middle: loop { loop { break 'middle; } } } + println!("I am dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_loop.stderr b/src/test/ui/reachable/expr_loop.stderr new file mode 100644 index 000000000000..6e98e754c54d --- /dev/null +++ b/src/test/ui/reachable/expr_loop.stderr @@ -0,0 +1,31 @@ +error: unreachable statement + --> $DIR/expr_loop.rs:19:5 + | +19 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_loop.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_loop.rs:31:5 + | +31 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_loop.rs:41:5 + | +41 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_match.rs b/src/test/ui/reachable/expr_match.rs new file mode 100644 index 000000000000..23bdcc035b22 --- /dev/null +++ b/src/test/ui/reachable/expr_match.rs @@ -0,0 +1,54 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn a() { + // The match is considered unreachable here, because the `return` + // diverges: + match {return} { } +} + +fn b() { + match () { () => return } + println!("I am dead"); +} + +fn c() { + match () { () if false => return, () => () } + println!("I am not dead"); +} + +fn d() { + match () { () if false => return, () => return } + println!("I am dead"); +} + +fn e() { + // Here the compiler fails to figure out that the `println` is dead. + match () { () if return => (), () => return } + println!("I am dead"); +} + +fn f() { + match Some(()) { None => (), Some(()) => return } + println!("I am not dead"); +} + +fn g() { + match Some(()) { None => return, Some(()) => () } + println!("I am not dead"); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr new file mode 100644 index 000000000000..f5857a5b345e --- /dev/null +++ b/src/test/ui/reachable/expr_match.stderr @@ -0,0 +1,30 @@ +error: unreachable expression + --> $DIR/expr_match.rs:20:5 + | +20 | match {return} { } + | ^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_match.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_match.rs:25:5 + | +25 | println!("I am dead"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_match.rs:35:5 + | +35 | println!("I am dead"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs new file mode 100644 index 000000000000..f1d979d7df79 --- /dev/null +++ b/src/test/ui/reachable/expr_method.rs @@ -0,0 +1,34 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +struct Foo; + +impl Foo { + fn foo(&self, x: !, y: usize) { } + fn bar(&self, x: !) { } +} + +fn a() { + // the `22` is unreachable: + Foo.foo(return, 22); +} + +fn b() { + // the call is unreachable: + Foo.bar(return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr new file mode 100644 index 000000000000..177d4352a376 --- /dev/null +++ b/src/test/ui/reachable/expr_method.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_method.rs:26:21 + | +26 | Foo.foo(return, 22); + | ^^ + | +note: lint level defined here + --> $DIR/expr_method.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_method.rs:31:5 + | +31 | Foo.bar(return); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_oror.rs b/src/test/ui/reachable/expr_oror.rs new file mode 100644 index 000000000000..d01304d4034b --- /dev/null +++ b/src/test/ui/reachable/expr_oror.rs @@ -0,0 +1,20 @@ +// 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. + +#![allow(unused_variables)] +#![allow(dead_code)] +#![deny(unreachable_code)] + +fn foo() { + let x = false || (return); + println!("I am not dead."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_oror.stderr b/src/test/ui/reachable/expr_oror.stderr new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/ui/reachable/expr_repeat.rs b/src/test/ui/reachable/expr_repeat.rs new file mode 100644 index 000000000000..6078d6d5bde4 --- /dev/null +++ b/src/test/ui/reachable/expr_repeat.rs @@ -0,0 +1,23 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the repeat is unreachable: + let x: [usize; 2] = [return; 2]; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_repeat.stderr b/src/test/ui/reachable/expr_repeat.stderr new file mode 100644 index 000000000000..19afc5dd7b5e --- /dev/null +++ b/src/test/ui/reachable/expr_repeat.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_repeat.rs:20:25 + | +20 | let x: [usize; 2] = [return; 2]; + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_repeat.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_return.rs b/src/test/ui/reachable/expr_return.rs new file mode 100644 index 000000000000..c640ca066302 --- /dev/null +++ b/src/test/ui/reachable/expr_return.rs @@ -0,0 +1,24 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // Here we issue that the "2nd-innermost" return is unreachable, + // but we stop there. + let x = {return {return {return;}}}; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_return.stderr b/src/test/ui/reachable/expr_return.stderr new file mode 100644 index 000000000000..3eb70a4dd7c8 --- /dev/null +++ b/src/test/ui/reachable/expr_return.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_return.rs:21:22 + | +21 | let x = {return {return {return;}}}; + | ^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_return.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_struct.rs b/src/test/ui/reachable/expr_struct.rs new file mode 100644 index 000000000000..09e31819279f --- /dev/null +++ b/src/test/ui/reachable/expr_struct.rs @@ -0,0 +1,43 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +struct Foo { + a: usize, + b: usize, +} + +fn a() { + // struct expr is unreachable: + let x = Foo { a: 22, b: 33, ..return }; +} + +fn b() { + // the `33` is unreachable: + let x = Foo { a: return, b: 33, ..return }; +} + +fn c() { + // the `..return` is unreachable: + let x = Foo { a: 22, b: return, ..return }; +} + +fn d() { + // the struct expr is unreachable: + let x = Foo { a: 22, b: return }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_struct.stderr b/src/test/ui/reachable/expr_struct.stderr new file mode 100644 index 000000000000..4b7ac6604132 --- /dev/null +++ b/src/test/ui/reachable/expr_struct.stderr @@ -0,0 +1,32 @@ +error: unreachable expression + --> $DIR/expr_struct.rs:25:13 + | +25 | let x = Foo { a: 22, b: 33, ..return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_struct.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:30:33 + | +30 | let x = Foo { a: return, b: 33, ..return }; + | ^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:35:39 + | +35 | let x = Foo { a: 22, b: return, ..return }; + | ^^^^^^ + +error: unreachable expression + --> $DIR/expr_struct.rs:40:13 + | +40 | let x = Foo { a: 22, b: return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/reachable/expr_tup.rs b/src/test/ui/reachable/expr_tup.rs new file mode 100644 index 000000000000..7c75296de6c5 --- /dev/null +++ b/src/test/ui/reachable/expr_tup.rs @@ -0,0 +1,28 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the `2` is unreachable: + let x: (usize, usize) = (return, 2); +} + +fn b() { + // the tuple is unreachable: + let x: (usize, usize) = (2, return); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_tup.stderr b/src/test/ui/reachable/expr_tup.stderr new file mode 100644 index 000000000000..63f477fd0c37 --- /dev/null +++ b/src/test/ui/reachable/expr_tup.stderr @@ -0,0 +1,20 @@ +error: unreachable expression + --> $DIR/expr_tup.rs:20:38 + | +20 | let x: (usize, usize) = (return, 2); + | ^ + | +note: lint level defined here + --> $DIR/expr_tup.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: unreachable expression + --> $DIR/expr_tup.rs:25:29 + | +25 | let x: (usize, usize) = (2, return); + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs new file mode 100644 index 000000000000..2fa277c382e8 --- /dev/null +++ b/src/test/ui/reachable/expr_type.rs @@ -0,0 +1,23 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] +#![feature(type_ascription)] + +fn a() { + // the cast is unreachable: + let x = {return}: !; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_type.stderr b/src/test/ui/reachable/expr_type.stderr new file mode 100644 index 000000000000..6ed79974ccb7 --- /dev/null +++ b/src/test/ui/reachable/expr_type.stderr @@ -0,0 +1,14 @@ +error: unreachable expression + --> $DIR/expr_type.rs:20:13 + | +20 | let x = {return}: !; + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_type.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs new file mode 100644 index 000000000000..57901fbaa7c4 --- /dev/null +++ b/src/test/ui/reachable/expr_unary.rs @@ -0,0 +1,21 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + let x: ! = ! { return; 22 }; +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr new file mode 100644 index 000000000000..11172652d844 --- /dev/null +++ b/src/test/ui/reachable/expr_unary.stderr @@ -0,0 +1,8 @@ +error: cannot apply unary operator `!` to type `!` + --> $DIR/expr_unary.rs:18:16 + | +18 | let x: ! = ! { return; 22 }; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_while.rs b/src/test/ui/reachable/expr_while.rs new file mode 100644 index 000000000000..7dcd609fbc8f --- /dev/null +++ b/src/test/ui/reachable/expr_while.rs @@ -0,0 +1,38 @@ +// 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. + +#![allow(unused_variables)] +#![allow(unused_assignments)] +#![allow(dead_code)] +#![deny(unreachable_code)] +#![feature(never_type)] + +fn foo() { + while {return} { + println!("Hello, world!"); + } +} + +fn bar() { + while {true} { + return; + } + println!("I am not dead."); +} + +fn baz() { + // Here, we cite the `while` loop as dead. + while {return} { + println!("I am dead."); + } + println!("I am, too."); +} + +fn main() { } diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr new file mode 100644 index 000000000000..066cfc86c646 --- /dev/null +++ b/src/test/ui/reachable/expr_while.stderr @@ -0,0 +1,31 @@ +error: unreachable statement + --> $DIR/expr_while.rs:19:9 + | +19 | println!("Hello, world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_while.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_while.rs:33:9 + | +33 | println!("I am dead."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: unreachable statement + --> $DIR/expr_while.rs:35:5 + | +35 | println!("I am, too."); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to 3 previous errors + From bad79484fb99d40f48e3b84776699526a37513e0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 15:37:57 -0400 Subject: [PATCH 169/905] avoid allocating a vector when the coercion sites are known upfront --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/autoderef.rs | 12 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/coercion.rs | 174 +++++++++++++++----- src/librustc_typeck/check/method/confirm.rs | 4 +- src/librustc_typeck/check/mod.rs | 18 +- src/librustc_typeck/lib.rs | 1 + 7 files changed, 154 insertions(+), 59 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index f0d2598a0fb2..5ca8f2c01c58 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -474,7 +474,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), }; - CoerceMany::new(coerce_first) + CoerceMany::with_coercion_sites(coerce_first, arms) }; for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 1aab4853a4f6..647adbbb82f2 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,6 +12,7 @@ use astconv::AstConv; use super::FnCtxt; +use check::coercion::AsCoercionSite; use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; @@ -148,16 +149,16 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.fcx.resolve_type_vars_if_possible(&self.cur_ty) } - pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) - where I: IntoIterator + pub fn finalize(self, pref: LvaluePreference, exprs: &[E]) + where E: AsCoercionSite { let fcx = self.fcx; fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); } - pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I) - -> InferOk<'tcx, ()> - where I: IntoIterator + pub fn finalize_as_infer_ok(self, pref: LvaluePreference, exprs: &[E]) + -> InferOk<'tcx, ()> + where E: AsCoercionSite { let methods: Vec<_> = self.steps .iter() @@ -176,6 +177,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.obligations); for expr in exprs { + let expr = expr.as_coercion_site(); debug!("finalize - finalizing #{} - {:?}", expr.id, expr); for (n, method) in methods.iter().enumerate() { if let &Some(method) = method { diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 529ee107c46c..f9bc947a9735 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) .next(); let callee_ty = autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr)); + autoderef.finalize(LvaluePreference::NoPreference, &[callee_expr]); let output = match result { None => { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c420449cea09..eba58df781f1 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -76,6 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use syntax::abi; use syntax::feature_gate; +use syntax::ptr::P; use std::collections::VecDeque; use std::ops::Deref; @@ -155,11 +156,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }) } - fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> - where E: Fn() -> I, - I: IntoIterator + fn coerce(&self, exprs: &[E], a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> + where E: AsCoercionSite { - let a = self.shallow_resolve(a); debug!("Coerce.tys({:?} => {:?})", a, b); @@ -239,15 +238,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. - fn coerce_borrowed_pointer<'a, E, I>(&self, - exprs: &E, - a: Ty<'tcx>, - b: Ty<'tcx>, - r_b: &'tcx ty::Region, - mt_b: TypeAndMut<'tcx>) - -> CoerceResult<'tcx> - where E: Fn() -> I, - I: IntoIterator + fn coerce_borrowed_pointer(&self, + exprs: &[E], + a: Ty<'tcx>, + b: Ty<'tcx>, + r_b: &'tcx ty::Region, + mt_b: TypeAndMut<'tcx>) + -> CoerceResult<'tcx> + where E: AsCoercionSite { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); @@ -424,7 +422,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { autoref); let pref = LvaluePreference::from_mutbl(mt_b.mutbl); - obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations); + obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations); success(Adjust::DerefRef { autoderefs: autoderefs, @@ -699,7 +697,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { - let ok = coerce.coerce(&|| Some(expr), source, target)?; + let ok = coerce.coerce(&[expr], source, target)?; let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); @@ -718,15 +716,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// /// This is really an internal helper. From outside the coercion /// module, you should instantiate a `CoerceMany` instance. - fn try_find_coercion_lub<'b, E, I>(&self, - cause: &ObligationCause<'tcx>, - exprs: E, - prev_ty: Ty<'tcx>, - new: &'b hir::Expr, - new_ty: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> - where E: Fn() -> I, - I: IntoIterator + fn try_find_coercion_lub(&self, + cause: &ObligationCause<'tcx>, + exprs: &[E], + prev_ty: Ty<'tcx>, + new: &hir::Expr, + new_ty: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where E: AsCoercionSite { let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); @@ -758,7 +755,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = self.tcx.mk_fn_ptr(fty); - for expr in exprs().into_iter().chain(Some(new)) { + for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { // No adjustments can produce a fn item, so this should never trip. assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); self.write_adjustment(expr.id, Adjustment { @@ -778,7 +775,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(&[new], new_ty, prev_ty)); match result { Ok(ok) => { let adjustment = self.register_infer_ok_obligations(ok); @@ -794,7 +791,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Then try to coerce the previous expressions to the type of the new one. // This requires ensuring there are no coercions applied to *any* of the // previous expressions, other than noop reborrows (ignoring lifetimes). - for expr in exprs() { + for expr in exprs { + let expr = expr.as_coercion_site(); let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) { Some(Adjust::DerefRef { autoderefs: 1, @@ -838,7 +836,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { let mut tables = self.tables.borrow_mut(); - for expr in exprs() { + for expr in exprs { + let expr = expr.as_coercion_site(); if let Some(&mut Adjustment { kind: Adjust::NeverToAny, ref mut target @@ -897,25 +896,61 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// let final_ty = coerce.complete(fcx); /// ``` #[derive(Clone)] // (*) -pub struct CoerceMany<'gcx: 'tcx, 'tcx> { +pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> + where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, +{ expected_ty: Ty<'tcx>, final_ty: Option>, - expressions: Vec<&'gcx hir::Expr>, + expressions: Expressions<'gcx, 'exprs, E>, + pushed: usize, +} + +/// The type of a `CoerceMany` that is storing up the expressions into +/// a buffer. We use this in `check/mod.rs` for things like `break`. +pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'static, hir::Expr>; + +#[derive(Clone)] // (*) +enum Expressions<'gcx, 'exprs, E> + where E: 'exprs + AsCoercionSite, +{ + Dynamic(Vec<&'gcx hir::Expr>), + UpFront(&'exprs [E]), } // (*) this is clone because `FnCtxt` is clone, but it seems dubious -- nmatsakis -impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { +impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> + where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, +{ + /// The usual case; collect the set of expressions dynamically. + /// If the full set of coercion sites is known before hand, + /// consider `with_coercion_sites()` instead to avoid allocation. pub fn new(expected_ty: Ty<'tcx>) -> Self { + Self::make(expected_ty, Expressions::Dynamic(vec![])) + } + + /// As an optimization, you can create a `CoerceMany` with a + /// pre-existing slice of expressions. In this case, you are + /// expected to pass each element in the slice to `coerce(...)` in + /// order. This is used with arrays in particular to avoid + /// needlessly cloning the slice. + pub fn with_coercion_sites(expected_ty: Ty<'tcx>, + coercion_sites: &'exprs [E]) + -> Self { + Self::make(expected_ty, Expressions::UpFront(coercion_sites)) + } + + fn make(expected_ty: Ty<'tcx>, expressions: Expressions<'gcx, 'exprs, E>) -> Self { CoerceMany { expected_ty, final_ty: None, - expressions: vec![], + expressions, + pushed: 0, } } pub fn is_empty(&self) -> bool { - self.expressions.is_empty() + self.pushed == 0 } /// Return the "expected type" with which this coercion was @@ -997,16 +1032,25 @@ impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { // Handle the actual type unification etc. let result = if let Some(expression) = expression { - if self.expressions.is_empty() { + if self.pushed == 0 { // Special-case the first expression we are coercing. // To be honest, I'm not entirely sure why we do this. fcx.try_coerce(expression, expression_ty, self.expected_ty) } else { - fcx.try_find_coercion_lub(cause, - || self.expressions.iter().cloned(), - self.merged_ty(), - expression, - expression_ty) + match self.expressions { + Expressions::Dynamic(ref exprs) => + fcx.try_find_coercion_lub(cause, + exprs, + self.merged_ty(), + expression, + expression_ty), + Expressions::UpFront(ref coercion_sites) => + fcx.try_find_coercion_lub(cause, + &coercion_sites[0..self.pushed], + self.merged_ty(), + expression, + expression_ty), + } } } else { // this is a hack for cases where we default to `()` because @@ -1034,7 +1078,17 @@ impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { match result { Ok(v) => { self.final_ty = Some(v); - self.expressions.extend(expression); + if let Some(e) = expression { + match self.expressions { + Expressions::Dynamic(ref mut buffer) => buffer.push(e), + Expressions::UpFront(coercion_sites) => { + // if the user gave us an array to validate, check that we got + // the next expression in the list, as expected + assert_eq!(coercion_sites[self.pushed].as_coercion_site().id, e.id); + } + } + self.pushed += 1; + } } Err(err) => { let (expected, found) = if expression.is_none() { @@ -1076,8 +1130,46 @@ impl<'gcx, 'tcx> CoerceMany<'gcx, 'tcx> { } else { // If we only had inputs that were of type `!` (or no // inputs at all), then the final type is `!`. - assert!(self.expressions.is_empty()); + assert_eq!(self.pushed, 0); fcx.tcx.types.never } } } + +/// Something that can be converted into an expression to which we can +/// apply a coercion. +pub trait AsCoercionSite { + fn as_coercion_site(&self) -> &hir::Expr; +} + +impl AsCoercionSite for hir::Expr { + fn as_coercion_site(&self) -> &hir::Expr { + self + } +} + +impl AsCoercionSite for P { + fn as_coercion_site(&self) -> &hir::Expr { + self + } +} + +impl<'a, T> AsCoercionSite for &'a T + where T: AsCoercionSite +{ + fn as_coercion_site(&self) -> &hir::Expr { + (**self).as_coercion_site() + } +} + +impl AsCoercionSite for ! { + fn as_coercion_site(&self) -> &hir::Expr { + unreachable!() + } +} + +impl AsCoercionSite for hir::Arm { + fn as_coercion_site(&self) -> &hir::Expr { + &self.body + } +} diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e6e4b577bd50..73f6cd76290a 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { assert_eq!(n, pick.autoderefs); autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr)); + autoderef.finalize(LvaluePreference::NoPreference, &[self.self_expr]); let target = pick.unsize.unwrap_or(autoderefd_ty); let target = target.adjust_for_autoref(self.tcx, autoref); @@ -444,7 +444,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { "expr was deref-able {} times but now isn't?", autoderefs); }); - autoderef.finalize(PreferMutLvalue, Some(expr)); + autoderef.finalize(PreferMutLvalue, &[expr]); } } Some(_) | None => {} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 65e7e240cc36..4b7d9a0fd3aa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -77,7 +77,7 @@ type parameter). */ pub use self::Expectation::*; -use self::coercion::CoerceMany; +use self::coercion::{CoerceMany, DynamicCoerceMany}; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; @@ -420,7 +420,7 @@ pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { // this is `null` for loops where break with a value is illegal, // such as `while`, `for`, and `while let` - coerce: Option>, + coerce: Option>, } #[derive(Clone)] @@ -450,7 +450,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_coercion: Option>>, + ret_coercion: Option>>, ps: RefCell, @@ -2245,12 +2245,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, base_expr, adj_ty, autoderefs, false, lvalue_pref, idx_ty) { - autoderef.finalize(lvalue_pref, Some(base_expr)); + autoderef.finalize(lvalue_pref, &[base_expr]); return Some(final_mt); } if let ty::TyArray(element_ty, _) = adj_ty.sty { - autoderef.finalize(lvalue_pref, Some(base_expr)); + autoderef.finalize(lvalue_pref, &[base_expr]); let adjusted_ty = self.tcx.mk_slice(element_ty); return self.try_index_step( MethodCall::expr(expr.id), expr, base_expr, @@ -2861,7 +2861,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // (`only_has_type`); otherwise, we just go with a // fresh type variable. let coerce_to_ty = expected.only_has_type_or_fresh_var(self, sp); - let mut coerce = CoerceMany::new(coerce_to_ty); + let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); coerce.coerce(self, &if_cause, then_expr, then_ty); @@ -2908,7 +2908,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); if self.tcx.vis_is_accessible_from(field.vis, self.body_id) { - autoderef.finalize(lvalue_pref, Some(base)); + autoderef.finalize(lvalue_pref, &[base]); self.write_autoderef_adjustment(base.id, autoderefs, base_t); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -3032,7 +3032,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, Some(base)); + autoderef.finalize(lvalue_pref, &[base]); self.write_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } @@ -3768,7 +3768,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let element_ty = if !args.is_empty() { let coerce_to = uty.unwrap_or_else( || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); - let mut coerce = CoerceMany::new(coerce_to); + let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index df1c94dc19b5..0bde9fefeba0 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -79,6 +79,7 @@ This API is completely unstable and subject to change. #![feature(conservative_impl_trait)] #![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(loop_break_value)] +#![feature(never_type)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] From f83706454fd00c2a3b7873b50223b68ca2cbd0d0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 11:48:44 -0400 Subject: [PATCH 170/905] coercion now depends on whether the expression diverges Before I was checking this in `demand_coerce` but that's not really the right place. The right place is to move that into the coercion routine itself. --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/cast.rs | 10 ++++-- src/librustc_typeck/check/coercion.rs | 46 ++++++++++++++++++++------- src/librustc_typeck/check/demand.rs | 16 +--------- src/librustc_typeck/check/mod.rs | 18 +++++++---- 5 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5ca8f2c01c58..e83b786b9a83 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -504,7 +504,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arm_span: arm.body.span, source: match_src }); - coercion.coerce(self, &cause, &arm.body, arm_ty); + coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get()); } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 441d427fe499..ea0aad007dd7 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::FnCtxt; +use super::{Diverges, FnCtxt}; use lint; use hir::def_id::DefId; @@ -376,7 +376,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (None, Some(t_cast)) => { if let ty::TyFnDef(.., f) = self.expr_ty.sty { // Attempt a coercion to a fn pointer type. - let res = fcx.try_coerce(self.expr, self.expr_ty, fcx.tcx.mk_fn_ptr(f)); + let res = fcx.try_coerce(self.expr, + self.expr_ty, + Diverges::Maybe, // TODO + fcx.tcx.mk_fn_ptr(f)); if !res.is_ok() { return Err(CastError::NonScalar); } @@ -542,7 +545,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { - fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok() + // TODO + fcx.try_coerce(self.expr, self.expr_ty, Diverges::Maybe, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index eba58df781f1..a737b82700e3 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,7 +60,7 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use check::FnCtxt; +use check::{Diverges, FnCtxt}; use rustc::hir; use rustc::hir::def_id::DefId; @@ -156,7 +156,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }) } - fn coerce(&self, exprs: &[E], a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> + fn coerce(&self, + exprs: &[E], + a: Ty<'tcx>, + b: Ty<'tcx>) + -> CoerceResult<'tcx> where E: AsCoercionSite { let a = self.shallow_resolve(a); @@ -689,11 +693,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn try_coerce(&self, expr: &hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, target: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); + // Special-ish case: we can coerce any type `T` into the `!` + // type, but only if the source expression diverges. + if target.is_never() && expr_diverges.always() { + debug!("permit coercion to `!` because expr diverges"); + return Ok(target); + } + let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { @@ -721,15 +733,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { exprs: &[E], prev_ty: Ty<'tcx>, new: &hir::Expr, - new_ty: Ty<'tcx>) + new_ty: Ty<'tcx>, + new_diverges: Diverges) -> RelateResult<'tcx, Ty<'tcx>> where E: AsCoercionSite { - let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); let new_ty = self.resolve_type_vars_with_obligations(new_ty); debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + // Special-ish case: we can coerce any type `T` into the `!` + // type, but only if the source expression diverges. + if prev_ty.is_never() && new_diverges.always() { + debug!("permit coercion to `!` because expr diverges"); + return Ok(prev_ty); + } + let trace = TypeTrace::types(cause, true, prev_ty, new_ty); // Special-case that coercion alone cannot handle: @@ -982,9 +1001,10 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> fcx: &FnCtxt<'a, 'gcx, 'tcx>, cause: &ObligationCause<'tcx>, expression: &'gcx hir::Expr, - expression_ty: Ty<'tcx>) + expression_ty: Ty<'tcx>, + expression_diverges: Diverges) { - self.coerce_inner(fcx, cause, Some(expression), expression_ty) + self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges) } /// Indicates that one of the inputs is a "forced unit". This @@ -1002,7 +1022,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> self.coerce_inner(fcx, cause, None, - fcx.tcx.mk_nil()) + fcx.tcx.mk_nil(), + Diverges::Maybe) } /// The inner coercion "engine". If `expression` is `None`, this @@ -1012,7 +1033,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> fcx: &FnCtxt<'a, 'gcx, 'tcx>, cause: &ObligationCause<'tcx>, expression: Option<&'gcx hir::Expr>, - mut expression_ty: Ty<'tcx>) + mut expression_ty: Ty<'tcx>, + expression_diverges: Diverges) { // Incorporate whatever type inference information we have // until now; in principle we might also want to process @@ -1035,7 +1057,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> if self.pushed == 0 { // Special-case the first expression we are coercing. // To be honest, I'm not entirely sure why we do this. - fcx.try_coerce(expression, expression_ty, self.expected_ty) + fcx.try_coerce(expression, expression_ty, expression_diverges, self.expected_ty) } else { match self.expressions { Expressions::Dynamic(ref exprs) => @@ -1043,13 +1065,15 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> exprs, self.merged_ty(), expression, - expression_ty), + expression_ty, + expression_diverges), Expressions::UpFront(ref coercion_sites) => fcx.try_find_coercion_lub(cause, &coercion_sites[0..self.pushed], self.merged_ty(), expression, - expression_ty), + expression_ty, + expression_diverges), } } } else { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 25d689b3c2c4..e922c7447ff8 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -77,21 +77,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); - // If we are "assigning" to a `!` location, then we can permit - // any type to be assigned there, so long as we are in - // dead-code. This applies to e.g. `fn foo() -> ! { return; 22 - // }` but also `fn foo() { let x: ! = { return; 22 }; }`. - // - // You might imagine that we could just *always* bail if we - // are in dead-code, but we don't want to do that, because - // that leaves a lot of type variables unconstrained. See - // e.g. #39808 and #39984. - let in_dead_code = self.diverges.get().always(); - if expected.is_never() && in_dead_code { - return; - } - - if let Err(e) = self.try_coerce(expr, checked_ty, expected) { + if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let mode = probe::Mode::MethodCall; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4b7d9a0fd3aa..539f16ec6709 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -366,7 +366,7 @@ impl UnsafetyState { /// as diverging), with some manual adjustments for control-flow /// primitives (approximating a CFG). #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -enum Diverges { +pub enum Diverges { /// Potentially unknown, some cases converge, /// others require a CFG to determine them. Maybe, @@ -2833,7 +2833,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .coerce(self, &self.misc(return_expr.span), return_expr, - return_expr_ty); + return_expr_ty, + self.diverges.get()); } @@ -2864,13 +2865,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); - coerce.coerce(self, &if_cause, then_expr, then_ty); + coerce.coerce(self, &if_cause, then_expr, then_ty, then_diverges); if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); - coerce.coerce(self, &if_cause, else_expr, else_ty); + coerce.coerce(self, &if_cause, else_expr, else_ty, else_diverges); // We won't diverge unless both branches do (or the condition does). self.diverges.set(cond_diverges | then_diverges & else_diverges); @@ -3553,7 +3554,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprBreak(destination, ref expr_opt) => { if let Some(target_id) = destination.target_id.opt_id() { - let (e_ty, cause); + let (e_ty, e_diverges, cause); if let Some(ref e) = *expr_opt { // If this is a break with a value, we need to type-check // the expression. Get an expected type from the loop context. @@ -3572,11 +3573,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); + e_diverges = self.diverges.get(); cause = self.misc(e.span); } else { // Otherwise, this is a break *without* a value. That's // always legal, and is equivalent to `break ()`. e_ty = tcx.mk_nil(); + e_diverges = Diverges::Maybe; cause = self.misc(expr.span); } @@ -3587,7 +3590,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ctxt = enclosing_breakables.find_breakable(target_id); if let Some(ref mut coerce) = ctxt.coerce { if let Some(ref e) = *expr_opt { - coerce.coerce(self, &cause, e, e_ty); + coerce.coerce(self, &cause, e, e_ty, e_diverges); } else { assert!(e_ty.is_nil()); coerce.coerce_forced_unit(self, &cause); @@ -3769,10 +3772,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce_to = uty.unwrap_or_else( || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); + assert_eq!(self.diverges.get(), Diverges::Maybe); for e in args { let e_ty = self.check_expr_with_hint(e, coerce_to); let cause = self.misc(e.span); - coerce.coerce(self, &cause, e, e_ty); + coerce.coerce(self, &cause, e, e_ty, self.diverges.get()); } coerce.complete(self) } else { From d448329849bb2cef355cabfdc6cb4d8b5b76b80e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 11:50:36 -0400 Subject: [PATCH 171/905] fix handling of blocks with `CoerceMany` --- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/mod.rs | 141 ++++++++++---------------- 2 files changed, 53 insertions(+), 90 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a737b82700e3..8a9db674c6eb 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -926,7 +926,7 @@ pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> /// The type of a `CoerceMany` that is storing up the expressions into /// a buffer. We use this in `check/mod.rs` for things like `break`. -pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'static, hir::Expr>; +pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'gcx, P>; #[derive(Clone)] // (*) enum Expressions<'gcx, 'exprs, E> diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 539f16ec6709..413d09117af0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -86,6 +86,7 @@ use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_back::slice::ref_slice; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace}; use rustc::infer::type_variable::{self, TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; @@ -4108,102 +4109,64 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - let mut ty = if blk.targeted_by_break { - let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(blk.span)); - let coerce_to = expected.only_has_type(self).unwrap_or(unified); - let ctxt = BreakableCtxt { - unified: unified, - coerce_to: coerce_to, - break_exprs: vec![], - may_break: false, - }; - - let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(blk.id, ctxt, || { - for s in &blk.stmts { - self.check_stmt(s); - } - let coerce_to = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - enclosing_breakables.find_breakable(blk.id).coerce_to - }; - let e_ty; - let cause; - match blk.expr { - Some(ref e) => { - e_ty = self.check_expr_with_hint(e, coerce_to); - cause = self.misc(e.span); - }, - None => { - e_ty = if self.diverges.get().always() { - self.tcx.types.never - } else { - self.tcx.mk_nil() - }; - cause = self.misc(blk.span); - } - }; - - (e_ty, cause) - }); - - if let ExpectHasType(ety) = expected { - if let Some(ref e) = blk.expr { - let result = if !ctxt.may_break { - self.try_coerce(e, e_ty, ctxt.coerce_to) - } else { - self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(), - ctxt.unified, e, e_ty) - }; - match result { - Ok(ty) => ctxt.unified = ty, - Err(err) => - self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(), - } - } else if self.diverges.get().always() { - // No tail expression and the body diverges; ignore - // the expected type, and keep `!` as the type of the - // block. - } else { - self.check_block_no_expr(blk, self.tcx.mk_nil(), e_ty); - }; - - ctxt.unified + // In some cases, blocks have just one exit, but other blocks + // can be targeted by multiple breaks. This cannot happen in + // normal Rust syntax today, but it can happen when we desugar + // a `do catch { ... }` expression. + // + // Example 1: + // + // 'a: { if true { break 'a Err(()); } Ok(()) } + // + // Here we would wind up with two coercions, one from + // `Err(())` and the other from the tail expression + // `Ok(())`. If the tail expression is omitted, that's a + // "forced unit" -- unless the block diverges, in which + // case we can ignore the tail expression (e.g., `'a: { + // break 'a 22; }` would not force the type of the block + // to be `()`). + let tail_expr = blk.expr.as_ref(); + let coerce_to_ty = expected.coercion_target_type(self, blk.span); + let coerce = if blk.targeted_by_break { + CoerceMany::new(coerce_to_ty) } else { + let tail_expr: &[P] = match tail_expr { + Some(e) => ref_slice(e), + None => &[], + }; + CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) + }; + + let ctxt = BreakableCtxt { + coerce: Some(coerce), + may_break: false, + }; + + let (ctxt, ()) = self.with_breakable_ctxt(blk.id, ctxt, || { for s in &blk.stmts { self.check_stmt(s); } - let mut ty = match blk.expr { - Some(ref e) => self.check_expr_with_expectation(e, expected), - None => if self.diverges.get().always() { - self.tcx.types.never - } else { - self.tcx.mk_nil() - }, - }; + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); - if let ExpectHasType(ety) = expected { - if let Some(ref e) = blk.expr { - // Coerce the tail expression to the right type. - self.demand_coerce(e, ty, ety); - - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; - } else if self.diverges.get().always() { - // No tail expression and the body diverges; ignore - // the expected type, and keep `!` as the type of the - // block. - } else { - self.check_block_no_expr(blk, ty, ety); - - // We already applied the type (and potentially errored), - // use the expected type to avoid further errors out. - ty = ety; - } + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let mut ctxt = enclosing_breakables.find_breakable(blk.id); + let mut coerce = ctxt.coerce.as_mut().unwrap(); + if let Some(tail_expr_ty) = tail_expr_ty { + let tail_expr = tail_expr.unwrap(); + coerce.coerce(self, + &self.misc(tail_expr.span), + tail_expr, + tail_expr_ty, + self.diverges.get()); // TODO + } else if !self.diverges.get().always() { + coerce.coerce_forced_unit(self, &self.misc(blk.span)); } - ty - }; + }); + + let mut ty = ctxt.coerce.unwrap().complete(self); if self.has_errors.get() || ty.references_error() { ty = self.tcx.types.err From 127a7d643d70dea605ca479c12a32f450d985b09 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 11:51:02 -0400 Subject: [PATCH 172/905] rename `only_has_type_or_fresh_var` to `coercion_target_type` --- src/librustc_typeck/check/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 413d09117af0..0a2cb94c591d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -314,7 +314,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { /// Like `only_has_type`, but instead of returning `None` if no /// hard constraint exists, creates a fresh type variable. - fn only_has_type_or_fresh_var(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { + fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { self.only_has_type(fcx) .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span))) } @@ -2862,7 +2862,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `expected` if it represents a *hard* constraint // (`only_has_type`); otherwise, we just go with a // fresh type variable. - let coerce_to_ty = expected.only_has_type_or_fresh_var(self, sp); + let coerce_to_ty = expected.coercion_target_type(self, sp); let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty); let if_cause = self.cause(sp, ObligationCauseCode::IfExpression); @@ -3683,7 +3683,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let coerce = match source { // you can only use break with a value from a normal `loop { }` hir::LoopSource::Loop => { - let coerce_to = expected.only_has_type_or_fresh_var(self, body.span); + let coerce_to = expected.coercion_target_type(self, body.span); Some(CoerceMany::new(coerce_to)) } From d08a6da1f05dc6f8de4201efe949f1c26704ced0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 21 Mar 2017 21:21:24 -0400 Subject: [PATCH 173/905] remove `Clone` from `FnCtxt` --- src/librustc_typeck/check/coercion.rs | 4 ---- src/librustc_typeck/check/mod.rs | 3 --- 2 files changed, 7 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8a9db674c6eb..37d442f1d059 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -914,7 +914,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// } /// let final_ty = coerce.complete(fcx); /// ``` -#[derive(Clone)] // (*) pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, { @@ -928,7 +927,6 @@ pub struct CoerceMany<'gcx, 'tcx, 'exprs, E> /// a buffer. We use this in `check/mod.rs` for things like `break`. pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'gcx, P>; -#[derive(Clone)] // (*) enum Expressions<'gcx, 'exprs, E> where E: 'exprs + AsCoercionSite, { @@ -936,8 +934,6 @@ enum Expressions<'gcx, 'exprs, E> UpFront(&'exprs [E]), } -// (*) this is clone because `FnCtxt` is clone, but it seems dubious -- nmatsakis - impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> where 'gcx: 'tcx, E: 'exprs + AsCoercionSite, { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0a2cb94c591d..9eaa8404bded 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -415,7 +415,6 @@ impl Diverges { } } -#[derive(Clone)] pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { may_break: bool, @@ -424,7 +423,6 @@ pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { coerce: Option>, } -#[derive(Clone)] pub struct EnclosingBreakables<'gcx: 'tcx, 'tcx> { stack: Vec>, by_id: NodeMap, @@ -439,7 +437,6 @@ impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { } } -#[derive(Clone)] pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ast_ty_to_ty_cache: RefCell>>, From 8c6156e1d1f7e46c59fd21c878dccbc4526d7e0c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 22 Mar 2017 21:07:02 -0400 Subject: [PATCH 174/905] have coercion supply back the target type The `try_coerce` method coerces from a source to a target type, possibly inserting adjustments. It should guarantee that the post-adjustment type is a subtype of the target type (or else that some side-constraint has been registered which will lead to an error). However, it used to return the (possibly adjusted) source as the type of the expression rather than the target. This led to less good downstream errors. To work around this, the code around blocks -- and particular tail expressions in blocks -- had some special case manipulation. However, since that code is now using the more general `CoerceMany` construct (to account for breaks), it can no longer take advantage of that. This lead to some regressions in compile-fail tests were errors were reported at "less good" locations than before. This change modifies coercions to return the target type when successful rather the source type. This extends the behavior from blocks to all coercions. Typically this has limited effect but on a few tests yielded better errors results (and avoided regressions, of course). This change also restores the hint about removing semicolons which went missing (by giving 'force-unit' coercions a chance to add notes etc). --- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 40 +++++--- src/librustc_typeck/check/mod.rs | 99 +++++++++++-------- src/test/compile-fail/issue-15965.rs | 2 +- src/test/compile-fail/issue-2149.rs | 2 +- ...region-invariant-static-error-reporting.rs | 3 - src/test/compile-fail/regions-bounds.rs | 4 +- 7 files changed, 91 insertions(+), 61 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e83b786b9a83..4a0446424444 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -498,7 +498,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if is_if_let_fallback { let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); assert!(arm_ty.is_nil()); - coercion.coerce_forced_unit(self, &cause); + coercion.coerce_forced_unit(self, &cause, &mut |_| ()); } else { let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { arm_span: arm.body.span, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 37d442f1d059..a5acd0c7e530 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -74,6 +74,7 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; +use errors::DiagnosticBuilder; use syntax::abi; use syntax::feature_gate; use syntax::ptr::P; @@ -718,7 +719,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.write_adjustment(expr.id, adjustment); } - Ok(adjustment.target) + + // We should now have added sufficient adjustments etc to + // ensure that the type of expression, post-adjustment, is + // a subtype of target. + Ok(target) }) } @@ -1000,7 +1005,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> expression_ty: Ty<'tcx>, expression_diverges: Diverges) { - self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges) + self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges, None) } /// Indicates that one of the inputs is a "forced unit". This @@ -1011,15 +1016,21 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> /// purposes. Note that these tend to correspond to cases where /// the `()` expression is implicit in the source, and hence we do /// not take an expression argument. + /// + /// The `augment_error` gives you a chance to extend the error + /// message, in case any results (e.g., we use this to suggest + /// removing a `;`). pub fn coerce_forced_unit<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, - cause: &ObligationCause<'tcx>) + cause: &ObligationCause<'tcx>, + augment_error: &mut FnMut(&mut DiagnosticBuilder)) { self.coerce_inner(fcx, cause, None, fcx.tcx.mk_nil(), - Diverges::Maybe) + Diverges::Maybe, + Some(augment_error)) } /// The inner coercion "engine". If `expression` is `None`, this @@ -1030,7 +1041,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> cause: &ObligationCause<'tcx>, expression: Option<&'gcx hir::Expr>, mut expression_ty: Ty<'tcx>, - expression_diverges: Diverges) + expression_diverges: Diverges, + augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>) { // Incorporate whatever type inference information we have // until now; in principle we might also want to process @@ -1126,19 +1138,25 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> (self.final_ty.unwrap_or(self.expected_ty), expression_ty) }; + let mut db; match cause.code { ObligationCauseCode::ReturnNoExpression => { - struct_span_err!(fcx.tcx.sess, cause.span, E0069, - "`return;` in a function whose return type is not `()`") - .span_label(cause.span, &format!("return type is not ()")) - .emit(); + db = struct_span_err!( + fcx.tcx.sess, cause.span, E0069, + "`return;` in a function whose return type is not `()`"); + db.span_label(cause.span, &format!("return type is not ()")); } _ => { - fcx.report_mismatched_types(cause, expected, found, err) - .emit(); + db = fcx.report_mismatched_types(cause, expected, found, err); } } + if let Some(mut augment_error) = augment_error { + augment_error(&mut db); + } + + db.emit(); + self.final_ty = Some(fcx.tcx.types.err); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9eaa8404bded..29b83523aed6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,7 +87,7 @@ use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; -use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace}; +use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{self, TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; @@ -99,6 +99,7 @@ use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; +use errors::DiagnosticBuilder; use require_c_abi_if_variadic; use session::{Session, CompileResult}; use TypeAndSubsts; @@ -2875,7 +2876,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(cond_diverges | then_diverges & else_diverges); } else { let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); - coerce.coerce_forced_unit(self, &else_cause); + coerce.coerce_forced_unit(self, &else_cause, &mut |_| ()); // If the condition is false we can't diverge. self.diverges.set(cond_diverges); @@ -3591,7 +3592,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { coerce.coerce(self, &cause, e, e_ty, e_diverges); } else { assert!(e_ty.is_nil()); - coerce.coerce_forced_unit(self, &cause); + coerce.coerce_forced_unit(self, &cause, &mut |_| ()); } } else { // If `ctxt.coerce` is `None`, we can just ignore @@ -3626,7 +3627,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - coercion.coerce_forced_unit(self, &cause); + coercion.coerce_forced_unit(self, &cause, &mut |_| ()); } tcx.types.never } @@ -4158,8 +4159,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tail_expr, tail_expr_ty, self.diverges.get()); // TODO - } else if !self.diverges.get().always() { - coerce.coerce_forced_unit(self, &self.misc(blk.span)); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + if !self.diverges.get().always() { + coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| { + if let Some(expected_ty) = expected.only_has_type(self) { + self.consider_hint_about_removing_semicolon(blk, + expected_ty, + err); + } + }); + } } }); @@ -4175,43 +4191,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } - pub fn check_block_no_expr(&self, blk: &'gcx hir::Block, ty: Ty<'tcx>, ety: Ty<'tcx>) { - // We're not diverging and there's an expected type, which, - // in case it's not `()`, could result in an error higher-up. - // We have a chance to error here early and be more helpful. - let cause = self.misc(blk.span); - let trace = TypeTrace::types(&cause, false, ty, ety); - match self.sub_types(false, &cause, ty, ety) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }, - Err(err) => { - let mut err = self.report_and_explain_type_error(trace, &err); - - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let mut extra_semi = None; - if let Some(stmt) = blk.stmts.last() { - if let hir::StmtSemi(ref e, _) = stmt.node { - if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { - extra_semi = Some(stmt); - } - } - } - if let Some(last_stmt) = extra_semi { - let original_span = original_sp(last_stmt.span, blk.span); - let span_semi = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - ctxt: original_span.ctxt, - }; - err.span_help(span_semi, "consider removing this semicolon:"); - } - - err.emit(); - } + /// A common error is to add an extra semicolon: + /// + /// ``` + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + fn consider_hint_about_removing_semicolon(&self, + blk: &'gcx hir::Block, + expected_ty: Ty<'tcx>, + err: &mut DiagnosticBuilder) { + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let last_stmt = match blk.stmts.last() { + Some(s) => s, + None => return, + }; + let last_expr = match last_stmt.node { + hir::StmtSemi(ref e, _) => e, + _ => return, + }; + let last_expr_ty = self.expr_ty(last_expr); + if self.can_sub_types(last_expr_ty, expected_ty).is_err() { + return; } + let original_span = original_sp(last_stmt.span, blk.span); + let span_semi = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + ctxt: original_span.ctxt, + }; + err.span_help(span_semi, "consider removing this semicolon:"); } // Instantiates the given path, which must refer to an item with the given diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index d5d597c190ea..08b896f387bb 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,7 +11,7 @@ fn main() { return { return () } -//~^ ERROR expected function, found `!` +//~^ ERROR the type of this value must be known in this context () ; } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 9143a226a248..256c5d8e6f72 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -21,5 +21,5 @@ impl vec_monad for Vec { } fn main() { ["hi"].bind(|x| [x] ); - //~^ ERROR no method named `bind` found for type `[&'static str; 1]` in the current scope + //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope } diff --git a/src/test/compile-fail/region-invariant-static-error-reporting.rs b/src/test/compile-fail/region-invariant-static-error-reporting.rs index ac0167e08bdd..d25674a74b1d 100644 --- a/src/test/compile-fail/region-invariant-static-error-reporting.rs +++ b/src/test/compile-fail/region-invariant-static-error-reporting.rs @@ -13,9 +13,6 @@ // over time, but this test used to exhibit some pretty bogus messages // that were not remotely helpful. -// error-pattern:cannot infer -// error-pattern:cannot outlive the lifetime 'a -// error-pattern:must be valid for the static lifetime // error-pattern:cannot infer // error-pattern:cannot outlive the lifetime 'a // error-pattern:must be valid for the static lifetime diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 810a8671c536..5ce80be98d97 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -16,11 +16,11 @@ struct an_enum<'a>(&'a isize); struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { - return e; //~^ ERROR mismatched types + return e; //~ ERROR mismatched types } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { - return e; //~^ ERROR mismatched types + return e; //~ ERROR mismatched types } fn main() { } From 7eeddb409364fdeecbec8611f08a6ccea134971f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:21:50 -0400 Subject: [PATCH 175/905] add test illustrating current "coerce to `!`" behavior --- src/test/compile-fail/coerce-to-bang.rs | 90 +++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/test/compile-fail/coerce-to-bang.rs diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs new file mode 100644 index 000000000000..870665bb49ee --- /dev/null +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -0,0 +1,90 @@ +// 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. + +#![feature(never_type)] + +fn foo(x: usize, y: !, z: usize) { } + +fn call_foo_a() { + // FIXME(#40800) -- accepted beacuse divergence happens **before** + // the coercion to `!`, but within same expression. Not clear that + // these are the rules we want. + foo(return, 22, 44); +} + +fn call_foo_b() { + // Divergence happens in the argument itself, definitely ok. + foo(22, return, 44); +} + +fn call_foo_c() { + // This test fails because the divergence happens **after** the + // coercion to `!`: + foo(22, 44, return); //~ ERROR mismatched types +} + +fn call_foo_d() { + // This test passes because `a` has type `!`: + let a: ! = return; + let b = 22; + let c = 44; + foo(a, b, c); // ... and hence a reference to `a` is expected to diverge. +} + +fn call_foo_e() { + // This test probably could pass but we don't *know* that `a` + // has type `!` so we don't let it work. + let a = return; + let b = 22; + let c = 44; + foo(a, b, c); //~ ERROR mismatched types +} + +fn call_foo_f() { + // This fn fails because `a` has type `usize`, and hence a + // reference to is it **not** considered to diverge. + let a: usize = return; + let b = 22; + let c = 44; + foo(a, b, c); //~ ERROR mismatched types +} + +fn array_a() { + // Accepted: return is coerced to `!` just fine, and then `22` can be + // because we already diverged. + let x: [!; 2] = [return, 22]; +} + +fn array_b() { + // Error: divergence has not yet occurred. + let x: [!; 2] = [22, return]; //~ ERROR mismatched types +} + +fn tuple_a() { + // No divergence at all. + let x: (usize, !, usize) = (22, 44, 66); //~ ERROR mismatched types +} + +fn tuple_b() { + // Divergence happens before coercion: OK + let x: (usize, !, usize) = (return, 44, 66); +} + +fn tuple_c() { + // Divergence happens before coercion: OK + let x: (usize, !, usize) = (22, return, 66); +} + +fn tuple_d() { + // Error: divergence happens too late + let x: (usize, !, usize) = (22, 44, return); //~ ERROR mismatched types +} + +fn main() { } From 8450add8bede7bc5119457e37bbbcc95a5e8b121 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:35:49 -0400 Subject: [PATCH 176/905] fix `X as !` behavior --- src/librustc_typeck/check/cast.rs | 8 ++++--- src/librustc_typeck/check/mod.rs | 5 +++-- src/test/compile-fail/coerce-to-bang-cast.rs | 23 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/coerce-to-bang-cast.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index ea0aad007dd7..32b363ed755f 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -56,6 +56,7 @@ use util::common::ErrorReported; pub struct CastCheck<'tcx> { expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -115,6 +116,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, + expr_diverges: Diverges, cast_ty: Ty<'tcx>, cast_span: Span, span: Span) @@ -122,6 +124,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let check = CastCheck { expr: expr, expr_ty: expr_ty, + expr_diverges: expr_diverges, cast_ty: cast_ty, cast_span: cast_span, span: span, @@ -378,7 +381,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // Attempt a coercion to a fn pointer type. let res = fcx.try_coerce(self.expr, self.expr_ty, - Diverges::Maybe, // TODO + self.expr_diverges, fcx.tcx.mk_fn_ptr(f)); if !res.is_ok() { return Err(CastError::NonScalar); @@ -545,8 +548,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { - // TODO - fcx.try_coerce(self.expr, self.expr_ty, Diverges::Maybe, self.cast_ty).is_ok() + fcx.try_coerce(self.expr, self.expr_ty, self.expr_diverges, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 29b83523aed6..da15c8f766e3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3736,6 +3736,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let t_cast = self.resolve_type_vars_if_possible(&t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); let t_cast = self.resolve_type_vars_if_possible(&t_cast); + let diverges = self.diverges.get(); // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { @@ -3743,7 +3744,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + match cast::CastCheck::new(self, e, t_expr, diverges, t_cast, t.span, expr.span) { Ok(cast_check) => { deferred_cast_checks.push(cast_check); t_cast @@ -4158,7 +4159,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self.misc(tail_expr.span), tail_expr, tail_expr_ty, - self.diverges.get()); // TODO + self.diverges.get()); } else { // Subtle: if there is no explicit tail expression, // that is typically equivalent to a tail expression diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs new file mode 100644 index 000000000000..57d2192e6356 --- /dev/null +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -0,0 +1,23 @@ +// 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. + +#![feature(never_type)] + +fn foo(x: usize, y: !, z: usize) { } + +fn cast_a() { + let y = {return; 22} as !; +} + +fn cast_b() { + let y = 22 as !; //~ ERROR non-scalar cast +} + +fn main() { } From 1b5768df4e70e4a05e15271ee58c32cb00d7fefd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 13:36:01 -0400 Subject: [PATCH 177/905] document `diverges` more correctly --- src/librustc_typeck/check/mod.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index da15c8f766e3..aaa3cf0f29e7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -454,11 +454,19 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ps: RefCell, /// Whether the last checked node generates a divergence (e.g., - /// `return` will set this to Always). In general, this is - /// typically set to *Maybe* on the way **down** the tree, and - /// then values are propagated **up** the tree. In a block, we - /// combine the results from statements and propagate the - /// end-result up. + /// `return` will set this to Always). In general, when entering + /// an expression or other node in the tree, the initial value + /// indicates whether prior parts of the containing expression may + /// have diverged. It is then typically set to `Maybe` (and the + /// old value remembered) for processing the subparts of the + /// current expression. As each subpart is processed, they may set + /// the flag to `Always` etc. Finally, at the end, we take the + /// result and "union" it with the original value, so that when we + /// return the flag indicates if any subpart of the the parent + /// expression (up to and including this part) has diverged. So, + /// if you read it after evaluating a subexpression `X`, the value + /// you get indicates whether any subexpression that was + /// evaluating up to and including `X` diverged. /// /// We use this flag for two purposes: /// From e97fc5247a1d3e3e223febbbcda15e3439b61c30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 24 Mar 2017 18:47:58 -0400 Subject: [PATCH 178/905] kill the graphviz-flowgraph tests They are so annoying to update, and haven't caught any bugs afaik. --- src/test/run-make/graphviz-flowgraph/Makefile | 38 ----- .../graphviz-flowgraph/f00.dot-expected.dot | 9 - src/test/run-make/graphviz-flowgraph/f00.rs | 13 -- .../graphviz-flowgraph/f01.dot-expected.dot | 13 -- src/test/run-make/graphviz-flowgraph/f01.rs | 13 -- .../graphviz-flowgraph/f02.dot-expected.dot | 13 -- src/test/run-make/graphviz-flowgraph/f02.rs | 13 -- .../graphviz-flowgraph/f03.dot-expected.dot | 17 -- src/test/run-make/graphviz-flowgraph/f03.rs | 13 -- .../graphviz-flowgraph/f04.dot-expected.dot | 15 -- src/test/run-make/graphviz-flowgraph/f04.rs | 13 -- .../graphviz-flowgraph/f05.dot-expected.dot | 23 --- src/test/run-make/graphviz-flowgraph/f05.rs | 13 -- .../graphviz-flowgraph/f06.dot-expected.dot | 19 --- src/test/run-make/graphviz-flowgraph/f06.rs | 14 -- .../graphviz-flowgraph/f07.dot-expected.dot | 39 ----- src/test/run-make/graphviz-flowgraph/f07.rs | 17 -- .../graphviz-flowgraph/f08.dot-expected.dot | 38 ----- src/test/run-make/graphviz-flowgraph/f08.rs | 16 -- .../graphviz-flowgraph/f09.dot-expected.dot | 54 ------ src/test/run-make/graphviz-flowgraph/f09.rs | 18 -- .../graphviz-flowgraph/f10.dot-expected.dot | 36 ---- src/test/run-make/graphviz-flowgraph/f10.rs | 16 -- .../graphviz-flowgraph/f11.dot-expected.dot | 35 ---- src/test/run-make/graphviz-flowgraph/f11.rs | 18 -- .../graphviz-flowgraph/f12.dot-expected.dot | 50 ------ src/test/run-make/graphviz-flowgraph/f12.rs | 18 -- .../graphviz-flowgraph/f13.dot-expected.dot | 54 ------ src/test/run-make/graphviz-flowgraph/f13.rs | 18 -- .../graphviz-flowgraph/f14.dot-expected.dot | 36 ---- src/test/run-make/graphviz-flowgraph/f14.rs | 18 -- .../graphviz-flowgraph/f15.dot-expected.dot | 105 ------------ src/test/run-make/graphviz-flowgraph/f15.rs | 30 ---- .../graphviz-flowgraph/f16.dot-expected.dot | 111 ------------ src/test/run-make/graphviz-flowgraph/f16.rs | 31 ---- .../graphviz-flowgraph/f17.dot-expected.dot | 21 --- src/test/run-make/graphviz-flowgraph/f17.rs | 13 -- .../graphviz-flowgraph/f18.dot-expected.dot | 23 --- src/test/run-make/graphviz-flowgraph/f18.rs | 14 -- .../graphviz-flowgraph/f19.dot-expected.dot | 29 ---- src/test/run-make/graphviz-flowgraph/f19.rs | 16 -- .../graphviz-flowgraph/f20.dot-expected.dot | 29 ---- src/test/run-make/graphviz-flowgraph/f20.rs | 14 -- .../graphviz-flowgraph/f21.dot-expected.dot | 101 ----------- src/test/run-make/graphviz-flowgraph/f21.rs | 30 ---- .../graphviz-flowgraph/f22.dot-expected.dot | 107 ------------ src/test/run-make/graphviz-flowgraph/f22.rs | 31 ---- .../graphviz-flowgraph/f23.dot-expected.dot | 113 ------------ src/test/run-make/graphviz-flowgraph/f23.rs | 31 ---- .../graphviz-flowgraph/f24.dot-expected.dot | 161 ------------------ src/test/run-make/graphviz-flowgraph/f24.rs | 36 ---- .../graphviz-flowgraph/f25.dot-expected.dot | 161 ------------------ src/test/run-make/graphviz-flowgraph/f25.rs | 36 ---- 53 files changed, 1963 deletions(-) delete mode 100644 src/test/run-make/graphviz-flowgraph/Makefile delete mode 100644 src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f00.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f01.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f02.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f03.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f07.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f08.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f09.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f10.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f12.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f23.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.rs diff --git a/src/test/run-make/graphviz-flowgraph/Makefile b/src/test/run-make/graphviz-flowgraph/Makefile deleted file mode 100644 index 5740a36359c9..000000000000 --- a/src/test/run-make/graphviz-flowgraph/Makefile +++ /dev/null @@ -1,38 +0,0 @@ --include ../tools.mk - -FILES=f00.rs f01.rs f02.rs f03.rs f04.rs f05.rs f06.rs f07.rs \ - f08.rs f09.rs f10.rs f11.rs f12.rs f13.rs f14.rs f15.rs \ - f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs f23.rs \ - f24.rs f25.rs - - -# all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES)) -all: $(patsubst %.rs,$(TMPDIR)/%.check,$(FILES)) - - -RUSTC_LIB=$(RUSTC) --crate-type=lib - -define FIND_LAST_BLOCK -LASTBLOCKNUM_$(1) := $(shell $(RUSTC_LIB) -Z unstable-options --pretty=expanded,identified $(1) \ - | grep block - | tail -1 - | sed -e 's@.*/\* block \([0-9]*\) \*/.*@\1@') -endef - -ifeq ($(findstring rustc,$(RUSTC)),) -$(error Must set RUSTC) -endif - -$(TMPDIR)/%.pp: %.rs - $(RUSTC_LIB) --pretty=expanded,identified $< -o $@ - -$(TMPDIR)/%.dot: %.rs - $(eval $(call FIND_LAST_BLOCK,$<)) - $(RUSTC_LIB) -Z unstable-options --unpretty flowgraph,unlabelled=$(LASTBLOCKNUM_$<) $< -o $@.tmp - cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \ - -e 's@\[label=""\]@@' \ - -e 's@digraph [a-zA-Z0-9_]* @digraph block @' \ - > $@ - -$(TMPDIR)/%.check: %.rs $(TMPDIR)/%.dot - diff -u $(patsubst %.rs,$(TMPDIR)/%.dot,$<) $(patsubst %.rs,%.dot-expected.dot,$<) diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot deleted file mode 100644 index 8ea8370ab235..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot +++ /dev/null @@ -1,9 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="block { }"]; - N3[label="expr { }"]; - N0 -> N2; - N2 -> N3; - N3 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f00.rs b/src/test/run-make/graphviz-flowgraph/f00.rs deleted file mode 100644 index 4e7fc7ea9b08..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f00.rs +++ /dev/null @@ -1,13 +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. - -pub fn empty_0() { - -} diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot deleted file mode 100644 index 5982fbea7690..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot +++ /dev/null @@ -1,13 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 1"]; - N3[label="stmt 1;"]; - N4[label="block { 1; }"]; - N5[label="expr { 1; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f01.rs b/src/test/run-make/graphviz-flowgraph/f01.rs deleted file mode 100644 index 231aab69e50d..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f01.rs +++ /dev/null @@ -1,13 +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. - -pub fn lit_1() { - 1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot deleted file mode 100644 index 1639785bd68c..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot +++ /dev/null @@ -1,13 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="local _x"]; - N3[label="stmt let _x: isize;"]; - N4[label="block { let _x: isize; }"]; - N5[label="expr { let _x: isize; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f02.rs b/src/test/run-make/graphviz-flowgraph/f02.rs deleted file mode 100644 index f7fe12661985..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f02.rs +++ /dev/null @@ -1,13 +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. - -pub fn decl_x_2() { - let _x : isize; -} diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot deleted file mode 100644 index b0ae00d81675..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot +++ /dev/null @@ -1,17 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 3"]; - N3[label="expr 4"]; - N4[label="expr 3 + 4"]; - N5[label="stmt 3 + 4;"]; - N6[label="block { 3 + 4; }"]; - N7[label="expr { 3 + 4; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f03.rs b/src/test/run-make/graphviz-flowgraph/f03.rs deleted file mode 100644 index 2dd71b623c24..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f03.rs +++ /dev/null @@ -1,13 +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. - -pub fn expr_add_3() { - 3 + 4; -} diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot deleted file mode 100644 index 41ace15a4c68..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot +++ /dev/null @@ -1,15 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 4"]; - N3[label="local _x"]; - N4[label="stmt let _x = 4;"]; - N5[label="block { let _x = 4; }"]; - N6[label="expr { let _x = 4; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f04.rs b/src/test/run-make/graphviz-flowgraph/f04.rs deleted file mode 100644 index 2a0ac8ac9e57..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f04.rs +++ /dev/null @@ -1,13 +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. - -pub fn pat_id_4() { - let _x = 4; -} diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot deleted file mode 100644 index 72b8ae71751c..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 5"]; - N3[label="expr 55"]; - N4[label="expr (5, 55)"]; - N5[label="local _x"]; - N6[label="local _y"]; - N7[label="pat (_x, _y)"]; - N8[label="stmt let (_x, _y) = (5, 55);"]; - N9[label="block { let (_x, _y) = (5, 55); }"]; - N10[label="expr { let (_x, _y) = (5, 55); }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f05.rs b/src/test/run-make/graphviz-flowgraph/f05.rs deleted file mode 100644 index 616d822bed07..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f05.rs +++ /dev/null @@ -1,13 +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. - -pub fn pat_tup_5() { - let (_x, _y) = (5, 55); -} diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot deleted file mode 100644 index acba71ef625f..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot +++ /dev/null @@ -1,19 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 6"]; - N3[label="expr S6{val: 6,}"]; - N4[label="local _x"]; - N5[label="pat S6 { val: _x }"]; - N6[label="stmt let S6 { val: _x } = S6{val: 6,};"]; - N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"]; - N8[label="expr { let S6 { val: _x } = S6{val: 6,}; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f06.rs b/src/test/run-make/graphviz-flowgraph/f06.rs deleted file mode 100644 index 538ef2af8989..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f06.rs +++ /dev/null @@ -1,14 +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. - -struct S6 { val: isize } -pub fn pat_struct_6() { - let S6 { val: _x } = S6{ val: 6 }; -} diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot deleted file mode 100644 index 251e2b39f14c..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ /dev/null @@ -1,39 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 7"]; - N3[label="expr 77"]; - N4[label="expr 777"]; - N5[label="expr 7777"]; - N6[label="expr [7, 77, 777, 7777]"]; - N7[label="expr match [7, 77, 777, 7777] { [x, y, ..] => x + y, }"]; - N8[label="(dummy_node)"]; - N9[label="local x"]; - N10[label="local y"]; - N11[label="pat _"]; - N12[label="pat [x, y, ..]"]; - N13[label="expr x"]; - N14[label="expr y"]; - N15[label="expr x + y"]; - N16[label="stmt match [7, 77, 777, 7777] { [x, y, ..] => x + y, };"]; - N17[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; - N18[label="expr { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N8; - N8 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N7; - N7 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f07.rs b/src/test/run-make/graphviz-flowgraph/f07.rs deleted file mode 100644 index f36b8d0abc7e..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f07.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(slice_patterns)] - -pub fn pat_vec_7() { - match [7, 77, 777, 7777] { - [x, y, ..] => x + y - }; -} diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot deleted file mode 100644 index e2779c9414a9..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot +++ /dev/null @@ -1,38 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 8"]; - N3[label="local x"]; - N4[label="stmt let x = 8;"]; - N5[label="local _y"]; - N6[label="stmt let _y;"]; - N7[label="expr x"]; - N8[label="expr 88"]; - N9[label="expr x > 88"]; - N10[label="expr 888"]; - N11[label="expr _y"]; - N12[label="expr _y = 888"]; - N13[label="stmt _y = 888;"]; - N14[label="block { _y = 888; }"]; - N15[label="expr if x > 88 { _y = 888; }"]; - N16[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"]; - N17[label="expr { let x = 8; let _y; if x > 88 { _y = 888; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N9 -> N15; - N14 -> N15; - N15 -> N16; - N16 -> N17; - N17 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f08.rs b/src/test/run-make/graphviz-flowgraph/f08.rs deleted file mode 100644 index 6ba7b03d54da..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f08.rs +++ /dev/null @@ -1,16 +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. - -pub fn expr_if_onearm_8() { - let x = 8; let _y; - if x > 88 { - _y = 888; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot deleted file mode 100644 index 536abde91e81..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot +++ /dev/null @@ -1,54 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 91"]; - N3[label="local x"]; - N4[label="stmt let x = 91;"]; - N5[label="local _y"]; - N6[label="stmt let _y;"]; - N7[label="expr x"]; - N8[label="expr 92"]; - N9[label="expr x > 92"]; - N10[label="expr 93"]; - N11[label="expr _y"]; - N12[label="expr _y = 93"]; - N13[label="stmt _y = 93;"]; - N14[label="block { _y = 93; }"]; - N15[label="expr 94"]; - N16[label="expr 95"]; - N17[label="expr 94 + 95"]; - N18[label="expr _y"]; - N19[label="expr _y = 94 + 95"]; - N20[label="stmt _y = 94 + 95;"]; - N21[label="block { _y = 94 + 95; }"]; - N22[label="expr { _y = 94 + 95; }"]; - N23[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"]; - N24[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; - N25[label="expr { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N9 -> N15; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N21 -> N22; - N14 -> N23; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f09.rs b/src/test/run-make/graphviz-flowgraph/f09.rs deleted file mode 100644 index a78ccb8a9374..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f09.rs +++ /dev/null @@ -1,18 +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. - -pub fn expr_if_twoarm_9() { - let x = 91; let _y; - if x > 92 { - _y = 93; - } else { - _y = 94+95; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot deleted file mode 100644 index 07b9c744a717..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot +++ /dev/null @@ -1,36 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 10"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 10;"]; - N5[label="(dummy_node)"]; - N6[label="expr while x > 0 { x -= 1; }"]; - N7[label="expr x"]; - N8[label="expr 0"]; - N9[label="expr x > 0"]; - N10[label="expr 1"]; - N11[label="expr x"]; - N12[label="expr x -= 1"]; - N13[label="stmt x -= 1;"]; - N14[label="block { x -= 1; }"]; - N15[label="block { let mut x = 10; while x > 0 { x -= 1; } }"]; - N16[label="expr { let mut x = 10; while x > 0 { x -= 1; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N6; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N5; - N6 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f10.rs b/src/test/run-make/graphviz-flowgraph/f10.rs deleted file mode 100644 index 0ca7cc5ee86b..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f10.rs +++ /dev/null @@ -1,16 +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. - -pub fn expr_while_10() { - let mut x = 10; - while x > 0 { - x -= 1; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot deleted file mode 100644 index 70034d299ba9..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot +++ /dev/null @@ -1,35 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 11"]; - N3[label="local mut _x"]; - N4[label="stmt let mut _x = 11;"]; - N5[label="(dummy_node)"]; - N6[label="expr loop { _x -= 1; }"]; - N7[label="expr 1"]; - N8[label="expr _x"]; - N9[label="expr _x -= 1"]; - N10[label="stmt _x -= 1;"]; - N11[label="block { _x -= 1; }"]; - N12[label="stmt loop { _x -= 1; }"]; - N13[label="expr \"unreachable\""]; - N14[label="stmt \"unreachable\";"]; - N15[label="block { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; - N16[label="expr { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N5; - N6 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f11.rs b/src/test/run-make/graphviz-flowgraph/f11.rs deleted file mode 100644 index d0f3452119e1..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f11.rs +++ /dev/null @@ -1,18 +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. - -#[allow(unreachable_code)] -pub fn expr_loop_11() { - let mut _x = 11; - loop { - _x -= 1; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot deleted file mode 100644 index 245afc43504c..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ /dev/null @@ -1,50 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 12"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 12;"]; - N5[label="(dummy_node)"]; - N6[label="expr loop { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; - N7[label="expr 1"]; - N8[label="expr x"]; - N9[label="expr x -= 1"]; - N10[label="stmt x -= 1;"]; - N11[label="expr x"]; - N12[label="expr 2"]; - N13[label="expr x == 2"]; - N14[label="expr break"]; - N15[label="(dummy_node)"]; - N16[label="stmt break ;"]; - N17[label="expr \"unreachable\""]; - N18[label="stmt \"unreachable\";"]; - N19[label="block { break ; \"unreachable\"; }"]; - N20[label="expr if x == 2 { break ; \"unreachable\"; }"]; - N21[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; - N22[label="block { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; - N23[label="expr { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N6; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N13 -> N20; - N19 -> N20; - N20 -> N21; - N21 -> N5; - N6 -> N22; - N22 -> N23; - N23 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f12.rs b/src/test/run-make/graphviz-flowgraph/f12.rs deleted file mode 100644 index 90b146340b6f..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f12.rs +++ /dev/null @@ -1,18 +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. - -#[allow(unreachable_code)] -pub fn expr_loop_12() { - let mut x = 12; - loop { - x -= 1; - if x == 2 { break; "unreachable"; } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot deleted file mode 100644 index 0f268bd0f2ae..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ /dev/null @@ -1,54 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr E13::E13b"]; - N3[label="expr 13"]; - N4[label="expr E13::E13b(13)"]; - N5[label="local x"]; - N6[label="stmt let x = E13::E13b(13);"]; - N7[label="local _y"]; - N8[label="stmt let _y;"]; - N9[label="expr x"]; - N10[label="expr match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }"]; - N11[label="(dummy_node)"]; - N12[label="pat E13::E13a"]; - N13[label="expr 1"]; - N14[label="expr _y"]; - N15[label="expr _y = 1"]; - N16[label="(dummy_node)"]; - N17[label="local v"]; - N18[label="pat E13::E13b(v)"]; - N19[label="expr v"]; - N20[label="expr 1"]; - N21[label="expr v + 1"]; - N22[label="expr _y"]; - N23[label="expr _y = v + 1"]; - N24[label="block {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; - N25[label="expr {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N12; - N12 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N10; - N9 -> N17; - N17 -> N18; - N18 -> N16; - N16 -> N19; - N19 -> N20; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N10; - N10 -> N24; - N24 -> N25; - N25 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f13.rs b/src/test/run-make/graphviz-flowgraph/f13.rs deleted file mode 100644 index babb283c7342..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f13.rs +++ /dev/null @@ -1,18 +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. - -enum E13 { E13a, E13b(isize) } -pub fn expr_match_13() { - let x = E13::E13b(13); let _y; - match x { - E13::E13a => _y = 1, - E13::E13b(v) => _y = v + 1, - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot deleted file mode 100644 index 719a6cf2619d..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot +++ /dev/null @@ -1,36 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 14"]; - N3[label="local x"]; - N4[label="stmt let x = 14;"]; - N5[label="expr x"]; - N6[label="expr 1"]; - N7[label="expr x > 1"]; - N8[label="expr return"]; - N9[label="(dummy_node)"]; - N10[label="stmt return;"]; - N11[label="expr \"unreachable\""]; - N12[label="stmt \"unreachable\";"]; - N13[label="block { return; \"unreachable\"; }"]; - N14[label="expr if x > 1 { return; \"unreachable\"; }"]; - N15[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; - N16[label="expr { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N1; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N7 -> N14; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f14.rs b/src/test/run-make/graphviz-flowgraph/f14.rs deleted file mode 100644 index 98ff095c8317..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f14.rs +++ /dev/null @@ -1,18 +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. - -#[allow(unreachable_code)] -pub fn expr_ret_14() { - let x = 14; - if x > 1 { - return; - "unreachable"; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot deleted file mode 100644 index d8cbd8411e20..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ /dev/null @@ -1,105 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr break \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt break \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { break \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="stmt break ;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { break ; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { break ; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { break ; \"unreachable\"; }"]; - N34[label="expr 3"]; - N35[label="expr y"]; - N36[label="expr y -= 3"]; - N37[label="stmt y -= 3;"]; - N38[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l}\l"]; - N39[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"]; - N40[label="expr 4"]; - N41[label="expr y"]; - N42[label="expr y -= 4"]; - N43[label="stmt y -= 4;"]; - N44[label="expr 5"]; - N45[label="expr x"]; - N46[label="expr x -= 5"]; - N47[label="stmt x -= 5;"]; - N48[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; - N49[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; - N50[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N9; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N11; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N10; - N11 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N48 -> N8; - N9 -> N49; - N49 -> N50; - N50 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs deleted file mode 100644 index 056458e5558d..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f15.rs +++ /dev/null @@ -1,30 +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. - -#[allow(unreachable_code)] -pub fn expr_break_label_15() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - break 'outer; - "unreachable"; - } - if y >= 2 { - break; - "unreachable"; - } - y -= 3; - } - y -= 4; - x -= 5; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot deleted file mode 100644 index b11881247fb6..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ /dev/null @@ -1,111 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 16"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 16;"]; - N5[label="expr 16"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 16;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr continue \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt continue \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { continue \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 1"]; - N25[label="expr y >= 1"]; - N26[label="expr break"]; - N27[label="(dummy_node)"]; - N28[label="stmt break ;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { break ; \"unreachable\"; }"]; - N32[label="expr if y >= 1 { break ; \"unreachable\"; }"]; - N33[label="stmt if y >= 1 { break ; \"unreachable\"; }"]; - N34[label="expr 1"]; - N35[label="expr y"]; - N36[label="expr y -= 1"]; - N37[label="stmt y -= 1;"]; - N38[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l}\l"]; - N39[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"]; - N40[label="expr 1"]; - N41[label="expr y"]; - N42[label="expr y -= 1"]; - N43[label="stmt y -= 1;"]; - N44[label="expr 1"]; - N45[label="expr x"]; - N46[label="expr x -= 1"]; - N47[label="stmt x -= 1;"]; - N48[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l}\l"]; - N49[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"]; - N50[label="expr \"unreachable\""]; - N51[label="stmt \"unreachable\";"]; - N52[label="block {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; - N53[label="expr {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N8; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N11; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N10; - N11 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N48 -> N8; - N9 -> N49; - N49 -> N50; - N50 -> N51; - N51 -> N52; - N52 -> N53; - N53 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs deleted file mode 100644 index e225b0080e59..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f16.rs +++ /dev/null @@ -1,31 +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. - -#[allow(unreachable_code)] -pub fn expr_continue_label_16() { - let mut x = 16; - let mut y = 16; - 'outer: loop { - 'inner: loop { - if x == 1 { - continue 'outer; - "unreachable"; - } - if y >= 1 { - break; - "unreachable"; - } - y -= 1; - } - y -= 1; - x -= 1; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot deleted file mode 100644 index 705eece77558..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot +++ /dev/null @@ -1,21 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 1"]; - N3[label="expr 7"]; - N4[label="expr 17"]; - N5[label="expr [1, 7, 17]"]; - N6[label="local _v"]; - N7[label="stmt let _v = [1, 7, 17];"]; - N8[label="block { let _v = [1, 7, 17]; }"]; - N9[label="expr { let _v = [1, 7, 17]; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f17.rs b/src/test/run-make/graphviz-flowgraph/f17.rs deleted file mode 100644 index 23f5bb8a1eb1..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f17.rs +++ /dev/null @@ -1,13 +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. - -pub fn expr_vec_17() { - let _v = [1, 7, 17]; -} diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot deleted file mode 100644 index b0491fe6e27f..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot +++ /dev/null @@ -1,23 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="stmt fn inner(x: isize) -> isize { x + x }"]; - N3[label="expr inner"]; - N4[label="expr inner"]; - N5[label="expr 18"]; - N6[label="expr inner(18)"]; - N7[label="expr inner(inner(18))"]; - N8[label="stmt inner(inner(18));"]; - N9[label="block {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"]; - N10[label="expr {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f18.rs b/src/test/run-make/graphviz-flowgraph/f18.rs deleted file mode 100644 index cbf8aa5db439..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f18.rs +++ /dev/null @@ -1,14 +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. - -pub fn expr_call_18() { - fn inner(x:isize) -> isize { x + x } - inner(inner(18)); -} diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot deleted file mode 100644 index 223978c3d763..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot +++ /dev/null @@ -1,29 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="stmt struct S19 {\l x: isize,\l}\l"]; - N3[label="stmt impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l}\l"]; - N4[label="expr 19"]; - N5[label="expr S19{x: 19,}"]; - N6[label="local s"]; - N7[label="stmt let s = S19{x: 19,};"]; - N8[label="expr s"]; - N9[label="expr s.inner()"]; - N10[label="expr s.inner().inner()"]; - N11[label="stmt s.inner().inner();"]; - N12[label="block {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; - N13[label="expr {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f19.rs b/src/test/run-make/graphviz-flowgraph/f19.rs deleted file mode 100644 index 78c15dd64adc..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f19.rs +++ /dev/null @@ -1,16 +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. - -pub fn expr_method_call_19() { - struct S19 { x: isize } - impl S19 { fn inner(self) -> S19 { S19 { x: self.x + self.x } } } - let s = S19 { x: 19 }; - s.inner().inner(); -} diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot deleted file mode 100644 index 120eab4dac90..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot +++ /dev/null @@ -1,29 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 2"]; - N3[label="expr 0"]; - N4[label="expr 20"]; - N5[label="expr [2, 0, 20]"]; - N6[label="local v"]; - N7[label="stmt let v = [2, 0, 20];"]; - N8[label="expr v"]; - N9[label="expr 20"]; - N10[label="expr v[20]"]; - N11[label="stmt v[20];"]; - N12[label="block { let v = [2, 0, 20]; v[20]; }"]; - N13[label="expr { let v = [2, 0, 20]; v[20]; }"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N12; - N12 -> N13; - N13 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f20.rs b/src/test/run-make/graphviz-flowgraph/f20.rs deleted file mode 100644 index d7349932355b..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f20.rs +++ /dev/null @@ -1,14 +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. - -pub fn expr_index_20() { - let v = [2, 0, 20]; - v[20]; -} diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot deleted file mode 100644 index 370dcdd8554d..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ /dev/null @@ -1,101 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr break \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt break \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { break \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr return"]; - N27[label="(dummy_node)"]; - N28[label="stmt return;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { return; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { return; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { return; \"unreachable\"; }"]; - N34[label="expr 3"]; - N35[label="expr y"]; - N36[label="expr y -= 3"]; - N37[label="stmt y -= 3;"]; - N38[label="expr 5"]; - N39[label="expr x"]; - N40[label="expr x -= 5"]; - N41[label="stmt x -= 5;"]; - N42[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l}\l"]; - N43[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"]; - N44[label="expr \"unreachable\""]; - N45[label="stmt \"unreachable\";"]; - N46[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"]; - N47[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; - N48[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N9; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N1; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N10; - N11 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N8; - N9 -> N47; - N47 -> N48; - N48 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f21.rs b/src/test/run-make/graphviz-flowgraph/f21.rs deleted file mode 100644 index 70083ed8312c..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f21.rs +++ /dev/null @@ -1,30 +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. - -#[allow(unreachable_code)] -pub fn expr_break_label_21() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - break 'outer; - "unreachable"; - } - if y >= 2 { - return; - "unreachable"; - } - y -= 3; - x -= 5; - } - "unreachable"; - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot deleted file mode 100644 index 9d3bc22831a1..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ /dev/null @@ -1,107 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 15"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 15;"]; - N5[label="expr 151"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 151;"]; - N8[label="(dummy_node)"]; - N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; - N10[label="(dummy_node)"]; - N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"]; - N12[label="expr x"]; - N13[label="expr 1"]; - N14[label="expr x == 1"]; - N15[label="expr continue \'outer"]; - N16[label="(dummy_node)"]; - N17[label="stmt continue \'outer ;"]; - N18[label="expr \"unreachable\""]; - N19[label="stmt \"unreachable\";"]; - N20[label="block { continue \'outer ; \"unreachable\"; }"]; - N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"]; - N23[label="expr y"]; - N24[label="expr 2"]; - N25[label="expr y >= 2"]; - N26[label="expr return"]; - N27[label="(dummy_node)"]; - N28[label="stmt return;"]; - N29[label="expr \"unreachable\""]; - N30[label="stmt \"unreachable\";"]; - N31[label="block { return; \"unreachable\"; }"]; - N32[label="expr if y >= 2 { return; \"unreachable\"; }"]; - N33[label="stmt if y >= 2 { return; \"unreachable\"; }"]; - N34[label="expr 1"]; - N35[label="expr x"]; - N36[label="expr x -= 1"]; - N37[label="stmt x -= 1;"]; - N38[label="expr 3"]; - N39[label="expr y"]; - N40[label="expr y -= 3"]; - N41[label="stmt y -= 3;"]; - N42[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l}\l"]; - N43[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"]; - N44[label="expr \"unreachable\""]; - N45[label="stmt \"unreachable\";"]; - N46[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l}\l"]; - N47[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; - N48[label="expr \"unreachable\""]; - N49[label="stmt \"unreachable\";"]; - N50[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; - N51[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N10; - N10 -> N12; - N12 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N8; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N14 -> N21; - N20 -> N21; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N1; - N27 -> N28; - N28 -> N29; - N29 -> N30; - N30 -> N31; - N25 -> N32; - N31 -> N32; - N32 -> N33; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N10; - N11 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N46; - N46 -> N8; - N9 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N51; - N51 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f22.rs b/src/test/run-make/graphviz-flowgraph/f22.rs deleted file mode 100644 index b35aac9ec422..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f22.rs +++ /dev/null @@ -1,31 +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. - -#[allow(unreachable_code)] -pub fn expr_break_label_21() { - let mut x = 15; - let mut y = 151; - 'outer: loop { - 'inner: loop { - if x == 1 { - continue 'outer; - "unreachable"; - } - if y >= 2 { - return; - "unreachable"; - } - x -= 1; - y -= 3; - } - "unreachable"; - } - "unreachable"; -} diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot deleted file mode 100644 index c8bfcd6510b3..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot +++ /dev/null @@ -1,113 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 23"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 23;"]; - N5[label="expr 23"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 23;"]; - N8[label="expr 23"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 23;"]; - N11[label="(dummy_node)"]; - N12[label="expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x > 0"]; - N16[label="expr 1"]; - N17[label="expr x"]; - N18[label="expr x -= 1"]; - N19[label="stmt x -= 1;"]; - N20[label="(dummy_node)"]; - N21[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N22[label="expr y"]; - N23[label="expr 0"]; - N24[label="expr y > 0"]; - N25[label="expr 1"]; - N26[label="expr y"]; - N27[label="expr y -= 1"]; - N28[label="stmt y -= 1;"]; - N29[label="(dummy_node)"]; - N30[label="expr while z > 0 { z -= 1; }"]; - N31[label="expr z"]; - N32[label="expr 0"]; - N33[label="expr z > 0"]; - N34[label="expr 1"]; - N35[label="expr z"]; - N36[label="expr z -= 1"]; - N37[label="stmt z -= 1;"]; - N38[label="block { z -= 1; }"]; - N39[label="stmt while z > 0 { z -= 1; }"]; - N40[label="expr x"]; - N41[label="expr 10"]; - N42[label="expr x > 10"]; - N43[label="expr return"]; - N44[label="(dummy_node)"]; - N45[label="stmt return;"]; - N46[label="expr \"unreachable\""]; - N47[label="stmt \"unreachable\";"]; - N48[label="block { return; \"unreachable\"; }"]; - N49[label="expr if x > 10 { return; \"unreachable\"; }"]; - N50[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"]; - N51[label="block {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N52[label="block {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N53[label="expr {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N12; - N15 -> N16; - N16 -> N17; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N21; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N29; - N29 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N30; - N33 -> N34; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N38 -> N29; - N30 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N1; - N44 -> N45; - N45 -> N46; - N46 -> N47; - N47 -> N48; - N42 -> N49; - N48 -> N49; - N49 -> N50; - N50 -> N20; - N21 -> N51; - N51 -> N11; - N12 -> N52; - N52 -> N53; - N53 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f23.rs b/src/test/run-make/graphviz-flowgraph/f23.rs deleted file mode 100644 index 52341a3fbd40..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f23.rs +++ /dev/null @@ -1,31 +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. - -#[allow(unreachable_code)] -pub fn expr_while_23() { - let mut x = 23; - let mut y = 23; - let mut z = 23; - - while x > 0 { - x -= 1; - - while y > 0 { - y -= 1; - - while z > 0 { z -= 1; } - - if x > 10 { - return; - "unreachable"; - } - } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot deleted file mode 100644 index e40dd014f0a4..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ /dev/null @@ -1,161 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 24"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 24;"]; - N5[label="expr 24"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 24;"]; - N8[label="expr 24"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 24;"]; - N11[label="(dummy_node)"]; - N12[label="expr loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x == 0"]; - N16[label="expr break"]; - N17[label="(dummy_node)"]; - N18[label="stmt break ;"]; - N19[label="expr \"unreachable\""]; - N20[label="stmt \"unreachable\";"]; - N21[label="block { break ; \"unreachable\"; }"]; - N22[label="expr if x == 0 { break ; \"unreachable\"; }"]; - N23[label="stmt if x == 0 { break ; \"unreachable\"; }"]; - N24[label="expr 1"]; - N25[label="expr x"]; - N26[label="expr x -= 1"]; - N27[label="stmt x -= 1;"]; - N28[label="(dummy_node)"]; - N29[label="expr loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N30[label="expr y"]; - N31[label="expr 0"]; - N32[label="expr y == 0"]; - N33[label="expr break"]; - N34[label="(dummy_node)"]; - N35[label="stmt break ;"]; - N36[label="expr \"unreachable\""]; - N37[label="stmt \"unreachable\";"]; - N38[label="block { break ; \"unreachable\"; }"]; - N39[label="expr if y == 0 { break ; \"unreachable\"; }"]; - N40[label="stmt if y == 0 { break ; \"unreachable\"; }"]; - N41[label="expr 1"]; - N42[label="expr y"]; - N43[label="expr y -= 1"]; - N44[label="stmt y -= 1;"]; - N45[label="(dummy_node)"]; - N46[label="expr loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N47[label="expr z"]; - N48[label="expr 0"]; - N49[label="expr z == 0"]; - N50[label="expr break"]; - N51[label="(dummy_node)"]; - N52[label="stmt break ;"]; - N53[label="expr \"unreachable\""]; - N54[label="stmt \"unreachable\";"]; - N55[label="block { break ; \"unreachable\"; }"]; - N56[label="expr if z == 0 { break ; \"unreachable\"; }"]; - N57[label="stmt if z == 0 { break ; \"unreachable\"; }"]; - N58[label="expr 1"]; - N59[label="expr z"]; - N60[label="expr z -= 1"]; - N61[label="stmt z -= 1;"]; - N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N63[label="stmt loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N64[label="expr x"]; - N65[label="expr 10"]; - N66[label="expr x > 10"]; - N67[label="expr return"]; - N68[label="(dummy_node)"]; - N69[label="stmt return;"]; - N70[label="expr \"unreachable\""]; - N71[label="stmt \"unreachable\";"]; - N72[label="block { return; \"unreachable\"; }"]; - N73[label="expr if x > 10 { return; \"unreachable\"; }"]; - N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; - N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; - N76[label="block {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N77[label="expr {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N12; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N15 -> N22; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N30; - N30 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N29; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N32 -> N39; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N46; - N51 -> N52; - N52 -> N53; - N53 -> N54; - N54 -> N55; - N49 -> N56; - N55 -> N56; - N56 -> N57; - N57 -> N58; - N58 -> N59; - N59 -> N60; - N60 -> N61; - N61 -> N62; - N62 -> N45; - N46 -> N63; - N63 -> N64; - N64 -> N65; - N65 -> N66; - N66 -> N67; - N67 -> N1; - N68 -> N69; - N69 -> N70; - N70 -> N71; - N71 -> N72; - N66 -> N73; - N72 -> N73; - N73 -> N74; - N74 -> N28; - N29 -> N75; - N75 -> N11; - N12 -> N76; - N76 -> N77; - N77 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f24.rs b/src/test/run-make/graphviz-flowgraph/f24.rs deleted file mode 100644 index f796d660a185..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f24.rs +++ /dev/null @@ -1,36 +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. - -#[allow(unreachable_code)] -pub fn expr_while_24() { - let mut x = 24; - let mut y = 24; - let mut z = 24; - - loop { - if x == 0 { break; "unreachable"; } - x -= 1; - - loop { - if y == 0 { break; "unreachable"; } - y -= 1; - - loop { - if z == 0 { break; "unreachable"; } - z -= 1; - } - - if x > 10 { - return; - "unreachable"; - } - } - } -} diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot deleted file mode 100644 index 1e2df1ab5e7b..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ /dev/null @@ -1,161 +0,0 @@ -digraph block { - N0[label="entry"]; - N1[label="exit"]; - N2[label="expr 25"]; - N3[label="local mut x"]; - N4[label="stmt let mut x = 25;"]; - N5[label="expr 25"]; - N6[label="local mut y"]; - N7[label="stmt let mut y = 25;"]; - N8[label="expr 25"]; - N9[label="local mut z"]; - N10[label="stmt let mut z = 25;"]; - N11[label="(dummy_node)"]; - N12[label="expr \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l"]; - N13[label="expr x"]; - N14[label="expr 0"]; - N15[label="expr x == 0"]; - N16[label="expr break"]; - N17[label="(dummy_node)"]; - N18[label="stmt break ;"]; - N19[label="expr \"unreachable\""]; - N20[label="stmt \"unreachable\";"]; - N21[label="block { break ; \"unreachable\"; }"]; - N22[label="expr if x == 0 { break ; \"unreachable\"; }"]; - N23[label="stmt if x == 0 { break ; \"unreachable\"; }"]; - N24[label="expr 1"]; - N25[label="expr x"]; - N26[label="expr x -= 1"]; - N27[label="stmt x -= 1;"]; - N28[label="(dummy_node)"]; - N29[label="expr \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l"]; - N30[label="expr y"]; - N31[label="expr 0"]; - N32[label="expr y == 0"]; - N33[label="expr break"]; - N34[label="(dummy_node)"]; - N35[label="stmt break ;"]; - N36[label="expr \"unreachable\""]; - N37[label="stmt \"unreachable\";"]; - N38[label="block { break ; \"unreachable\"; }"]; - N39[label="expr if y == 0 { break ; \"unreachable\"; }"]; - N40[label="stmt if y == 0 { break ; \"unreachable\"; }"]; - N41[label="expr 1"]; - N42[label="expr y"]; - N43[label="expr y -= 1"]; - N44[label="stmt y -= 1;"]; - N45[label="(dummy_node)"]; - N46[label="expr \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N47[label="expr z"]; - N48[label="expr 0"]; - N49[label="expr z == 0"]; - N50[label="expr break"]; - N51[label="(dummy_node)"]; - N52[label="stmt break ;"]; - N53[label="expr \"unreachable\""]; - N54[label="stmt \"unreachable\";"]; - N55[label="block { break ; \"unreachable\"; }"]; - N56[label="expr if z == 0 { break ; \"unreachable\"; }"]; - N57[label="stmt if z == 0 { break ; \"unreachable\"; }"]; - N58[label="expr 1"]; - N59[label="expr z"]; - N60[label="expr z -= 1"]; - N61[label="stmt z -= 1;"]; - N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N63[label="stmt \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; - N64[label="expr x"]; - N65[label="expr 10"]; - N66[label="expr x > 10"]; - N67[label="expr continue \'a"]; - N68[label="(dummy_node)"]; - N69[label="stmt continue \'a ;"]; - N70[label="expr \"unreachable\""]; - N71[label="stmt \"unreachable\";"]; - N72[label="block { continue \'a ; \"unreachable\"; }"]; - N73[label="expr if x > 10 { continue \'a ; \"unreachable\"; }"]; - N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; - N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"]; - N76[label="block {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; - N77[label="expr {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; - N0 -> N2; - N2 -> N3; - N3 -> N4; - N4 -> N5; - N5 -> N6; - N6 -> N7; - N7 -> N8; - N8 -> N9; - N9 -> N10; - N10 -> N11; - N11 -> N13; - N13 -> N14; - N14 -> N15; - N15 -> N16; - N16 -> N12; - N17 -> N18; - N18 -> N19; - N19 -> N20; - N20 -> N21; - N15 -> N22; - N21 -> N22; - N22 -> N23; - N23 -> N24; - N24 -> N25; - N25 -> N26; - N26 -> N27; - N27 -> N28; - N28 -> N30; - N30 -> N31; - N31 -> N32; - N32 -> N33; - N33 -> N29; - N34 -> N35; - N35 -> N36; - N36 -> N37; - N37 -> N38; - N32 -> N39; - N38 -> N39; - N39 -> N40; - N40 -> N41; - N41 -> N42; - N42 -> N43; - N43 -> N44; - N44 -> N45; - N45 -> N47; - N47 -> N48; - N48 -> N49; - N49 -> N50; - N50 -> N46; - N51 -> N52; - N52 -> N53; - N53 -> N54; - N54 -> N55; - N49 -> N56; - N55 -> N56; - N56 -> N57; - N57 -> N58; - N58 -> N59; - N59 -> N60; - N60 -> N61; - N61 -> N62; - N62 -> N45; - N46 -> N63; - N63 -> N64; - N64 -> N65; - N65 -> N66; - N66 -> N67; - N67 -> N28; - N68 -> N69; - N69 -> N70; - N70 -> N71; - N71 -> N72; - N66 -> N73; - N72 -> N73; - N73 -> N74; - N74 -> N28; - N29 -> N75; - N75 -> N11; - N12 -> N76; - N76 -> N77; - N77 -> N1; -} diff --git a/src/test/run-make/graphviz-flowgraph/f25.rs b/src/test/run-make/graphviz-flowgraph/f25.rs deleted file mode 100644 index 2ee2e48fd10e..000000000000 --- a/src/test/run-make/graphviz-flowgraph/f25.rs +++ /dev/null @@ -1,36 +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. - -#[allow(unreachable_code)] -pub fn expr_while_25() { - let mut x = 25; - let mut y = 25; - let mut z = 25; - - 'a: loop { - if x == 0 { break; "unreachable"; } - x -= 1; - - 'a: loop { - if y == 0 { break; "unreachable"; } - y -= 1; - - 'a: loop { - if z == 0 { break; "unreachable"; } - z -= 1; - } - - if x > 10 { - continue 'a; - "unreachable"; - } - } - } -} From fb99d87c460c8f35ae8ab9e3694aa34d983dbd9c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 25 Mar 2017 05:30:39 -0400 Subject: [PATCH 179/905] update UI test We no longer give suggestions; this is presumably related to the changes I made in coercion. However, those suggestions appear to be wrong anyhow! --- src/test/ui/resolve/token-error-correct-3.stderr | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 56e368895750..5be23d8ca48c 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -36,10 +36,6 @@ error[E0308]: mismatched types | = note: expected type `()` found type `std::result::Result` - = help: here are some functions which might fulfill your needs: - - .unwrap() - - .unwrap_err() - - .unwrap_or_default() error: aborting due to previous error From 744f666445348d505f42b3fb77217e31d8eb786b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 26 Mar 2017 07:02:39 -0400 Subject: [PATCH 180/905] fix error message for issue-10176.rs --- src/test/compile-fail/issue-10176.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-10176.rs b/src/test/compile-fail/issue-10176.rs index 434b795ff31f..c968844ae21a 100644 --- a/src/test/compile-fail/issue-10176.rs +++ b/src/test/compile-fail/issue-10176.rs @@ -12,7 +12,7 @@ fn f() -> isize { (return 1, return 2) //~^ ERROR mismatched types //~| expected type `isize` -//~| found type `(_, _)` +//~| found type `(!, !)` //~| expected isize, found tuple } From 2414222b17f45e33d68582dd5ebe0083ed27b8cc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 27 Mar 2017 19:48:55 -0400 Subject: [PATCH 181/905] remove comments that were tripping up pretty printer --- src/test/run-pass/issue-39808.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/issue-39808.rs b/src/test/run-pass/issue-39808.rs index 00c2bdc8cc99..91c70d76eefb 100644 --- a/src/test/run-pass/issue-39808.rs +++ b/src/test/run-pass/issue-39808.rs @@ -19,7 +19,7 @@ use std::borrow::Cow; fn main() { let _ = if false { - Cow::Owned(format!("{:?}", panic!())) /* as Cow */ // uncomment to fix + Cow::Owned(format!("{:?}", panic!())) } else { Cow::Borrowed("") }; From 8804a4a6d91309ffb33dc62a430d4749a803348a Mon Sep 17 00:00:00 2001 From: Luxko Date: Thu, 30 Mar 2017 20:36:07 +0800 Subject: [PATCH 182/905] Add missing link in unstable-book add link to specialization's tracking issue --- src/doc/unstable-book/src/specialization.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/unstable-book/src/specialization.md b/src/doc/unstable-book/src/specialization.md index 59f27343b66d..efc380df6e11 100644 --- a/src/doc/unstable-book/src/specialization.md +++ b/src/doc/unstable-book/src/specialization.md @@ -2,6 +2,8 @@ The tracking issue for this feature is: [#31844] +[#31844]: https://github.com/rust-lang/rust/issues/31844 + ------------------------ From 3fa28cc11eb5559b169f0d2fc7523f933e188e13 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 30 Mar 2017 16:08:13 +0200 Subject: [PATCH 183/905] Add a note about overflow for fetch_add/fetch_sub --- src/libcore/sync/atomic.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 743e3c41170a..cde98a670367 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1171,6 +1171,8 @@ macro_rules! atomic_int { /// Add to the current value, returning the previous value. /// + /// This operation wraps around on overflow. + /// /// # Examples /// /// ``` @@ -1188,6 +1190,8 @@ macro_rules! atomic_int { /// Subtract from the current value, returning the previous value. /// + /// This operation wraps around on overflow. + /// /// # Examples /// /// ``` From 2946c41c05c8bfbad04a431c4a4603127630367d Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 30 Mar 2017 16:23:46 +0200 Subject: [PATCH 184/905] More consistent wording --- src/libcore/sync/atomic.rs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index cde98a670367..12c1287b4f65 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -296,7 +296,7 @@ impl AtomicBool { } } - /// Stores a value into the bool, returning the old value. + /// Stores a value into the bool, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -703,7 +703,7 @@ impl AtomicPtr { } } - /// Stores a value into the pointer, returning the old value. + /// Stores a value into the pointer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -1015,7 +1015,7 @@ macro_rules! atomic_int { unsafe { atomic_store(self.v.get(), val, order); } } - /// Stores a value into the atomic integer, returning the old value. + /// Stores a value into the atomic integer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. @@ -1169,7 +1169,7 @@ macro_rules! atomic_int { } } - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. /// /// This operation wraps around on overflow. /// @@ -1188,7 +1188,7 @@ macro_rules! atomic_int { unsafe { atomic_add(self.v.get(), val, order) } } - /// Subtract from the current value, returning the previous value. + /// Subtracts from the current value, returning the previous value. /// /// This operation wraps around on overflow. /// @@ -1207,7 +1207,12 @@ macro_rules! atomic_int { unsafe { atomic_sub(self.v.get(), val, order) } } - /// Bitwise and with the current value, returning the previous value. + /// 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 /// @@ -1223,7 +1228,12 @@ macro_rules! atomic_int { unsafe { atomic_and(self.v.get(), val, order) } } - /// Bitwise or with the current value, returning the previous value. + /// 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 /// @@ -1239,7 +1249,12 @@ macro_rules! atomic_int { unsafe { atomic_or(self.v.get(), val, order) } } - /// Bitwise xor with the current value, returning the previous value. + /// 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 /// @@ -1387,7 +1402,7 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_add). +/// Returns the previous value (like __sync_fetch_and_add). #[inline] unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { @@ -1400,7 +1415,7 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_sub). +/// Returns the previous value (like __sync_fetch_and_sub). #[inline] unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { From f82705403f133bbff8d8ab72f34a3a3e522c7c98 Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Thu, 30 Mar 2017 16:31:16 +0200 Subject: [PATCH 185/905] adding debug in consume_body function When in debug_assertions=true mode, the function consume_body lacks some debug output, which makes it harder to follow the control flow. This commit adds this needed debug. --- src/librustc/middle/expr_use_visitor.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a44679b0b3e0..57b96dba753a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -288,6 +288,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } pub fn consume_body(&mut self, body: &hir::Body) { + debug!("consume_body(body={:?})", body); + for arg in &body.arguments { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); From ea281962149cd188edf384cb120852369b669c50 Mon Sep 17 00:00:00 2001 From: GAJaloyan Date: Thu, 30 Mar 2017 17:02:51 +0200 Subject: [PATCH 186/905] removing trailing whitespaces --- src/librustc/middle/expr_use_visitor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 57b96dba753a..dc40d0bc649d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn consume_body(&mut self, body: &hir::Body) { debug!("consume_body(body={:?})", body); - + for arg in &body.arguments { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); From 6fda0fe891fd85f5cde89fe672d5796f15269898 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 30 Mar 2017 17:25:36 +0200 Subject: [PATCH 187/905] cmp: Implement all PartialOrd methods for Reverse When making a forwarding wrapper we must in general forward all methods, so that we use the type's own `lt` for example instead of the default. Example important case: f32's partial_cmp does several operations but its lt is a primitive. --- src/libcore/cmp.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index dc2398b22ace..74ded948b18e 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -347,6 +347,15 @@ impl PartialOrd for Reverse { fn partial_cmp(&self, other: &Reverse) -> Option { other.0.partial_cmp(&self.0) } + + #[inline] + fn lt(&self, other: &Self) -> bool { other.0 < self.0 } + #[inline] + fn le(&self, other: &Self) -> bool { other.0 <= self.0 } + #[inline] + fn ge(&self, other: &Self) -> bool { other.0 >= self.0 } + #[inline] + fn gt(&self, other: &Self) -> bool { other.0 > self.0 } } #[unstable(feature = "reverse_cmp_key", issue = "40893")] From 9d4b486b845c7d04691801f1151219b41b7c327b Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:36:50 -0400 Subject: [PATCH 188/905] Modify Lines' description --- src/libcore/str/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 857eeb26af07..e995b59a1450 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1161,9 +1161,13 @@ generate_pattern_iterators! { delegate double ended; } -/// Created with the method [`lines`]. +/// An iterator over the lines of a string, as string slices. /// -/// [`lines`]: ../../std/primitive.str.html#method.lines +/// This struct is created with the [`lines()`] method on [`str`]. +/// See its documentation for more. +/// +/// [`lines()`]: ../../std/primitive.str.html#method.lines +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Lines<'a>(Map, LinesAnyMap>); From 0f5cf54246f7a68a8fc18ee41dffc7cdf866e19c Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:40:05 -0400 Subject: [PATCH 189/905] Modify Bytes' description --- src/libcore/str/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e995b59a1450..4556d41dd0a5 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -625,12 +625,13 @@ impl<'a> CharIndices<'a> { } } -/// External iterator for a string's bytes. -/// Use with the `std::iter` module. +/// An iterator over the bytes of a string slice. /// -/// Created with the method [`bytes`]. +/// This struct is created by the [`bytes()`] method on [`str`]. +/// See its documentation for more. /// -/// [`bytes`]: ../../std/primitive.str.html#method.bytes +/// [`bytes()`]: ../../std/primitive.str.html#method.bytes +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Bytes<'a>(Cloned>); From b03edb4a0245b04716c537ac4f2c0eee4ec5b321 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Thu, 30 Mar 2017 13:23:35 -0500 Subject: [PATCH 190/905] Improve the docs for the write and writeln macros This change reduces duplication by linking the documentation for `writeln!` to `write!`. It also restructures the `write!` documentation to read in a more logical manner. Updates #29329, #29381 --- src/libcore/macros.rs | 54 +++++++++++++------------------------------ 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 021079f85f6b..2a28d108df77 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -337,27 +337,20 @@ macro_rules! try { /// Write formatted data into a buffer /// -/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a -/// list of arguments to format. +/// This macro accepts a format string, a list of arguments, and a 'writer'. Arguments will be +/// formatted according to the specified format string and the result will be passed to the writer. +/// The writer may be any value with a `write_fmt` method; generally this comes from an +/// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro +/// returns whatever the 'write_fmt' method returns; commonly a [`std::fmt::Result`], or an +/// [`io::Result`]. /// -/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] -/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of -/// these two traits. +/// See [`std::fmt`] for more information on the format string syntax. /// -/// Passed arguments will be formatted according to the specified format string and the resulting -/// string will be passed to the writer. -/// -/// See [`std::fmt`][fmt] for more information on format syntax. -/// -/// `write!` returns whatever the 'write_fmt' method returns. -/// -/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] -/// -/// [fmt]: ../std/fmt/index.html -/// [fmt_write]: ../std/fmt/trait.Write.html -/// [io_write]: ../std/io/trait.Write.html -/// [fmt_result]: ../std/fmt/type.Result.html -/// [io_result]: ../std/io/type.Result.html +/// [`std::fmt`]: ../std/fmt/index.html +/// [`std::fmt::Write`]: ../std/fmt/trait.Write.html +/// [`std::io::Write`]: ../std/io/trait.Write.html +/// [`std::fmt::Result`]: ../std/fmt/type.Result.html +/// [`io::Result`]: ../std/io/type.Result.html /// /// # Examples /// @@ -396,27 +389,12 @@ macro_rules! write { /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone /// (no additional CARRIAGE RETURN (`\r`/`U+000D`). /// -/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a -/// list of arguments to format. +/// For more information, see [`write!`]. For information on the format string syntax, see +/// [`std::fmt`]. /// -/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] -/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of -/// these two traits. +/// [`write!`]: macro.write.html +/// [`std::fmt`]: ../std/fmt/index.html /// -/// Passed arguments will be formatted according to the specified format string and the resulting -/// string will be passed to the writer, along with the appended newline. -/// -/// See [`std::fmt`][fmt] for more information on format syntax. -/// -/// `write!` returns whatever the 'write_fmt' method returns. -/// -/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] -/// -/// [fmt]: ../std/fmt/index.html -/// [fmt_write]: ../std/fmt/trait.Write.html -/// [io_write]: ../std/io/trait.Write.html -/// [fmt_result]: ../std/fmt/type.Result.html -/// [io_result]: ../std/io/type.Result.html /// /// # Examples /// From 41e04985867e04b2be7b7fbd90864e5d9b3a276f Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:46:41 -0400 Subject: [PATCH 191/905] Modify CharIndices' description --- src/libcore/str/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4556d41dd0a5..4720c965c57c 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -553,7 +553,15 @@ impl<'a> Chars<'a> { } } -/// Iterator for a string's characters and their byte offsets. +/// An iterator over the [`char`]s of a string slice, and their positions. +/// +/// [`char`]: ../../std/primitive.char.html +/// +/// This struct is created by the [`char_indices()`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char_indices()`]: ../../std/primitive.str.html#method.char_indices +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CharIndices<'a> { From 17b4884d3c3d88af7f43d5fca32fd8f48d75669b Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 15:51:49 -0400 Subject: [PATCH 192/905] Modify Chars' description --- src/libcore/str/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4720c965c57c..11d52e3c15bc 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -369,11 +369,15 @@ impl fmt::Display for Utf8Error { Section: Iterators */ -/// Iterator for the char (representing *Unicode Scalar Values*) of a string. +/// An iterator over the [`char`]s of a string slice. /// -/// Created with the method [`chars`]. +/// [`char`]: ../../std/primitive.char.html /// -/// [`chars`]: ../../std/primitive.str.html#method.chars +/// This struct is created by the [`chars()`] method on [`str`]. +/// See its documentation for more. +/// +/// [`chars()`]: ../../std/primitive.str.html#method.chars +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { From 5d14ccbc96923607f6ab00810817885ee0939486 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 16:35:19 -0400 Subject: [PATCH 193/905] Modify EncodeUtf16's description --- src/libcollections/str.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 219e818f7d73..aee6861a09f4 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -133,9 +133,15 @@ impl> SliceConcatExt for [S] { } } -/// External iterator for a string's UTF-16 code units. +/// An iterator of [`u16`] over the string encoded as UTF-16. /// -/// For use with the `std::iter` module. +/// [`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> { From a4a7166fd585802e9644ae9b4aa3e63861d11d3e Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 16:36:06 -0400 Subject: [PATCH 194/905] Modify SplitWhitespace's description --- src/libstd_unicode/u_str.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index 3c02ea82d2a1..fd309e822a0e 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -17,8 +17,13 @@ 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. +/// An iterator over sub-slices of the original string slice. +/// +/// 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")] pub struct SplitWhitespace<'a> { inner: Filter bool>, fn(&&str) -> bool>, From c4b11d19b85f970b759f14e6dd864512d8c41f66 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 16:46:16 -0400 Subject: [PATCH 195/905] Revert SplitWhitespace's description Original headline of SplitWhitespace's description is more descriptive as to what it contains and iterates over. --- src/libstd_unicode/u_str.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index fd309e822a0e..d3aa27b436d4 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -17,7 +17,8 @@ use core::char; use core::iter::{Filter, FusedIterator}; use core::str::Split; -/// An iterator over sub-slices of the original string slice. +/// 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. From 3b396217b5b52cf87769263bf0b842c56471b54f Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Thu, 30 Mar 2017 18:33:23 -0400 Subject: [PATCH 196/905] Remove parentheses in method references --- src/libcollections/str.rs | 4 ++-- src/libcore/str/mod.rs | 16 ++++++++-------- src/libstd_unicode/u_str.rs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index aee6861a09f4..36a1f1eb2b7b 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -137,10 +137,10 @@ impl> SliceConcatExt for [S] { /// /// [`u16`]: ../../std/primitive.u16.html /// -/// This struct is created by the [`encode_utf16()`] method on [`str`]. +/// 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 +/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16 /// [`str`]: ../../std/primitive.str.html #[derive(Clone)] #[stable(feature = "encode_utf16", since = "1.8.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 11d52e3c15bc..56f42349b204 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -373,10 +373,10 @@ Section: Iterators /// /// [`char`]: ../../std/primitive.char.html /// -/// This struct is created by the [`chars()`] method on [`str`]. +/// This struct is created by the [`chars`] method on [`str`]. /// See its documentation for more. /// -/// [`chars()`]: ../../std/primitive.str.html#method.chars +/// [`chars`]: ../../std/primitive.str.html#method.chars /// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -561,10 +561,10 @@ impl<'a> Chars<'a> { /// /// [`char`]: ../../std/primitive.char.html /// -/// This struct is created by the [`char_indices()`] method on [`str`]. +/// This struct is created by the [`char_indices`] method on [`str`]. /// See its documentation for more. /// -/// [`char_indices()`]: ../../std/primitive.str.html#method.char_indices +/// [`char_indices`]: ../../std/primitive.str.html#method.char_indices /// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -639,10 +639,10 @@ impl<'a> CharIndices<'a> { /// An iterator over the bytes of a string slice. /// -/// This struct is created by the [`bytes()`] method on [`str`]. +/// This struct is created by the [`bytes`] method on [`str`]. /// See its documentation for more. /// -/// [`bytes()`]: ../../std/primitive.str.html#method.bytes +/// [`bytes`]: ../../std/primitive.str.html#method.bytes /// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] @@ -1176,10 +1176,10 @@ generate_pattern_iterators! { /// An iterator over the lines of a string, as string slices. /// -/// This struct is created with the [`lines()`] method on [`str`]. +/// This struct is created with the [`lines`] method on [`str`]. /// See its documentation for more. /// -/// [`lines()`]: ../../std/primitive.str.html#method.lines +/// [`lines`]: ../../std/primitive.str.html#method.lines /// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index d3aa27b436d4..770b67acd49e 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -20,10 +20,10 @@ 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`]. +/// 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 +/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace /// [`str`]: ../../std/primitive.str.html #[stable(feature = "split_whitespace", since = "1.1.0")] pub struct SplitWhitespace<'a> { From 36b15f0409fae948b3de7dee1d6b2cb995c5784d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Mar 2017 17:29:54 -0600 Subject: [PATCH 197/905] Fix multiple footnotes and improve testing --- src/librustdoc/html/markdown.rs | 52 ++++++++++++------- src/test/rustdoc/check-rule-image-footnote.rs | 13 +++-- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 6c82dab94bcb..e8acabde4081 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,6 +27,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; +use std::collections::HashMap; use std::default::Default; use std::fmt::{self, Write}; use std::str; @@ -135,8 +136,8 @@ macro_rules! event_loop_break { struct ParserWrapper<'a> { parser: Parser<'a>, - footnotes: Vec, - current_footnote_id: u16, + // The key is the footnote reference. The value is the footnote definition and the id. + footnotes: HashMap, } impl<'a> ParserWrapper<'a> { @@ -144,18 +145,18 @@ impl<'a> ParserWrapper<'a> { ParserWrapper { parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | pulldown_cmark::OPTION_ENABLE_FOOTNOTES), - footnotes: Vec::new(), - current_footnote_id: 1, + footnotes: HashMap::new(), } } + pub fn next(&mut self) -> Option> { self.parser.next() } - pub fn get_next_footnote_id(&mut self) -> u16 { - let tmp = self.current_footnote_id; - self.current_footnote_id += 1; - tmp + pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) { + let new_id = self.footnotes.keys().count() + 1; + let key = key.to_owned(); + self.footnotes.entry(key).or_insert((String::new(), new_id as u16)) } } @@ -450,10 +451,11 @@ pub fn render(w: &mut fmt::Formatter, fn footnote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, - mut definition: String, id: &mut Option<&mut String>) { - event_loop_break!(parser, toc_builder, shorter, definition, true, id, + id: &mut Option<&mut String>) { + let mut content = String::new(); + event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::FootnoteDefinition(_))); - buffer.push_str(&definition); + buffer.push_str(&content); } fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, @@ -507,17 +509,24 @@ pub fn render(w: &mut fmt::Formatter, } Event::Start(Tag::FootnoteDefinition(ref def)) => { let mut content = String::new(); - footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(), - id); - let cur_len = parser.footnotes.len() + 1; - parser.footnotes.push(format!("
  • {}↩
  • ", - cur_len, content)); + let def = def.as_ref(); + footnote(parser, &mut content, toc_builder, shorter, id); + let entry = parser.get_entry(def); + let cur_id = (*entry).1; + (*entry).0.push_str(&format!("
  • {} β†©

  • ", + cur_id, + if content.ends_with("

    ") { + &content[..content.len() - 4] + } else { + &content + })); } - Event::FootnoteReference(_) => { + Event::FootnoteReference(ref reference) => { + let entry = parser.get_entry(reference.as_ref()); buffer.push_str(&format!("{0}\ ", - parser.get_next_footnote_id())); + (*entry).1)); } Event::Html(h) | Event::InlineHtml(h) => { buffer.push_str(&*h); @@ -545,7 +554,10 @@ pub fn render(w: &mut fmt::Formatter, } if !parser.footnotes.is_empty() { buffer.push_str(&format!("

      {}
    ", - parser.footnotes.join(""))); + parser.footnotes.values() + .map(|&(ref s, _)| s.as_str()) + .collect::>() + .join(""))); } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs index 629e1a64e6fd..4d3bea20ba89 100644 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -10,11 +10,10 @@ #![crate_name = "foo"] +// ignore-tidy-linelength + // @has foo/fn.f.html -// @has - '

    hard break: after hard break


    ' -// @has - 'Rust' -// @has - '
  • ' -// @has - '1' +// @has - '

    markdown test

    this is a link.

    hard break: after hard break


    a footnote1.

    another footnote2.

    Rust


    1. Thing β†©

    2. Another Thing β†©

    ' /// markdown test /// /// this is a [link]. @@ -28,8 +27,14 @@ /// /// a footnote[^footnote]. /// +/// another footnote[^footnotebis]. +/// /// [^footnote]: Thing /// +/// +/// [^footnotebis]: Another Thing +/// +/// /// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) #[deprecated(note = "Struct")] pub fn f() {} From 78c3a49044d2f93a008f5e8040a27445c8d2f58c Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Thu, 23 Mar 2017 18:03:39 -0700 Subject: [PATCH 198/905] Emit linker hints for all library kinds. --- src/librustc_trans/back/link.rs | 31 ++------ src/librustc_trans/back/linker.rs | 127 +++++++++++++++--------------- 2 files changed, 68 insertions(+), 90 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 6d17b2f0eeda..12a1ffa27672 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -734,9 +734,10 @@ fn link_natively(sess: &Session, } { - let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); + let mut linker = trans.linker_info.to_linker(cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, objects, out_filename, outputs, trans); + cmd = linker.finalize(); } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -1021,38 +1022,18 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { } }); - let pair = sess.cstore.used_libraries().into_iter().filter(|l| { + let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| { relevant_lib(sess, l) - }).partition(|lib| { - lib.kind == NativeLibraryKind::NativeStatic }); - let (staticlibs, others): (Vec<_>, Vec<_>) = pair; - - // 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. - cmd.hint_static(); let search_path = archive_search_paths(sess); - for l in staticlibs { - // 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. - cmd.link_whole_staticlib(&l.name.as_str(), &search_path); - } - - cmd.hint_dynamic(); - - for lib in others { + 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 => bug!(), + NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(), + &search_path) } } } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 80801e8161cd..a178d17a7c2d 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> LinkerInfo { } pub fn to_linker(&'a self, - cmd: &'a mut Command, + cmd: Command, sess: &'a Session) -> Box { if sess.target.target.options.is_like_msvc { Box::new(MsvcLinker { @@ -61,7 +61,8 @@ impl<'a, 'tcx> LinkerInfo { Box::new(GnuLinker { cmd: cmd, sess: sess, - info: self + info: self, + hinted_static: false, }) as Box } } @@ -93,30 +94,49 @@ pub trait Linker { fn no_default_libraries(&mut self); fn build_dylib(&mut self, out_filename: &Path); fn args(&mut self, args: &[String]); - fn hint_static(&mut self); - fn hint_dynamic(&mut self); - fn whole_archives(&mut self); - fn no_whole_archives(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); fn subsystem(&mut self, subsystem: &str); + // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). + fn finalize(&mut self) -> Command; } pub struct GnuLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, - info: &'a LinkerInfo + info: &'a LinkerInfo, + hinted_static: bool, // Keeps track of the current hinting mode. } impl<'a> GnuLinker<'a> { 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.cmd.arg("-Wl,-Bstatic"); + self.hinted_static = true; + } + } + + fn hint_dynamic(&mut self) { + if !self.takes_hints() { return } + if self.hinted_static { + self.cmd.arg("-Wl,-Bdynamic"); + self.hinted_static = false; + } + } } impl<'a> Linker for GnuLinker<'a> { - 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 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); } @@ -125,14 +145,23 @@ impl<'a> Linker for GnuLinker<'a> { 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.cmd.arg("-Wl,--whole-archive") @@ -148,6 +177,7 @@ impl<'a> Linker for GnuLinker<'a> { } 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("-Wl,-force_load,"); v.push(lib); @@ -228,26 +258,6 @@ impl<'a> Linker for GnuLinker<'a> { } } - fn whole_archives(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,--whole-archive"); - } - - fn no_whole_archives(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,--no-whole-archive"); - } - - fn hint_static(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,-Bstatic"); - } - - fn hint_dynamic(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,-Bdynamic"); - } - 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. @@ -311,10 +321,17 @@ impl<'a> Linker for GnuLinker<'a> { fn subsystem(&mut self, subsystem: &str) { self.cmd.arg(&format!("-Wl,--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 + } } pub struct MsvcLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, info: &'a LinkerInfo } @@ -416,22 +433,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/DEBUG"); } - fn whole_archives(&mut self) { - // hints not supported? - } - fn no_whole_archives(&mut self) { - // hints not supported? - } - - // On windows static libraries are of the form `foo.lib` and dynamic - // libraries are not linked against directly, but rather through their - // import libraries also called `foo.lib`. As a result there's no - // possibility for a native library to appear both dynamically and - // statically in the same folder so we don't have to worry about hints like - // we do on Unix platforms. - fn hint_static(&mut self) {} - fn hint_dynamic(&mut self) {} - // 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 @@ -492,10 +493,16 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/ENTRY:mainCRTStartup"); } } + + fn finalize(&mut self) -> Command { + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } } pub struct EmLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, info: &'a LinkerInfo } @@ -591,22 +598,6 @@ impl<'a> Linker for EmLinker<'a> { bug!("building dynamic library is unsupported on Emscripten") } - fn whole_archives(&mut self) { - // noop - } - - fn no_whole_archives(&mut self) { - // noop - } - - fn hint_static(&mut self) { - // noop - } - - fn hint_dynamic(&mut self) { - // noop - } - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { let symbols = &self.info.exports[&crate_type]; @@ -640,6 +631,12 @@ impl<'a> Linker for EmLinker<'a> { 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 + } } fn exported_symbols(scx: &SharedCrateContext, From 7c2fc62a47a9e7e6c71492d5b3752ab78cf0af0d Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 11:01:45 -0700 Subject: [PATCH 199/905] libgcc_eh may depend on libpthread. Make sure we link to the static libpthread, so that compiled Rust binaries do not depend on winpthread1.dll. --- src/libunwind/build.rs | 3 ++- src/libunwind/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index ed3d5212bf25..9b8099d55a02 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -35,7 +35,8 @@ fn main() { } else if target.contains("dragonfly") { println!("cargo:rustc-link-lib=gcc_pic"); } else if target.contains("windows-gnu") { - println!("cargo:rustc-link-lib=gcc_eh"); + println!("cargo:rustc-link-lib=static-nobundle=gcc_eh"); + println!("cargo:rustc-link-lib=static-nobundle=pthread"); } else if target.contains("fuchsia") { println!("cargo:rustc-link-lib=unwind"); } diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 7fa2ce650fd6..d4d52322adab 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -17,6 +17,7 @@ #![feature(cfg_target_vendor)] #![feature(staged_api)] #![feature(unwind_attributes)] +#![feature(static_nobundle)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] From 3b1ba01095aaf37e3f3edf251332e0682bd98c8a Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 10:58:18 -0700 Subject: [PATCH 200/905] Fix stage0->stage1 build when using "pthreads" mingw compiler. --- src/bootstrap/bootstrap.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5bc6127a1e7..9f9d3471640f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -163,12 +163,13 @@ class RustBuild(object): if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) + channel = self.stage0_rustc_channel() + if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): self.print_what_it_means_to_bootstrap() if os.path.exists(self.bin_root()): shutil.rmtree(self.bin_root()) - channel = self.stage0_rustc_channel() filename = "rust-std-{}-{}.tar.gz".format(channel, self.build) url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() tarball = os.path.join(rustc_cache, filename) @@ -189,6 +190,14 @@ class RustBuild(object): with open(self.rustc_stamp(), 'w') as f: f.write(self.stage0_rustc_date()) + if "pc-windows-gnu" in self.build: + filename = "rust-mingw-{}-{}.tar.gz".format(channel, self.build) + url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), match="rust-mingw", verbose=self.verbose) + if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() From 0f87203e2e6c79677388443fba76c3f6895f7674 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 10:59:27 -0700 Subject: [PATCH 201/905] Make sure that -lole32 ends up *after* LLVM libs on the linker command line. --- src/librustc_llvm/build.rs | 6 ++++++ src/librustc_llvm/ffi.rs | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 2b945e0a3afa..7d5887e699fd 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -259,4 +259,10 @@ fn main() { println!("cargo:rustc-link-lib={}", stdcppname); } } + + // LLVM requires symbols from this library, but apparently they're not printeds + // during llvm-config? + if target.contains("windows") { + println!("cargo:rustc-link-lib=ole32"); + } } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 26c7a9166e68..32c9183ece99 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1662,10 +1662,3 @@ extern "C" { pub fn LLVMRustUnsetComdat(V: ValueRef); pub fn LLVMRustSetModulePIELevel(M: ModuleRef); } - - -// LLVM requires symbols from this library, but apparently they're not printed -// during llvm-config? -#[cfg(windows)] -#[link(name = "ole32")] -extern "C" {} From ad3f6e056cdae847c3784ece2ebd8b52baa130e2 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 24 Mar 2017 15:10:52 -0700 Subject: [PATCH 202/905] Include libpthread into mingw package. --- src/etc/make-win-dist.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py index eda5f8540857..394ff97d8453 100644 --- a/src/etc/make-win-dist.py +++ b/src/etc/make-win-dist.py @@ -51,7 +51,7 @@ def make_win_dist(rust_root, plat_root, target_triple): target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe"] - rustc_dlls = ["libstdc++-6.dll"] + rustc_dlls = ["libstdc++-6.dll", "libwinpthread-1.dll"] if target_triple.startswith("i686-"): rustc_dlls.append("libgcc_s_dw2-1.dll") else: @@ -67,6 +67,7 @@ def make_win_dist(rust_root, plat_root, target_triple): "libstdc++.a", "libiconv.a", "libmoldname.a", + "libpthread.a", # Windows import libs "libadvapi32.a", "libbcrypt.a", From 9a50874dd46313203d137847427da0036bd11fd4 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Thu, 30 Mar 2017 21:54:10 -0400 Subject: [PATCH 203/905] tweak links --- src/libstd/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ab1167e20b1d..b5a4cabafdce 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -97,12 +97,12 @@ //! # Contributing changes to the documentation //! //! Check out the rust contribution guidelines [here](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). -//! The source for this documentation can be found on [Github](https://github.com/rust-lang/rust/tree/master/src/libstd). +//! The source for this documentation can be found on [Github](https://github.com/rust-lang). //! To contribute changes, make sure you read the guidelines first, then submit //! pull-requests for your suggested changes. //! //! Contributions are appreciated! If you see a part of the docs that can be -//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust. +//! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs. //! //! # A Tour of The Rust Standard Library //! From e1b0027b51d8c8b7558513565c2baa45f1b1b984 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 20:49:06 -0600 Subject: [PATCH 204/905] Refer to a subcommand as a subcommand. For some reason 'command' and 'subcommand' were intermixed to mean the same thing. Lets just call it the one thing that it is. --- src/bootstrap/flags.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index b55f3d710ca7..ea0fc97e22a7 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -90,12 +90,11 @@ impl Flags { opts.optflag("h", "help", "print this help message"); let usage = |n, opts: &Options| -> ! { - let command = args.get(0).map(|s| &**s); - let brief = format!("Usage: x.py {} [options] [...]", - command.unwrap_or("")); + let subcommand = args.get(0).map(|s| &**s); + let brief = format!("Usage: x.py [options] [...]"); println!("{}", opts.usage(&brief)); - match command { + match subcommand { Some("build") => { println!("\ Arguments: @@ -156,13 +155,13 @@ Arguments: _ => {} } - if let Some(command) = command { - if command == "build" || - command == "dist" || - command == "doc" || - command == "test" || - command == "bench" || - command == "clean" { + if let Some(subcommand) = subcommand { + if subcommand == "build" || + subcommand == "dist" || + subcommand == "doc" || + subcommand == "test" || + subcommand == "bench" || + subcommand == "clean" { println!("Available invocations:"); if args.iter().any(|a| a == "-v") { let flags = Flags::parse(&["build".to_string()]); @@ -170,10 +169,10 @@ Arguments: config.build = flags.build.clone(); let mut build = Build::new(flags, config); metadata::build(&mut build); - step::build_rules(&build).print_help(command); + step::build_rules(&build).print_help(subcommand); } else { println!(" ... elided, run `./x.py {} -h -v` to see", - command); + subcommand); } println!(""); @@ -189,13 +188,13 @@ Subcommands: clean Clean out build directories dist Build and/or install distribution artifacts -To learn more about a subcommand, run `./x.py -h` +To learn more about a subcommand, run `./x.py -h` "); process::exit(n); }; if args.len() == 0 { - println!("a command must be passed"); + println!("a subcommand must be passed"); usage(1, &opts); } let parse = |opts: &Options| { @@ -258,7 +257,7 @@ To learn more about a subcommand, run `./x.py -h` } "--help" => usage(0, &opts), cmd => { - println!("unknown command: {}", cmd); + println!("unknown subcommand: {}", cmd); usage(1, &opts); } }; From 8ad5c95e521f90897a6bd611956d476fcc51c042 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 20:58:07 -0600 Subject: [PATCH 205/905] When dealing with the list of all possible subcommands, deal with them in the same order to ease comparing the sections of code in order. I chose the order that appears in the help text, because that is most likely to have been ordered with specific reasoning. --- src/bootstrap/flags.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ea0fc97e22a7..556a362a8749 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -157,11 +157,11 @@ Arguments: if let Some(subcommand) = subcommand { if subcommand == "build" || - subcommand == "dist" || - subcommand == "doc" || subcommand == "test" || subcommand == "bench" || - subcommand == "clean" { + subcommand == "doc" || + subcommand == "clean" || + subcommand == "dist" { println!("Available invocations:"); if args.iter().any(|a| a == "-v") { let flags = Flags::parse(&["build".to_string()]); @@ -219,10 +219,6 @@ To learn more about a subcommand, run `./x.py -h` m = parse(&opts); Subcommand::Build { paths: remaining_as_path(&m) } } - "doc" => { - m = parse(&opts); - Subcommand::Doc { paths: remaining_as_path(&m) } - } "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); m = parse(&opts); @@ -239,6 +235,10 @@ To learn more about a subcommand, run `./x.py -h` test_args: m.opt_strs("test-args"), } } + "doc" => { + m = parse(&opts); + Subcommand::Doc { paths: remaining_as_path(&m) } + } "clean" => { m = parse(&opts); if m.free.len() > 0 { From e1c1e09867e489a41170e726fe64281caaca087a Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:12:01 -0600 Subject: [PATCH 206/905] Don't print build statistics if we explicitly asked for the help message. --- src/bootstrap/bootstrap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5bc6127a1e7..73f3b1d1ceba 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -593,14 +593,16 @@ def main(): start_time = time() try: bootstrap() - print("Build completed successfully in %s" % format_build_time(time() - start_time)) + if ('-h' not in sys.argv) and ('--help' not in sys.argv): + print("Build completed successfully in %s" % format_build_time(time() - start_time)) except (SystemExit, KeyboardInterrupt) as e: if hasattr(e, 'code') and isinstance(e.code, int): exit_code = e.code else: exit_code = 1 print(e) - print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) + if ('-h' not in sys.argv) and ('--help' not in sys.argv): + print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) sys.exit(exit_code) if __name__ == '__main__': From 5a6ebdfcda149fdf3093003bceacbb2e0a1682ab Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Thu, 30 Mar 2017 23:27:09 -0700 Subject: [PATCH 207/905] Add links to std::sync::mpsc docs #29377 --- src/libstd/sync/mpsc/mod.rs | 40 +++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 71dd94161c03..288a589e589b 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -13,40 +13,50 @@ //! This module provides message-based communication over channels, concretely //! defined among three types: //! -//! * `Sender` -//! * `SyncSender` -//! * `Receiver` +//! * [`Sender`] +//! * [`SyncSender`] +//! * [`Receiver`] //! -//! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both +//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both //! senders are clone-able (multi-producer) such that many threads can send //! simultaneously to one receiver (single-consumer). //! //! These channels come in two flavors: //! -//! 1. An asynchronous, infinitely buffered channel. The `channel()` function +//! 1. An asynchronous, infinitely buffered channel. The [`channel()`] function //! will return a `(Sender, Receiver)` tuple where all sends will be //! **asynchronous** (they never block). The channel conceptually has an //! infinite buffer. //! -//! 2. A synchronous, bounded channel. The `sync_channel()` function will return -//! a `(SyncSender, Receiver)` tuple where the storage for pending messages -//! is a pre-allocated buffer of a fixed size. All sends will be +//! 2. A synchronous, bounded channel. The [`sync_channel()`] function will +//! return a `(SyncSender, Receiver)` tuple where the storage for pending +//! messages is a pre-allocated buffer of a fixed size. All sends will be //! **synchronous** by blocking until there is buffer space available. Note -//! that a bound of 0 is allowed, causing the channel to become a -//! "rendezvous" channel where each sender atomically hands off a message to -//! a receiver. +//! that a bound of 0 is allowed, causing the channel to become a "rendezvous" +//! channel where each sender atomically hands off a message to a receiver. +//! +//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html +//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html +//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +//! [`channel()`]: ../../../std/sync/mpsc/fn.channel.html +//! [`sync_channel()`]: ../../../std/sync/mpsc/fn.sync_channel.html //! //! ## Disconnection //! -//! The send and receive operations on channels will all return a `Result` +//! The send and receive operations on channels will all return a [`Result`] //! indicating whether the operation succeeded or not. An unsuccessful operation //! is normally indicative of the other half of a channel having "hung up" by //! being dropped in its corresponding thread. //! //! Once half of a channel has been deallocated, most operations can no longer -//! continue to make progress, so `Err` will be returned. Many applications will -//! continue to `unwrap()` the results returned from this module, instigating a -//! propagation of failure among threads if one unexpectedly dies. +//! continue to make progress, so [`Err`] will be returned. Many applications +//! will continue to [`unwrap()`] the results returned from this module, +//! instigating a propagation of failure among threads if one unexpectedly dies. +//! +//! [`Result`]: ../../../std/result/enum.Result.html +//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err +//! [`unwrap()`]: ../../../std/result/enum.Result.html#method.unwrap //! //! # Examples //! From 0e2d3d41bb42abe1c40585d2ed06aea2840e664f Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 31 Mar 2017 16:59:01 +0200 Subject: [PATCH 208/905] Test sort algorithms using a random cmp function --- src/libcollectionstest/slice.rs | 16 +++++++++++++++- src/libcoretest/slice.rs | 12 ++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 00d4dbe9c045..c3e5304fb2b3 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -383,9 +383,11 @@ fn test_reverse() { #[test] fn test_sort() { + let mut rng = thread_rng(); + for len in (2..25).chain(500..510) { for _ in 0..100 { - let mut v: Vec<_> = thread_rng().gen_iter::().take(len).collect(); + let mut v: Vec<_> = rng.gen_iter::().take(len).collect(); let mut v1 = v.clone(); v.sort(); @@ -399,6 +401,18 @@ fn test_sort() { } } + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + let mut v = [0; 500]; + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + // Should not panic. [0i32; 0].sort(); [(); 10].sort(); diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index 89bd3be08519..ec38345030fa 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::cmp::Ordering::{Equal, Greater, Less}; use core::slice::heapsort; use core::result::Result::{Ok, Err}; use rand::{Rng, XorShiftRng}; @@ -268,6 +269,17 @@ fn sort_unstable() { } } + // 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(); From d7b3f053d06799e521fa15732f409595dd46d5fc Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 31 Mar 2017 17:12:47 +0200 Subject: [PATCH 209/905] Improve some docs for VecDeque --- src/libcollections/vec_deque.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index cb92236ec736..c37bf752e86b 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -635,7 +635,7 @@ impl VecDeque { } } - /// Shortens a `VecDeque`, dropping excess elements from the back. + /// Shortens the `VecDeque`, dropping excess elements from the back. /// /// If `len` is greater than the `VecDeque`'s current length, this has no /// effect. @@ -941,7 +941,7 @@ impl VecDeque { a.contains(x) || b.contains(x) } - /// Provides a reference to the front element, or `None` if the sequence is + /// Provides a reference to the front element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -966,7 +966,7 @@ impl VecDeque { } /// Provides a mutable reference to the front element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -993,7 +993,7 @@ impl VecDeque { } } - /// Provides a reference to the back element, or `None` if the sequence is + /// Provides a reference to the back element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1018,7 +1018,7 @@ impl VecDeque { } /// Provides a mutable reference to the back element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -1046,7 +1046,7 @@ impl VecDeque { } } - /// Removes the first element and returns it, or `None` if the sequence is + /// Removes the first element and returns it, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1073,7 +1073,7 @@ impl VecDeque { } } - /// Inserts an element first in the sequence. + /// Prepends an element to the front of the `VecDeque`. /// /// # Examples /// @@ -1096,7 +1096,7 @@ impl VecDeque { } } - /// Appends an element to the back of a buffer + /// Appends an element to the back of the `VecDeque`. /// /// # Examples /// @@ -1117,7 +1117,7 @@ impl VecDeque { unsafe { self.buffer_write(head, value) } } - /// Removes the last element from a buffer and returns it, or `None` if + /// Removes the last element from the `VecDeque` and returns it, or `None` if /// it is empty. /// /// # Examples From eef2a9598b9a149d45d440efe0580604b5726527 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 19 Mar 2017 10:45:05 -0400 Subject: [PATCH 210/905] Sync all unstable features with Unstable Book; add tidy lint. Add a tidy lint that checks for... * Unstable Book sections with no corresponding SUMMARY.md links * unstable features that don't have Unstable Book sections * Unstable Book sections that don't have corresponding unstable features --- src/Cargo.lock | 3 + src/doc/unstable-book/src/SUMMARY.md | 4 +- src/doc/unstable-book/src/pub-restricted.md | 7 - src/doc/unstable-book/src/reverse-cmp-key.md | 7 + src/doc/unstable-book/src/rustdoc.md | 7 - .../unstable-book/src/str-checked-slicing.md | 7 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/features.rs | 150 ++++++++++-------- src/tools/tidy/src/main.rs | 4 + src/tools/tidy/src/unstable_book.rs | 138 ++++++++++++++++ 10 files changed, 243 insertions(+), 85 deletions(-) delete mode 100644 src/doc/unstable-book/src/pub-restricted.md create mode 100644 src/doc/unstable-book/src/reverse-cmp-key.md delete mode 100644 src/doc/unstable-book/src/rustdoc.md create mode 100644 src/doc/unstable-book/src/str-checked-slicing.md create mode 100644 src/tools/tidy/src/unstable_book.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index a9021dc34e20..1fa256197ce5 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -926,6 +926,9 @@ dependencies = [ [[package]] name = "tidy" version = "0.1.0" +dependencies = [ + "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "toml" diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index fe491d7f9018..292f5a1ec816 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -146,7 +146,6 @@ - [proc_macro](proc-macro.md) - [proc_macro_internals](proc-macro-internals.md) - [process_try_wait](process-try-wait.md) -- [pub_restricted](pub-restricted.md) - [question_mark_carrier](question-mark-carrier.md) - [quote](quote.md) - [rand](rand.md) @@ -156,11 +155,11 @@ - [relaxed_adts](relaxed-adts.md) - [repr_simd](repr-simd.md) - [retain_hash_collection](retain-hash-collection.md) +- [reverse_cmp_key](reverse-cmp-key.md) - [rt](rt.md) - [rustc_attrs](rustc-attrs.md) - [rustc_diagnostic_macros](rustc-diagnostic-macros.md) - [rustc_private](rustc-private.md) -- [rustdoc](rustdoc.md) - [rvalue_static_promotion](rvalue-static-promotion.md) - [sanitizer_runtime](sanitizer-runtime.md) - [sanitizer_runtime_lib](sanitizer-runtime-lib.md) @@ -181,6 +180,7 @@ - [step_by](step-by.md) - [step_trait](step-trait.md) - [stmt_expr_attributes](stmt-expr-attributes.md) +- [str_checked_slicing](str-checked-slicing.md) - [str_escape](str-escape.md) - [str_internals](str-internals.md) - [struct_field_attributes](struct-field-attributes.md) diff --git a/src/doc/unstable-book/src/pub-restricted.md b/src/doc/unstable-book/src/pub-restricted.md deleted file mode 100644 index 6b1e88b86030..000000000000 --- a/src/doc/unstable-book/src/pub-restricted.md +++ /dev/null @@ -1,7 +0,0 @@ -# `pub_restricted` - -The tracking issue for this feature is: [#32409] - -[#38356]: https://github.com/rust-lang/rust/issues/32409 - ------------------------- diff --git a/src/doc/unstable-book/src/reverse-cmp-key.md b/src/doc/unstable-book/src/reverse-cmp-key.md new file mode 100644 index 000000000000..a1a851d6ed63 --- /dev/null +++ b/src/doc/unstable-book/src/reverse-cmp-key.md @@ -0,0 +1,7 @@ +# `reverse_cmp_key` + +The tracking issue for this feature is: [#40893] + +[#40893]: https://github.com/rust-lang/rust/issues/40893 + +------------------------ diff --git a/src/doc/unstable-book/src/rustdoc.md b/src/doc/unstable-book/src/rustdoc.md deleted file mode 100644 index c7491ab034bf..000000000000 --- a/src/doc/unstable-book/src/rustdoc.md +++ /dev/null @@ -1,7 +0,0 @@ -# `rustdoc` - -The tracking issue for this feature is: [#27812] - -[#27812]: https://github.com/rust-lang/rust/issues/27812 - ------------------------- diff --git a/src/doc/unstable-book/src/str-checked-slicing.md b/src/doc/unstable-book/src/str-checked-slicing.md new file mode 100644 index 000000000000..d390139a6bef --- /dev/null +++ b/src/doc/unstable-book/src/str-checked-slicing.md @@ -0,0 +1,7 @@ +# `str_checked_slicing` + +The tracking issue for this feature is: [#39932] + +[#39932]: https://github.com/rust-lang/rust/issues/39932 + +------------------------ diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index e900bd47fb7b..371922c9e6bb 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["Alex Crichton "] [dependencies] +regex = "0.2" \ No newline at end of file diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 9b323c95fc3c..e1fdc19c27d2 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -24,8 +24,8 @@ use std::fs::File; use std::io::prelude::*; use std::path::Path; -#[derive(PartialEq)] -enum Status { +#[derive(Debug, PartialEq)] +pub enum Status { Stable, Removed, Unstable, @@ -42,78 +42,21 @@ impl fmt::Display for Status { } } -struct Feature { - level: Status, - since: String, - has_gate_test: bool, +#[derive(Debug)] +pub struct Feature { + pub level: Status, + pub since: String, + pub has_gate_test: bool, } pub fn check(path: &Path, bad: &mut bool) { - let mut features = collect_lang_features(&path.join("libsyntax/feature_gate.rs")); + let mut features = collect_lang_features(path); assert!(!features.is_empty()); - let mut lib_features = HashMap::::new(); + + let lib_features = collect_lib_features(path, bad, &features); + assert!(!lib_features.is_empty()); let mut contents = String::new(); - super::walk(path, - &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), - &mut |file| { - let filename = file.file_name().unwrap().to_string_lossy(); - if !filename.ends_with(".rs") || filename == "features.rs" || - filename == "diagnostic_list.rs" { - return; - } - - contents.truncate(0); - t!(t!(File::open(&file), &file).read_to_string(&mut contents)); - - for (i, line) in contents.lines().enumerate() { - let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; - }; - let level = if line.contains("[unstable(") { - Status::Unstable - } else if line.contains("[stable(") { - Status::Stable - } else { - continue; - }; - let feature_name = match find_attr_val(line, "feature") { - Some(name) => name, - None => { - err("malformed stability attribute"); - continue; - } - }; - let since = match find_attr_val(line, "since") { - Some(name) => name, - None if level == Status::Stable => { - err("malformed stability attribute"); - continue; - } - None => "None", - }; - - if features.contains_key(feature_name) { - err("duplicating a lang feature"); - } - if let Some(ref s) = lib_features.get(feature_name) { - if s.level != level { - err("different stability level than before"); - } - if s.since != since { - err("different `since` than before"); - } - continue; - } - lib_features.insert(feature_name.to_owned(), - Feature { - level: level, - since: since.to_owned(), - has_gate_test: false, - }); - } - }); super::walk_many(&[&path.join("test/compile-fail"), &path.join("test/compile-fail-fulldeps"), @@ -233,8 +176,9 @@ fn test_filen_gate(filen_underscore: &str, return false; } -fn collect_lang_features(path: &Path) -> HashMap { +pub fn collect_lang_features(base_src_path: &Path) -> HashMap { let mut contents = String::new(); + let path = base_src_path.join("libsyntax/feature_gate.rs"); t!(t!(File::open(path)).read_to_string(&mut contents)); contents.lines() @@ -257,3 +201,71 @@ fn collect_lang_features(path: &Path) -> HashMap { }) .collect() } + +pub fn collect_lib_features(base_src_path: &Path, + bad: &mut bool, + features: &HashMap) -> HashMap { + let mut lib_features = HashMap::::new(); + let mut contents = String::new(); + super::walk(base_src_path, + &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), + &mut |file| { + let filename = file.file_name().unwrap().to_string_lossy(); + if !filename.ends_with(".rs") || filename == "features.rs" || + filename == "diagnostic_list.rs" { + return; + } + + contents.truncate(0); + t!(t!(File::open(&file), &file).read_to_string(&mut contents)); + + for (i, line) in contents.lines().enumerate() { + let mut err = |msg: &str| { + println!("{}:{}: {}", file.display(), i + 1, msg); + *bad = true; + }; + let level = if line.contains("[unstable(") { + Status::Unstable + } else if line.contains("[stable(") { + Status::Stable + } else { + continue; + }; + let feature_name = match find_attr_val(line, "feature") { + Some(name) => name, + None => { + err("malformed stability attribute"); + continue; + } + }; + let since = match find_attr_val(line, "since") { + Some(name) => name, + None if level == Status::Stable => { + err("malformed stability attribute"); + continue; + } + None => "None", + }; + + if features.contains_key(feature_name) { + err("duplicating a lang feature"); + } + if let Some(ref s) = lib_features.get(feature_name) { + if s.level != level { + err("different stability level than before"); + } + if s.since != since { + err("different `since` than before"); + } + continue; + } + lib_features.insert(feature_name.to_owned(), + Feature { + level: level, + since: since.to_owned(), + has_gate_test: false, + }); + } + }); + lib_features +} \ No newline at end of file diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 2af891b5b856..501e35e03e8a 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -14,6 +14,8 @@ //! etc. This is run by default on `make check` and as part of the auto //! builders. +extern crate regex; + use std::fs; use std::path::{PathBuf, Path}; use std::env; @@ -37,6 +39,7 @@ mod features; mod cargo; mod pal; mod deps; +mod unstable_book; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -51,6 +54,7 @@ fn main() { cargo::check(&path, &mut bad); features::check(&path, &mut bad); pal::check(&path, &mut bad); + unstable_book::check(&path, &mut bad); if !args.iter().any(|s| *s == "--no-vendor") { deps::check(&path, &mut bad); } diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs new file mode 100644 index 000000000000..c10e31077944 --- /dev/null +++ b/src/tools/tidy/src/unstable_book.rs @@ -0,0 +1,138 @@ +// 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::HashSet; +use std::fs; +use std::io::{self, BufRead, Write}; +use std::path; +use features::{collect_lang_features, collect_lib_features, Status}; + +const PATH_STR: &'static str = "doc/unstable-book/src"; + +const SUMMARY_FILE_NAME: &'static str = "SUMMARY.md"; + +static EXCLUDE: &'static [&'static str; 2] = &[SUMMARY_FILE_NAME, "the-unstable-book.md"]; + +/// Build the path to the Unstable Book source directory from the Rust 'src' directory +fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf { + base_src_path.join(PATH_STR) +} + +/// Build the path to the Unstable Book SUMMARY file from the Rust 'src' directory +fn unstable_book_summary_path(base_src_path: &path::Path) -> path::PathBuf { + unstable_book_path(base_src_path).join(SUMMARY_FILE_NAME) +} + +/// Open the Unstable Book SUMMARY file +fn open_unstable_book_summary_file(base_src_path: &path::Path) -> fs::File { + fs::File::open(unstable_book_summary_path(base_src_path)) + .expect("could not open Unstable Book SUMMARY.md") +} + +/// Test to determine if DirEntry is a file +fn dir_entry_is_file(dir_entry: &fs::DirEntry) -> bool { + dir_entry.file_type().expect("could not determine file type of directory entry").is_file() +} + +/// Retrieve names of all lang-related unstable features +fn collect_unstable_lang_feature_names(base_src_path: &path::Path) -> HashSet { + collect_lang_features(base_src_path) + .into_iter() + .filter(|&(_, ref f)| f.level == Status::Unstable) + .map(|(ref name, _)| name.to_owned()) + .collect() +} + +/// Retrieve names of all lib-related unstable features +fn collect_unstable_lib_feature_names(base_src_path: &path::Path) -> HashSet { + let mut bad = true; + let lang_features = collect_lang_features(base_src_path); + collect_lib_features(base_src_path, &mut bad, &lang_features) + .into_iter() + .filter(|&(_, ref f)| f.level == Status::Unstable) + .map(|(ref name, _)| name.to_owned()) + .collect() +} + +/// Retrieve names of all unstable features +fn collect_unstable_feature_names(base_src_path: &path::Path) -> HashSet { + collect_unstable_lib_feature_names(base_src_path) + .union(&collect_unstable_lang_feature_names(base_src_path)) + .map(|n| n.to_owned()) + .collect::>() +} + +/// Retrieve file names of all sections in the Unstable Book with: +/// +/// * hyphens replaced by underscores +/// * the markdown suffix ('.md') removed +fn collect_unstable_book_section_file_names(base_src_path: &path::Path) -> HashSet { + fs::read_dir(unstable_book_path(base_src_path)) + .expect("could not read directory") + .into_iter() + .map(|entry| entry.expect("could not read directory entry")) + .filter(dir_entry_is_file) + .map(|entry| entry.file_name().into_string().unwrap()) + .filter(|n| EXCLUDE.iter().all(|e| n != e)) + .map(|n| n.trim_right_matches(".md").replace('-', "_")) + .collect() +} + +/// Retrieve unstable feature names that are in the Unstable Book SUMMARY file +fn collect_unstable_book_summary_links(base_src_path: &path::Path) -> HashSet { + let summary_link_regex = + ::regex::Regex::new(r"^- \[(\S+)\]\(\S+\.md\)").expect("invalid regex"); + io::BufReader::new(open_unstable_book_summary_file(base_src_path)) + .lines() + .map(|l| l.expect("could not read line from file")) + .filter_map(|line| { + summary_link_regex.captures(&line).map(|c| { + c.get(1) + .unwrap() + .as_str() + .to_owned() + }) + }) + .collect() +} + +pub fn check(path: &path::Path, bad: &mut bool) { + let unstable_feature_names = collect_unstable_feature_names(path); + let unstable_book_section_file_names = collect_unstable_book_section_file_names(path); + let unstable_book_links = collect_unstable_book_summary_links(path); + + // Check for Unstable Book section names with no corresponding SUMMARY.md link + for feature_name in &unstable_book_section_file_names - &unstable_book_links { + *bad = true; + writeln!(io::stderr(), + "The Unstable Book section '{}' needs to have a link in SUMMARY.md", + feature_name) + .expect("could not write to stderr") + } + + // Check for unstable features that don't have Unstable Book sections + for feature_name in &unstable_feature_names - &unstable_book_section_file_names { + *bad = true; + writeln!(io::stderr(), + "Unstable feature '{}' needs to have a section in The Unstable Book", + feature_name) + .expect("could not write to stderr") + } + + // Check for Unstable Book sections that don't have a corresponding unstable feature + for feature_name in &unstable_book_section_file_names - &unstable_feature_names { + *bad = true; + writeln!(io::stderr(), + "The Unstable Book has a section '{}' which doesn't correspond \ + to an unstable feature", + feature_name) + .expect("could not write to stderr") + } +} From 0ba7da344935c553d6c45364e45246729abf6ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 31 Mar 2017 20:09:37 +0200 Subject: [PATCH 211/905] Ignore tests for the personality slot lifetimes on MSVC Exception handling on MSVC targets doesn't use personality slots. --- src/test/codegen/personality_lifetimes.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs index 1d07a2f10408..e0de64b26df4 100644 --- a/src/test/codegen/personality_lifetimes.rs +++ b/src/test/codegen/personality_lifetimes.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-msvc + // compile-flags: -O -C no-prepopulate-passes #![crate_type="lib"] From 51d3cec38794beb644f67e80b1e7718ee14facf0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Mar 2017 11:02:46 -0600 Subject: [PATCH 212/905] Fix hard break issue --- src/librustdoc/html/markdown.rs | 36 ++++++++++++++++++++-- src/librustdoc/passes/unindent_comments.rs | 13 +++++++- src/test/rustdoc/check-hard-break.rs | 19 ++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/check-hard-break.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e8acabde4081..d1f2948bc253 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -116,6 +116,7 @@ macro_rules! event_loop_break { match event { $($end_event)|* => break, Event::Text(ref s) => { + debug!("Text"); inner($id, s); if $escape { $buf.push_str(&format!("{}", Escape(s))); @@ -123,8 +124,11 @@ macro_rules! event_loop_break { $buf.push_str(s); } } - Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { - $buf.push(' '); + Event::SoftBreak => { + debug!("SoftBreak"); + if !$buf.is_empty() { + $buf.push(' '); + } } x => { looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); @@ -165,6 +169,7 @@ pub fn render(w: &mut fmt::Formatter, print_toc: bool, shorter: MarkdownOutputStyle) -> fmt::Result { fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { + debug!("CodeBlock"); let mut origtext = String::new(); while let Some(event) = parser.next() { match event { @@ -244,6 +249,7 @@ pub fn render(w: &mut fmt::Formatter, fn heading(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { + debug!("Heading"); let mut ret = String::new(); let mut id = String::new(); event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), @@ -279,6 +285,7 @@ pub fn render(w: &mut fmt::Formatter, fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("InlineCode"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); buffer.push_str(&format!("{}", @@ -288,6 +295,7 @@ pub fn render(w: &mut fmt::Formatter, fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, title: &str, id: &mut Option<&mut String>) { + debug!("Link"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Link(_, _))); @@ -302,6 +310,7 @@ pub fn render(w: &mut fmt::Formatter, fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, url: &str, mut title: String, id: &mut Option<&mut String>) { + debug!("Image"); event_loop_break!(parser, toc_builder, shorter, title, true, id, Event::End(Tag::Image(_, _))); buffer.push_str(&format!("\"{}\"", url, title)); @@ -310,6 +319,7 @@ pub fn render(w: &mut fmt::Formatter, fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Paragraph"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Paragraph)); @@ -318,6 +328,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableCell"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::TableHead) | @@ -329,6 +340,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_row(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableRow"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -348,6 +360,7 @@ pub fn render(w: &mut fmt::Formatter, fn table_head(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("TableHead"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -367,6 +380,7 @@ pub fn render(w: &mut fmt::Formatter, fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("Table"); let mut content = String::new(); let mut rows = String::new(); while let Some(event) = parser.next() { @@ -392,6 +406,7 @@ pub fn render(w: &mut fmt::Formatter, fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("BlockQuote"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, Event::End(Tag::BlockQuote)); @@ -400,6 +415,7 @@ pub fn render(w: &mut fmt::Formatter, fn list_item(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("ListItem"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -417,6 +433,7 @@ pub fn render(w: &mut fmt::Formatter, fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle) { + debug!("List"); let mut content = String::new(); while let Some(event) = parser.next() { match event { @@ -435,6 +452,7 @@ pub fn render(w: &mut fmt::Formatter, fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Emphasis"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Emphasis)); @@ -443,6 +461,7 @@ pub fn render(w: &mut fmt::Formatter, fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Strong"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Strong)); @@ -452,6 +471,7 @@ pub fn render(w: &mut fmt::Formatter, fn footnote(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("FootnoteDefinition"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::FootnoteDefinition(_))); @@ -460,6 +480,7 @@ pub fn render(w: &mut fmt::Formatter, fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { + debug!("Rule"); let mut content = String::new(); event_loop_break!(parser, toc_builder, shorter, content, true, id, Event::End(Tag::Rule)); @@ -508,6 +529,7 @@ pub fn render(w: &mut fmt::Formatter, rule(parser, buffer, toc_builder, shorter, id); } Event::Start(Tag::FootnoteDefinition(ref def)) => { + debug!("FootnoteDefinition"); let mut content = String::new(); let def = def.as_ref(); footnote(parser, &mut content, toc_builder, shorter, id); @@ -523,12 +545,22 @@ pub fn render(w: &mut fmt::Formatter, })); } Event::FootnoteReference(ref reference) => { + debug!("FootnoteReference"); let entry = parser.get_entry(reference.as_ref()); buffer.push_str(&format!("{0}\ ", (*entry).1)); } + Event::HardBreak => { + debug!("HardBreak"); + if shorter.is_fancy() { + buffer.push_str("
    "); + } else if !buffer.is_empty() { + buffer.push(' '); + } + } Event::Html(h) | Event::InlineHtml(h) => { + debug!("Html/InlineHtml"); buffer.push_str(&*h); } _ => {} diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 4d94c3084785..59fef8d20271 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -82,7 +82,7 @@ fn unindent(s: &str) -> String { }); if !lines.is_empty() { - let mut unindented = vec![ lines[0].trim().to_string() ]; + let mut unindented = vec![ lines[0].trim_left().to_string() ]; unindented.extend_from_slice(&lines[1..].iter().map(|&line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() @@ -160,4 +160,15 @@ mod unindent_tests { let r = unindent(&s); assert_eq!(r, "line1\nline2"); } + + #[test] + fn should_not_trim() { + let s = "\t line1 \n\t line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + + let s = " \tline1 \n \tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + } } diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs new file mode 100644 index 000000000000..4604639c3c8d --- /dev/null +++ b/src/test/rustdoc/check-hard-break.rs @@ -0,0 +1,19 @@ +// 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. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/fn.f.html +// @has - '

    hard break:
    after hard break

    ' +/// hard break: +/// after hard break +pub fn f() {} From 4de4a955052febfbcd28fd156a7585b90b5dd184 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 31 Mar 2017 12:08:31 -0600 Subject: [PATCH 213/905] Add end whitespace ignore flag for tidy --- src/test/rustdoc/check-hard-break.rs | 2 +- src/tools/tidy/src/style.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs index 4604639c3c8d..5c5e3f8136c7 100644 --- a/src/test/rustdoc/check-hard-break.rs +++ b/src/test/rustdoc/check-hard-break.rs @@ -10,7 +10,7 @@ #![crate_name = "foo"] -// ignore-tidy-linelength +// ignore-tidy-end-whitespace // @has foo/fn.f.html // @has - '

    hard break:
    after hard break

    ' diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2233f8c35297..012301299e0c 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -110,6 +110,7 @@ pub fn check(path: &Path, bad: &mut bool) { let skip_cr = contents.contains("ignore-tidy-cr"); let skip_tab = contents.contains("ignore-tidy-tab"); let skip_length = contents.contains("ignore-tidy-linelength"); + let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace"); for (i, line) in contents.split("\n").enumerate() { let mut err = |msg: &str| { println!("{}:{}: {}", file.display(), i + 1, msg); @@ -122,7 +123,7 @@ pub fn check(path: &Path, bad: &mut bool) { if line.contains("\t") && !skip_tab { err("tab character"); } - if line.ends_with(" ") || line.ends_with("\t") { + if !skip_end_whitespace && (line.ends_with(" ") || line.ends_with("\t")) { err("trailing whitespace"); } if line.contains("\r") && !skip_cr { From 30761556749ff4bce889f5b0ec9fd183aaa12f73 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 31 Mar 2017 11:04:25 -0700 Subject: [PATCH 214/905] travis: Compile OSX releases with Xcode 7 Unfortunately what we're using right now, Xcode 8.2, cannot compile LLVM for OSX 10.7. We've done this historically and Gecko would like to maintain this compabitiliby. This commit moves our release builders for OSX to using Xcode 7 which can compile LLVM for 10.7. The builders running tests continue to use Xcode 8.2, however, because the LLDB version with Xcode 7, 350, is blacklisted in running our LLDB tests. To continue running LLDB tests we'll stick with Xcode 8.2. --- .travis.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 148b59e8c64e..f95893cd5e63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,10 @@ matrix: - env: IMAGE=x86_64-gnu-distcheck - env: IMAGE=x86_64-gnu-incremental - # OSX builders + # OSX builders running tests, these run the full test suite. + # + # Note that the compiler is compiled to target 10.8 here because the Xcode + # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - env: > RUST_CHECK_TARGET=check RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin @@ -68,6 +71,12 @@ matrix: osx_image: xcode8.2 install: *osx_install_sccache + # OSX builders producing releases. These do not run the full test suite and + # just produce a bunch of artifacts. + # + # Note that these are running in the `xcode7` image instead of the + # `xcode8.2` image as above. That's because we want to build releases for + # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7. - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended" @@ -75,10 +84,9 @@ matrix: DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 + osx_image: xcode7 install: *osx_install_sccache - env: > RUST_CHECK_TARGET=dist @@ -87,10 +95,9 @@ matrix: DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 + osx_image: xcode7 install: *osx_install_sccache # "alternate" deployments, these are "nightlies" but don't have assertions @@ -105,10 +112,9 @@ matrix: DEPLOY_ALT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 + osx_image: xcode7 install: *osx_install_sccache env: From 113b3b46a77222fe898b0a6678af451f29a7acc4 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Fri, 31 Mar 2017 17:26:55 -0300 Subject: [PATCH 215/905] Use 64 bits emulator to run android tests Also install headless jre instead of the full jre. --- src/ci/docker/arm-android/Dockerfile | 2 +- src/ci/docker/arm-android/start-emulator.sh | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index 4c89ce12531b..04ca6d76c557 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -13,7 +13,7 @@ RUN dpkg --add-architecture i386 && \ cmake \ unzip \ expect \ - openjdk-9-jre \ + openjdk-9-jre-headless \ sudo \ libstdc++6:i386 \ xz-utils \ diff --git a/src/ci/docker/arm-android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh index 24c477d87f1a..4a73637e9ddb 100755 --- a/src/ci/docker/arm-android/start-emulator.sh +++ b/src/ci/docker/arm-android/start-emulator.sh @@ -10,7 +10,9 @@ # except according to those terms. set -ex -ANDROID_EMULATOR_FORCE_32BIT=true \ - nohup nohup emulator @arm-18 -no-window -partition-size 2047 \ - 0<&- &>/dev/null & + +# Setting SHELL to a file instead on a symlink helps android +# emulator identify the system +export SHELL=/bin/bash +nohup nohup emulator @arm-18 -no-window -partition-size 2047 0<&- &>/dev/null & exec "$@" From 2060266c1691f11a3c204ead056fe2e7a8c20e3b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 31 Mar 2017 23:52:35 +0100 Subject: [PATCH 216/905] Don't warn about `char` comparisons in constexprs --- src/librustc_const_eval/eval.rs | 11 +++++++++++ src/test/run-pass/const-err.rs | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c5d577ce571d..54f5cff16ed6 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -490,6 +490,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, _ => span_bug!(e.span, "typeck error"), }) } + (Char(a), Char(b)) => { + Bool(match op.node { + hir::BiEq => a == b, + hir::BiNe => a != b, + hir::BiLt => a < b, + hir::BiLe => a <= b, + hir::BiGe => a >= b, + hir::BiGt => a > b, + _ => span_bug!(e.span, "typeck error"), + }) + } _ => signal!(e, MiscBinaryOp), } diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs index a1c9ff8a21ed..f7f79356a0b9 100644 --- a/src/test/run-pass/const-err.rs +++ b/src/test/run-pass/const-err.rs @@ -13,6 +13,10 @@ #![deny(const_err)] const X: *const u8 = b"" as _; +const Y: bool = 'A' == 'B'; +const Z: char = 'A'; +const W: bool = Z <= 'B'; + fn main() { let _ = ((-1 as i8) << 8 - 1) as f32; From 44d8b236f4da3b17bc4a7ac3d571d67acd3be020 Mon Sep 17 00:00:00 2001 From: projektir Date: Fri, 31 Mar 2017 18:58:32 -0400 Subject: [PATCH 217/905] Updating the description for BarrierWaitResult #29377 --- src/libstd/sync/barrier.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 295a49d6a8e8..a7b01e49d2bb 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -50,12 +50,11 @@ struct BarrierState { generation_id: usize, } -/// A result returned from wait. +/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] +/// have rendezvoused. /// -/// Currently this opaque structure only has one method, [`.is_leader`]. Only -/// one thread will receive a result that will return `true` from this function. -/// -/// [`.is_leader`]: #method.is_leader +/// [`wait`]: struct.Barrier.html#method.wait +/// [`Barrier`]: struct.Barrier.html /// /// # Examples /// From 80bff6b59654cde4c36c7ae77ea06fb254ffe148 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 31 Mar 2017 18:04:42 -0500 Subject: [PATCH 218/905] rustdoc: format where clauses like rust-lang-nursery/fmt-rfcs#38 --- src/librustdoc/html/format.rs | 61 ++++++++++++------------- src/librustdoc/html/render.rs | 62 +++++++++++--------------- src/librustdoc/html/static/rustdoc.css | 13 +----- 3 files changed, 55 insertions(+), 81 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3589cc8fac61..3fb90f407ebc 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -49,14 +49,19 @@ pub struct MutableSpace(pub clean::Mutability); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); -/// Wrapper struct for emitting a where clause from Generics. -pub struct WhereClause<'a>(pub &'a clean::Generics, pub usize); /// Wrapper struct for emitting type parameter bounds. pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); /// Wrapper struct for emitting a comma-separated list of items pub struct CommaSep<'a, T: 'a>(pub &'a [T]); pub struct AbiSpace(pub Abi); +/// Wrapper struct for emitting a where clause from Generics. +pub struct WhereClause<'a>{ + pub gens: &'a clean::Generics, + pub indent: usize, + pub end_newline: bool, +} + pub struct HRef<'a> { pub did: DefId, pub text: &'a str, @@ -167,24 +172,27 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause(gens, pad) = self; + let &WhereClause{ gens, indent, end_newline } = self; if gens.where_predicates.is_empty() { return Ok(()); } let mut clause = String::new(); if f.alternate() { - clause.push_str(" where "); + clause.push_str(" where"); } else { - clause.push_str(" where "); + if end_newline { + clause.push_str("where"); + } else { + clause.push_str("where"); + } } for (i, pred) in gens.where_predicates.iter().enumerate() { - if i > 0 { - if f.alternate() { - clause.push_str(", "); - } else { - clause.push_str(",
    "); - } + if f.alternate() { + clause.push(' '); + } else { + clause.push_str("
    "); } + match pred { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; @@ -213,21 +221,18 @@ impl<'a> fmt::Display for WhereClause<'a> { } } } + + if i < gens.where_predicates.len() - 1 || end_newline { + clause.push(','); + } } if !f.alternate() { clause.push_str("
    "); - let plain = format!("{:#}", self); - if plain.len() + pad > 80 { - // break it onto its own line regardless, but make sure method impls and trait - // blocks keep their fixed padding (2 and 9, respectively) - let padding = if pad > 10 { - repeat(" ").take(8).collect::() - } else { - repeat(" ").take(pad + 6).collect::() - }; - clause = clause.replace("
    ", &format!("
    {}", padding)); - } else { - clause = clause.replace("
    ", " "); + let padding = repeat(" ").take(indent + 4).collect::(); + clause = clause.replace("
    ", &format!("
    {}", padding)); + clause.insert_str(0, &repeat(" ").take(indent).collect::()); + if !end_newline { + clause.insert_str(0, "
    "); } } write!(f, "{}", clause) @@ -838,43 +843,35 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool, use_absolute: bool) -> fmt::Result { - let mut plain = String::new(); - if f.alternate() { write!(f, "impl{:#} ", i.generics)?; } else { write!(f, "impl{} ", i.generics)?; } - plain.push_str(&format!("impl{:#} ", i.generics)); if let Some(ref ty) = i.trait_ { if i.polarity == Some(clean::ImplPolarity::Negative) { write!(f, "!")?; - plain.push_str("!"); } if link_trait { fmt::Display::fmt(ty, f)?; - plain.push_str(&format!("{:#}", ty)); } else { match *ty { clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.params, f)?; - plain.push_str(&format!("{:#}{:#}", last.name, last.params)); } _ => unreachable!(), } } write!(f, " for ")?; - plain.push_str(" for "); } fmt_type(&i.for_, f, use_absolute, true)?; - plain.push_str(&format!("{:#}", i.for_)); - fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?; + fmt::Display::fmt(&WhereClause{ gens: &i.generics, indent: 0, end_newline: true }, f)?; Ok(()) } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c571bcb08e4b..4eb228ce68f4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2012,7 +2012,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), generics = f.generics, - where_clause = WhereClause(&f.generics, 2), + where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true }, decl = Method(&f.decl, indent))?; document(w, cx, it) } @@ -2047,8 +2047,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, it.name.as_ref().unwrap(), t.generics, bounds, - // Where clauses in traits are indented nine spaces, per rustdoc.css - WhereClause(&t.generics, 9))?; + WhereClause { gens: &t.generics, indent: 0, end_newline: true })?; let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); @@ -2087,7 +2086,14 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, for m in &provided { write!(w, " ")?; render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; - write!(w, " {{ ... }}\n")?; + match m.inner { + clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => { + write!(w, ",\n {{ ... }}\n")?; + }, + _ => { + write!(w, " {{ ... }}\n")?; + }, + } } write!(w, "}}")?; } @@ -2327,14 +2333,14 @@ fn render_assoc_item(w: &mut fmt::Formatter, name, *g); let mut indent = prefix.len(); - let where_indent = if parent == ItemType::Trait { + let (where_indent, end_newline) = if parent == ItemType::Trait { indent += 4; - 8 + (4, false) } else if parent == ItemType::Impl { - 2 + (0, true) } else { let prefix = prefix + &format!("{:#}", Method(d, indent)); - prefix.lines().last().unwrap().len() + 1 + (prefix.lines().last().unwrap().len() + 1, true) }; write!(w, "{}{}{}fn {name}\ {generics}{decl}{where_clause}", @@ -2345,7 +2351,11 @@ fn render_assoc_item(w: &mut fmt::Formatter, name = name, generics = *g, decl = Method(d, indent), - where_clause = WhereClause(g, where_indent)) + where_clause = WhereClause { + gens: g, + indent: where_indent, + end_newline: end_newline, + }) } match item.inner { clean::StrippedItem(..) => Ok(()), @@ -2458,15 +2468,11 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, e: &clean::Enum) -> fmt::Result { write!(w, "
    ")?;
         render_attributes(w, it)?;
    -    let padding = format!("{}enum {}{:#} ",
    -                          VisSpace(&it.visibility),
    -                          it.name.as_ref().unwrap(),
    -                          e.generics).len();
         write!(w, "{}enum {}{}{}",
                VisSpace(&it.visibility),
                it.name.as_ref().unwrap(),
                e.generics,
    -           WhereClause(&e.generics, padding))?;
    +           WhereClause { gens: &e.generics, indent: 0, end_newline: true })?;
         if e.variants.is_empty() && !e.variants_stripped {
             write!(w, " {{}}")?;
         } else {
    @@ -2640,23 +2646,17 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                      fields: &[clean::Item],
                      tab: &str,
                      structhead: bool) -> fmt::Result {
    -    let mut plain = String::new();
         write!(w, "{}{}{}",
                VisSpace(&it.visibility),
                if structhead {"struct "} else {""},
                it.name.as_ref().unwrap())?;
    -    plain.push_str(&format!("{}{}{}",
    -                            VisSpace(&it.visibility),
    -                            if structhead {"struct "} else {""},
    -                            it.name.as_ref().unwrap()));
         if let Some(g) = g {
    -        plain.push_str(&format!("{:#}", g));
             write!(w, "{}", g)?
         }
         match ty {
             doctree::Plain => {
                 if let Some(g) = g {
    -                write!(w, "{}", WhereClause(g, plain.len() + 1))?
    +                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
                 }
                 let mut has_visible_fields = false;
                 write!(w, " {{")?;
    @@ -2685,35 +2685,30 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
             }
             doctree::Tuple => {
                 write!(w, "(")?;
    -            plain.push_str("(");
                 for (i, field) in fields.iter().enumerate() {
                     if i > 0 {
                         write!(w, ", ")?;
    -                    plain.push_str(", ");
                     }
                     match field.inner {
                         clean::StrippedItem(box clean::StructFieldItem(..)) => {
    -                        plain.push_str("_");
                             write!(w, "_")?
                         }
                         clean::StructFieldItem(ref ty) => {
    -                        plain.push_str(&format!("{}{:#}", VisSpace(&field.visibility), *ty));
                             write!(w, "{}{}", VisSpace(&field.visibility), *ty)?
                         }
                         _ => unreachable!()
                     }
                 }
                 write!(w, ")")?;
    -            plain.push_str(")");
                 if let Some(g) = g {
    -                write!(w, "{}", WhereClause(g, plain.len() + 1))?
    +                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
                 }
                 write!(w, ";")?;
             }
             doctree::Unit => {
                 // Needed for PhantomData.
                 if let Some(g) = g {
    -                write!(w, "{}", WhereClause(g, plain.len() + 1))?
    +                write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
                 }
                 write!(w, ";")?;
             }
    @@ -2726,19 +2721,13 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
                     fields: &[clean::Item],
                     tab: &str,
                     structhead: bool) -> fmt::Result {
    -    let mut plain = String::new();
         write!(w, "{}{}{}",
                VisSpace(&it.visibility),
                if structhead {"union "} else {""},
                it.name.as_ref().unwrap())?;
    -    plain.push_str(&format!("{}{}{}",
    -                            VisSpace(&it.visibility),
    -                            if structhead {"union "} else {""},
    -                            it.name.as_ref().unwrap()));
         if let Some(g) = g {
             write!(w, "{}", g)?;
    -        plain.push_str(&format!("{:#}", g));
    -        write!(w, "{}", WhereClause(g, plain.len() + 1))?;
    +        write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?;
         }
     
         write!(w, " {{\n{}", tab)?;
    @@ -3037,13 +3026,12 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
     
     fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                     t: &clean::Typedef) -> fmt::Result {
    -    let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics).len();
         write!(w, "
    ")?;
         render_attributes(w, it)?;
         write!(w, "type {}{}{where_clause} = {type_};
    ", it.name.as_ref().unwrap(), t.generics, - where_clause = WhereClause(&t.generics, indent), + where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, type_ = t.type_)?; document(w, cx, it) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 4047f6045bcc..77ae2b587042 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -379,12 +379,6 @@ h4 > code, h3 > code, .invisible > code { .content .where.fmt-newline { display: block; } -/* Bit of whitespace to indent it */ -.content .method .where::before, -.content .fn .where::before, -.content .where.fmt-newline::before { - content: ' '; -} .content .methods > div { margin-left: 40px; } @@ -399,11 +393,6 @@ h4 > code, h3 > code, .invisible > code { font-size: 90%; } -/* Shift where in trait listing down a line */ -pre.trait .where::before { - content: '\a '; -} - nav { border-bottom: 1px solid; padding-bottom: 10px; @@ -772,4 +761,4 @@ span.since { nav.sub, .content .out-of-band, .collapse-toggle { display: none; } -} \ No newline at end of file +} From 3643d8165909c4a7959ed6cf9f3d1bd9cf3661b4 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Fri, 31 Mar 2017 19:02:00 -0500 Subject: [PATCH 219/905] rustdoc: fix alignment of fn arguments when on multiple lines --- src/librustdoc/html/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3fb90f407ebc..fd069ed7e076 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -971,7 +971,7 @@ impl<'a> fmt::Display for Method<'a> { } } else { if i > 0 { - args.push_str("
    "); + args.push_str("
    "); args_plain.push_str(" "); } if !input.name.is_empty() { From 89c35ae76493b6ea2401d2f0271f0f35693b1198 Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Fri, 31 Mar 2017 17:05:45 -0700 Subject: [PATCH 220/905] Add links and examples to std::sync::mpsc docs (#29377) This change adds links to to `Receiver`, `Iter`, `TryIter`, `IntoIter`, `Sender`, `SyncSender`, `SendError`, `RecvError`, `TryRecvError`, `RecvTimeoutError`, `TrySendError`, `Sender::send`, `SyncSender::send`, `SyncSender::try_send`, `Receiver::recv`, `Receiver::recv_timeout`, `Receiver::iter`, and `Receiver::try_iter`. Examples added to `Receiver`, `Sender`, `Receiver::iter`. --- src/libstd/sync/mpsc/mod.rs | 167 +++++++++++++++++++++++++++++------- 1 file changed, 136 insertions(+), 31 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 288a589e589b..fa31c6cedd2e 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -298,7 +298,28 @@ mod mpsc_queue; mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by -/// one thread +/// one thread. +/// +/// Messages sent to the channel can be retrieved using [`recv`]. +/// +/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// use std::time::Duration; +/// let (send, recv) = channel(); +/// thread::spawn(move || { +/// send.send("Hello world!"); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// send.send("Delayed for 2 seconds"); +/// }); +/// println!("{:?}", recv.recv()); // Received immediately +/// println!("Waiting..."); +/// println!("{:?}", recv.recv()); // Received after 2 seconds +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Receiver { inner: UnsafeCell>, @@ -312,9 +333,12 @@ unsafe impl Send for Receiver { } #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for Receiver { } -/// An iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be -/// returned when the corresponding channel has hung up. +/// An iterator over messages on a receiver, this iterator will block whenever +/// [`next`] is called, waiting for a new message, and [`None`] will be returned +/// when the corresponding channel has hung up. +/// +/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, T: 'a> { @@ -322,11 +346,13 @@ pub struct Iter<'a, T: 'a> { } /// An iterator that attempts to yield all pending values for a receiver. -/// `None` will be returned when there are no pending values remaining or -/// if the corresponding channel has hung up. +/// [`None`] will be returned when there are no pending values remaining or if +/// the corresponding channel has hung up. /// /// This Iterator will never block the caller in order to wait for data to -/// become available. Instead, it will return `None`. +/// become available. Instead, it will return [`None`]. +/// +/// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "receiver_try_iter", since = "1.15.0")] #[derive(Debug)] pub struct TryIter<'a, T: 'a> { @@ -334,8 +360,12 @@ pub struct TryIter<'a, T: 'a> { } /// An owning iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be +/// whenever [`next`] is called, waiting for a new message, and [`None`] will be /// returned when the corresponding channel has hung up. +/// +/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// #[stable(feature = "receiver_into_iter", since = "1.1.0")] #[derive(Debug)] pub struct IntoIter { @@ -344,6 +374,30 @@ pub struct IntoIter { /// The sending-half of Rust's asynchronous channel type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. +/// +/// Messages can be sent through this channel with [`send`]. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// let (sender, receiver) = channel(); +/// let sender2 = sender.clone(); +/// // First thread owns sender +/// thread::spawn(move || { +/// sender.send(1); +/// }); +/// // Second thread owns sender2 +/// thread::spawn(move || { +/// sender2.send(2); +/// }); +/// let msg = receiver.recv().unwrap(); +/// let msg2 = receiver.recv().unwrap(); +/// assert_eq!(3, msg + msg2); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Sender { inner: UnsafeCell>, @@ -359,6 +413,10 @@ impl !Sync for Sender { } /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send +/// #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender { inner: Arc>, @@ -370,25 +428,32 @@ unsafe impl Send for SyncSender {} #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for SyncSender {} -/// An error returned from the `send` function on channels. +/// An error returned from the [`send`] function on channels. /// -/// A `send` operation can only fail if the receiving end of a channel is +/// A [`send`] operation can only fail if the receiving end of a channel is /// disconnected, implying that the data could never be received. The error /// contains the data being sent as a payload so it can be recovered. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); -/// An error returned from the `recv` function on a `Receiver`. +/// An error returned from the [`recv`] function on a [`Receiver`]. /// -/// The `recv` operation can only fail if the sending half of a channel is +/// The [`recv`] operation can only fail if the sending half of a channel is /// disconnected, implying that no further messages will ever be received. +/// +/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; -/// This enumeration is the list of the possible reasons that `try_recv` could +/// This enumeration is the list of the possible reasons that [`try_recv`] could /// not return data when called. +/// +/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { @@ -403,8 +468,10 @@ pub enum TryRecvError { Disconnected, } -/// This enumeration is the list of possible errors that `recv_timeout` could +/// This enumeration is the list of possible errors that [`recv_timeout`] could /// not return data when called. +/// +/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { @@ -419,7 +486,9 @@ pub enum RecvTimeoutError { } /// This enumeration is the list of the possible error outcomes for the -/// `SyncSender::try_send` method. +/// [`SyncSender::try_send`] method. +/// +/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub enum TrySendError { @@ -566,10 +635,13 @@ impl Sender { /// A successful send occurs when it is determined that the other end of /// the channel has not hung up already. An unsuccessful send would be one /// where the corresponding receiver has already been deallocated. Note - /// that a return value of `Err` means that the data will never be - /// received, but a return value of `Ok` does *not* mean that the data + /// that a return value of [`Err`] means that the data will never be + /// received, but a return value of [`Ok`] does *not* mean that the data /// will be received. It is possible for the corresponding receiver to - /// hang up immediately after this function returns `Ok`. + /// hang up immediately after this function returns [`Ok`]. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok /// /// This method will never block the current thread. /// @@ -712,9 +784,12 @@ impl SyncSender { /// time. If the buffer size is 0, however, it can be guaranteed that the /// receiver has indeed received the data if this function returns success. /// - /// This function will never panic, but it may return `Err` if the - /// `Receiver` has disconnected and is no longer able to receive + /// This function will never panic, but it may return [`Err`] if the + /// [`Receiver`] has disconnected and is no longer able to receive /// information. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html #[stable(feature = "rust1", since = "1.0.0")] pub fn send(&self, t: T) -> Result<(), SendError> { self.inner.send(t).map_err(SendError) @@ -722,13 +797,16 @@ impl SyncSender { /// Attempts to send a value on this channel without blocking. /// - /// This method differs from `send` by returning immediately if the + /// This method differs from [`send`] by returning immediately if the /// channel's buffer is full or no receiver is waiting to acquire some - /// data. Compared with `send`, this function has two failure cases + /// data. Compared with [`send`], this function has two failure cases /// instead of one (one for disconnection, one for a full buffer). /// - /// See `SyncSender::send` for notes about guarantees of whether the + /// See [`SyncSender::send`] for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. + /// + /// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send + /// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] pub fn try_send(&self, t: T) -> Result<(), TrySendError> { self.inner.try_send(t) @@ -829,15 +907,18 @@ impl Receiver { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and + /// sent to the corresponding [`Sender`], then this receiver will wake up and /// return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ``` @@ -917,15 +998,18 @@ impl Receiver { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and + /// sent to the corresponding [`Sender`], then this receiver will wake up and /// return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ```no_run @@ -1003,7 +1087,26 @@ impl Receiver { } /// Returns an iterator that will block waiting for messages, but never - /// `panic!`. It will return `None` when the channel has hung up. + /// [`panic!`]. It will return [`None`] when the channel has hung up. + /// + /// [`panic!`]: ../../../std/macro.panic.html + /// [`None`]: ../../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::channel; + /// use std::thread; + /// let (send, recv) = channel(); + /// thread::spawn(move || { + /// send.send(1u8); + /// send.send(2u8); + /// send.send(3u8); + /// }); + /// for x in recv.iter() { + /// println!("Got: {}", x); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter { Iter { rx: self } @@ -1011,8 +1114,10 @@ impl Receiver { /// Returns an iterator that will attempt to yield all pending values. /// It will return `None` if there are no more pending values or if the - /// channel has hung up. The iterator will never `panic!` or block the + /// channel has hung up. The iterator will never [`panic!`] or block the /// user by waiting for values. + /// + /// [`panic!`]: ../../../std/macro.panic.html #[stable(feature = "receiver_try_iter", since = "1.15.0")] pub fn try_iter(&self) -> TryIter { TryIter { rx: self } From 1e2a61d4a6994c57cc8c8cd755734416e8117c45 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 1 Apr 2017 02:47:37 +0200 Subject: [PATCH 221/905] Change wording for push_front --- src/libcollections/vec_deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index c37bf752e86b..22f2ff1a3461 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1073,7 +1073,7 @@ impl VecDeque { } } - /// Prepends an element to the front of the `VecDeque`. + /// Prepends an element to the `VecDeque`. /// /// # Examples /// From ae8ba78e9df9891c4a6ebedf87dfcdafcacc6e68 Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Fri, 31 Mar 2017 18:51:37 -0700 Subject: [PATCH 222/905] Fix broken links to std::iter::Iterator::next --- src/libstd/sync/mpsc/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index fa31c6cedd2e..4f3d3422fd21 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -337,7 +337,7 @@ impl !Sync for Receiver { } /// [`next`] is called, waiting for a new message, and [`None`] will be returned /// when the corresponding channel has hung up. /// -/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next /// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] @@ -363,7 +363,7 @@ pub struct TryIter<'a, T: 'a> { /// whenever [`next`] is called, waiting for a new message, and [`None`] will be /// returned when the corresponding channel has hung up. /// -/// [`next`]: ../../../std/iter/trait.Iterator.html#method.next +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next /// [`None`]: ../../../std/option/enum.Option.html#variant.None /// #[stable(feature = "receiver_into_iter", since = "1.1.0")] From 5198072c3a70b5b61271b79d2b92cc751bedafd8 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Fri, 31 Mar 2017 23:22:22 -0400 Subject: [PATCH 223/905] Added links to from_utf8 methods in Utf8Error --- src/libcore/str/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5056adeaeeec..46264ea7b4f6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -152,11 +152,16 @@ impl fmt::Display for ParseBoolError { Section: Creating a string */ -/// Errors which can occur when attempting to interpret a sequence of `u8` +/// Errors which can occur when attempting to interpret a sequence of [`u8`] /// as a string. /// -/// As such, the `from_utf8` family of functions and methods for both `String`s -/// and `&str`s make use of this error, for example. +/// [`u8`]: ../../std/primitive.u8.html +/// +/// As such, the `from_utf8` family of functions and methods for both [`String`]s +/// and [`&str`]s make use of this error, for example. +/// +/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 +/// [`&str`]: ../../std/str/fn.from_utf8.html #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { From 7897e168bdd9708f83514a9c3e88d83278de4334 Mon Sep 17 00:00:00 2001 From: Dylan Maccora Date: Sat, 1 Apr 2017 15:35:03 +1100 Subject: [PATCH 224/905] Convert docs clean up. --- src/libcore/convert.rs | 145 ++++++++++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 31 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 0b0f831f093b..5546d2a13c47 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -17,8 +17,8 @@ //! Like many traits, these are often used as bounds for generic functions, to //! support arguments of multiple types. //! -//! - Impl the `As*` traits for reference-to-reference conversions -//! - Impl the [`Into`] trait when you want to consume the value in the conversion +//! - Implement the `As*` traits for reference-to-reference conversions +//! - Implement the [`Into`] trait when you want to consume the value in the conversion //! - The [`From`] trait is the most flexible, useful for value _and_ reference conversions //! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], but allow for the //! conversion to fail @@ -29,7 +29,7 @@ //! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a blanket implementation //! in the standard library. //! -//! # Generic impl +//! # Generic Implementations //! //! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference //! - [`From`]` for T` implies [`Into`]` for U` @@ -50,10 +50,20 @@ use str::FromStr; -/// A cheap, reference-to-reference conversion. +/// A cheap reference-to-reference conversion. Used to convert a value to a reference value +/// within generic code. /// -/// `AsRef` is very similar to, but different than, [`Borrow`]. See -/// [the book][book] for more. +/// `AsRef` is very similar to, but serves a slightly different purpose than, [`Borrow`]. +/// +/// `AsRef` is to be used when wishing to convert to a reference of another type. +/// `Borrow` is more related to the notion of taking the reference. It is useful when wishing to abstract +/// over the type of reference (`&T`, `&mut T`) or allow both the referenced and owned type to be treated in the same manner. +/// 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 +/// +/// See [the book][book] for a more detailed comparison. /// /// [book]: ../../book/borrow-and-asref.html /// [`Borrow`]: ../../std/borrow/trait.Borrow.html @@ -64,7 +74,23 @@ use str::FromStr; /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # Generic Implementations +/// +/// - `AsRef` 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`) +/// /// # Examples +/// An example implementation of the trait is [`Path`]. +/// +/// [`Path`]: ../../std/struct.Path.html +/// +/// ``` +/// impl AsRef for str { +/// fn as_ref(&self) -> &Path { +/// Path::new(self) +/// } +/// } +/// ``` /// /// Both [`String`] and `&str` implement `AsRef`: /// @@ -82,11 +108,6 @@ use str::FromStr; /// is_hello(s); /// ``` /// -/// # Generic Impls -/// -/// - `AsRef` 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`) -/// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRef { /// Performs the conversion. @@ -96,12 +117,19 @@ pub trait AsRef { /// A cheap, mutable reference-to-mutable reference conversion. /// +/// This trait is similar to `AsRef` but used for converting mutable references. +/// /// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which /// returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # 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`) +/// /// # Examples /// /// [`Box`] implements `AsMut`: @@ -118,10 +146,13 @@ pub trait AsRef { /// assert_eq!(*boxed_num, 1); /// ``` /// -/// # Generic Impls +/// Implementing `AsMut`: /// -/// - `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`) +/// ``` +/// impl Type { +/// let a = 1; +/// } +/// ``` /// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsMut { @@ -130,7 +161,7 @@ pub trait AsMut { fn as_mut(&mut self) -> &mut T; } -/// A conversion that consumes `self`, which may or may not be expensive. +/// A conversion that consumes `self`, which may or may not be expensive. The reciprocal of [`From`][From]. /// /// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated /// method which returns an [`Option`] or a [`Result`]. @@ -139,6 +170,11 @@ pub trait AsMut { /// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into` /// implementation for free, thanks to a blanket implementation in the standard library. /// +/// # Generic Implementations +/// +/// - [`From`][From]` for U` implies `Into for T` +/// - [`into`] is reflexive, which means that `Into for T` is implemented +/// /// # Examples /// /// [`String`] implements `Into>`: @@ -153,11 +189,6 @@ pub trait AsMut { /// is_hello(s); /// ``` /// -/// # Generic Impls -/// -/// - [`From`][From]` for U` implies `Into for T` -/// - [`into`] is reflexive, which means that `Into for T` is implemented -/// /// [`TryInto`]: trait.TryInto.html /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html @@ -171,11 +202,24 @@ pub trait Into: Sized { fn into(self) -> T; } -/// Construct `Self` via a conversion. +/// Simple and safe type conversions in to `Self`. It is the reciprocal of `Into`. +/// +/// This trait is useful when performing error handling as described by [the book][book] and is closely related to the `?` operator. +/// +/// When constructing a function that is capable of failing the return type will generally be of the form `Result`. +/// The `From` trait allows for simplification of error handling by providing a means of returning a single error type that encapsulates +/// numerous possible erroneous situations. +/// This trait is not limited to error handling, rather the general case for this trait would be in any type conversions to have an +/// explicit definition of how they are performed. /// /// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated /// method which returns an [`Option`] or a [`Result`]. /// +/// # Generic Implementations +/// +/// - `From for U` implies [`Into`]` for T` +/// - [`from`] is reflexive, which means that `From for T` is implemented +/// /// # Examples /// /// [`String`] implements `From<&str>`: @@ -186,10 +230,34 @@ pub trait Into: Sized { /// /// assert_eq!(string, other_string); /// ``` -/// # Generic impls /// -/// - `From for U` implies [`Into`]` for T` -/// - [`from`] is reflexive, which means that `From for T` is implemented +/// An example usage for error handling: +/// +/// ``` +/// enum CliError { +/// IoError(io::Error), +/// ParseError(num::ParseIntError), +/// } +/// +/// impl From for MyError { +/// fn from(error: io::Error) -> Self { +/// CliError::IoError(error) +/// } +/// } +/// +/// impl From for MyError { +/// fn from(error: io::Error) -> Self { +/// CliError::ParseError(error) +/// } +/// } +/// +/// fn open_and_parse_file(file_name: &str) -> Result { +/// let file = std::fs::File::open("test")?; +/// let mut contents = String::new(); +/// file.read_to_string(&mut contents)?; +/// let num: i32 = contents.trim().parse()?; +/// } +/// ``` /// /// [`TryFrom`]: trait.TryFrom.html /// [`Option`]: ../../std/option/enum.Option.html @@ -197,6 +265,7 @@ pub trait Into: Sized { /// [`String`]: ../../std/string/struct.String.html /// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from +/// [book]: ../../book/error-handling.html#the-from-trait #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. @@ -236,7 +305,9 @@ pub trait TryFrom: Sized { // As lifts over & #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T + where T: AsRef +{ fn as_ref(&self) -> &U { >::as_ref(*self) } @@ -244,7 +315,9 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { // As lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T + where T: AsRef +{ fn as_ref(&self) -> &U { >::as_ref(*self) } @@ -260,7 +333,9 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { // AsMut lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { +impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T + where T: AsMut +{ fn as_mut(&mut self) -> &mut U { (*self).as_mut() } @@ -276,7 +351,9 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { // From implies Into #[stable(feature = "rust1", since = "1.0.0")] -impl Into for T where U: From { +impl Into for T + where U: From +{ fn into(self) -> U { U::from(self) } @@ -285,13 +362,17 @@ impl Into for T where U: From { // From (and thus Into) is reflexive #[stable(feature = "rust1", since = "1.0.0")] impl From for T { - fn from(t: T) -> T { t } + fn from(t: T) -> T { + t + } } // TryFrom implies TryInto #[unstable(feature = "try_from", issue = "33417")] -impl TryInto for T where U: TryFrom { +impl TryInto for T + where U: TryFrom +{ type Error = U::Error; fn try_into(self) -> Result { @@ -327,7 +408,9 @@ impl AsRef for str { // FromStr implies TryFrom<&str> #[unstable(feature = "try_from", issue = "33417")] -impl<'a, T> TryFrom<&'a str> for T where T: FromStr { +impl<'a, T> TryFrom<&'a str> for T + where T: FromStr +{ type Error = ::Err; fn try_from(s: &'a str) -> Result { From dab8e8121f4a2ba6322417ba7644f3a06973a785 Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Fri, 31 Mar 2017 23:22:59 -0700 Subject: [PATCH 225/905] Fix warnings in examples --- src/libstd/sync/mpsc/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 4f3d3422fd21..33ffd5548fb8 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -312,13 +312,13 @@ mod spsc_queue; /// use std::time::Duration; /// let (send, recv) = channel(); /// thread::spawn(move || { -/// send.send("Hello world!"); +/// send.send("Hello world!").unwrap(); /// thread::sleep(Duration::from_secs(2)); // block for two seconds -/// send.send("Delayed for 2 seconds"); +/// send.send("Delayed for 2 seconds").unwrap(); /// }); -/// println!("{:?}", recv.recv()); // Received immediately +/// println!("{}", recv.recv().unwrap()); // Received immediately /// println!("Waiting..."); -/// println!("{:?}", recv.recv()); // Received after 2 seconds +/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Receiver { @@ -388,11 +388,11 @@ pub struct IntoIter { /// let sender2 = sender.clone(); /// // First thread owns sender /// thread::spawn(move || { -/// sender.send(1); +/// sender.send(1).unwrap(); /// }); /// // Second thread owns sender2 /// thread::spawn(move || { -/// sender2.send(2); +/// sender2.send(2).unwrap(); /// }); /// let msg = receiver.recv().unwrap(); /// let msg2 = receiver.recv().unwrap(); @@ -1099,9 +1099,9 @@ impl Receiver { /// use std::thread; /// let (send, recv) = channel(); /// thread::spawn(move || { - /// send.send(1u8); - /// send.send(2u8); - /// send.send(3u8); + /// send.send(1u8).unwrap(); + /// send.send(2u8).unwrap(); + /// send.send(3u8).unwrap(); /// }); /// for x in recv.iter() { /// println!("Got: {}", x); From ef01ae7fe0652c050ec9af8f70990bb01309ffbc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 1 Apr 2017 00:31:37 -0600 Subject: [PATCH 226/905] Force footnote references to be sorted by id --- src/librustdoc/html/markdown.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index d1f2948bc253..0b098fb14f19 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -585,11 +585,13 @@ pub fn render(w: &mut fmt::Formatter, } } if !parser.footnotes.is_empty() { + let mut v: Vec<_> = parser.footnotes.values().collect(); + v.sort_by(|a, b| a.1.cmp(&b.1)); buffer.push_str(&format!("

      {}
    ", - parser.footnotes.values() - .map(|&(ref s, _)| s.as_str()) - .collect::>() - .join(""))); + v.iter() + .map(|s| s.0.as_str()) + .collect::>() + .join(""))); } let mut ret = toc_builder.map_or(Ok(()), |builder| { write!(w, "", builder.into_toc()) From d8fb322acc5314efc3026b889594c92c320dce85 Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Sat, 1 Apr 2017 00:07:55 -0700 Subject: [PATCH 227/905] Clean up std::ascii sub-level docs. * Change `utf8` variable names to `non_ascii` to be more clear, since ASCII and UTF-8 are compatible. * Fix `EscapeDefault` struct description to follow the typical iterator method format with a link to the generating function. * Add more `escape_default` examples to cover every case mentioned in the function description itself. --- src/libstd/ascii.rs | 52 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 1cac11f668d9..12ea9ab431da 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -53,11 +53,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❀'; + /// let non_ascii = '❀'; /// let int_ascii = 97; /// /// assert!(ascii.is_ascii()); - /// assert!(!utf8.is_ascii()); + /// assert!(!non_ascii.is_ascii()); /// assert!(int_ascii.is_ascii()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -79,11 +79,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❀'; + /// let non_ascii = '❀'; /// let int_ascii = 97; /// /// assert_eq!('A', ascii.to_ascii_uppercase()); - /// assert_eq!('❀', utf8.to_ascii_uppercase()); + /// assert_eq!('❀', non_ascii.to_ascii_uppercase()); /// assert_eq!(65, int_ascii.to_ascii_uppercase()); /// ``` /// @@ -108,11 +108,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'A'; - /// let utf8 = '❀'; + /// let non_ascii = '❀'; /// let int_ascii = 65; /// /// assert_eq!('a', ascii.to_ascii_lowercase()); - /// assert_eq!('❀', utf8.to_ascii_lowercase()); + /// assert_eq!('❀', non_ascii.to_ascii_lowercase()); /// assert_eq!(97, int_ascii.to_ascii_lowercase()); /// ``` /// @@ -934,8 +934,12 @@ impl AsciiExt for char { } } -/// An iterator over the escaped version of a byte, constructed via -/// `std::ascii::escape_default`. +/// 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, @@ -966,6 +970,38 @@ pub struct EscapeDefault { /// /// 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 { From a5d775d2b6b0b5f8e595d83b2fc10d74036aa36a Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Sat, 1 Apr 2017 00:47:58 -0700 Subject: [PATCH 228/905] Add more std::ascii module-level docs. --- src/libstd/ascii.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 12ea9ab431da..b36253862094 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -9,6 +9,20 @@ // 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 [`AsciiExt`] trait provides methods that allow for character +//! operations that only act on the ASCII subset and leave non-ASCII characters +//! alone. +//! +//! The [`escape_default`] function provides an iterator over the bytes of an +//! escaped version of the character given. +//! +//! [`AsciiExt`]: trait.AsciiExt.html +//! [`escape_default`]: fn.escape_default.html #![stable(feature = "rust1", since = "1.0.0")] From 34cf28826f380fde33fedf377c1540e12d3b13a0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Mar 2017 12:49:13 -0700 Subject: [PATCH 229/905] rustc: Stabilize the `#![windows_subsystem]` attribute This commit stabilizes the `#![windows_subsystem]` attribute which is a conservative exposure of the `/SUBSYSTEM` linker flag on Widnows platforms. This is useful for creating applications as well as console programs. Closes #37499 --- src/doc/unstable-book/src/SUMMARY.md | 1 - src/doc/unstable-book/src/windows-subsystem.md | 10 ---------- src/libsyntax/feature_gate.rs | 12 +++--------- src/test/compile-fail/windows-subsystem-gated.rs | 16 ---------------- .../compile-fail/windows-subsystem-invalid.rs | 1 - src/test/run-make/windows-subsystem/console.rs | 1 - src/test/run-make/windows-subsystem/windows.rs | 1 - 7 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 src/doc/unstable-book/src/windows-subsystem.md delete mode 100644 src/test/compile-fail/windows-subsystem-gated.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 292f5a1ec816..72c2461c8bb5 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -209,5 +209,4 @@ - [windows_handle](windows-handle.md) - [windows_net](windows-net.md) - [windows_stdio](windows-stdio.md) -- [windows_subsystem](windows-subsystem.md) - [zero_one](zero-one.md) diff --git a/src/doc/unstable-book/src/windows-subsystem.md b/src/doc/unstable-book/src/windows-subsystem.md deleted file mode 100644 index 80583352fbf9..000000000000 --- a/src/doc/unstable-book/src/windows-subsystem.md +++ /dev/null @@ -1,10 +0,0 @@ -# `windows_subsystem` - -The tracking issue for this feature is: [#37499] - -[#37499]: https://github.com/rust-lang/rust/issues/37499 - ------------------------- - - - diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 12d25ca4274f..412803ddcd5a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -292,9 +292,6 @@ declare_features! ( // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) (active, generic_param_attrs, "1.11.0", Some(34761)), - // The #![windows_subsystem] attribute - (active, windows_subsystem, "1.14.0", Some(37499)), - // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), @@ -408,7 +405,8 @@ declare_features! ( (accepted, static_recursion, "1.17.0", Some(29719)), // pub(restricted) visibilities (RFC 1422) (accepted, pub_restricted, "1.17.0", Some(32409)), - + // The #![windows_subsystem] attribute + (accepted, windows_subsystem, "1.18.0", Some(37499)), ); // If you change this, please modify src/doc/unstable-book as well. You must // move that documentation into the relevant place in the other docs, and @@ -768,11 +766,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - ("windows_subsystem", Whitelisted, Gated(Stability::Unstable, - "windows_subsystem", - "the windows subsystem attribute \ - is currently unstable", - cfg_fn!(windows_subsystem))), + ("windows_subsystem", Whitelisted, Ungated), ("proc_macro_attribute", Normal, Gated(Stability::Unstable, "proc_macro", diff --git a/src/test/compile-fail/windows-subsystem-gated.rs b/src/test/compile-fail/windows-subsystem-gated.rs deleted file mode 100644 index 63f891a2af7b..000000000000 --- a/src/test/compile-fail/windows-subsystem-gated.rs +++ /dev/null @@ -1,16 +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-windows_subsystem - -#![windows_subsystem = "console"] -//~^ ERROR: the windows subsystem attribute is currently unstable - -fn main() {} diff --git a/src/test/compile-fail/windows-subsystem-invalid.rs b/src/test/compile-fail/windows-subsystem-invalid.rs index e0003440719e..7772cfd6a2c9 100644 --- a/src/test/compile-fail/windows-subsystem-invalid.rs +++ b/src/test/compile-fail/windows-subsystem-invalid.rs @@ -10,7 +10,6 @@ // error-pattern: invalid windows subsystem `wrong`, only `windows` and `console` are allowed -#![feature(windows_subsystem)] #![windows_subsystem = "wrong"] fn main() {} diff --git a/src/test/run-make/windows-subsystem/console.rs b/src/test/run-make/windows-subsystem/console.rs index 3aedb0ecab72..ffad1e35ee66 100644 --- a/src/test/run-make/windows-subsystem/console.rs +++ b/src/test/run-make/windows-subsystem/console.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(windows_subsystem)] #![windows_subsystem = "console"] fn main() {} diff --git a/src/test/run-make/windows-subsystem/windows.rs b/src/test/run-make/windows-subsystem/windows.rs index 5d875a5a1bf1..33cbe3205919 100644 --- a/src/test/run-make/windows-subsystem/windows.rs +++ b/src/test/run-make/windows-subsystem/windows.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(windows_subsystem)] #![windows_subsystem = "windows"] fn main() {} From 364241c709b3b769a0515b07b21c5748818291d8 Mon Sep 17 00:00:00 2001 From: Donnie Bishop Date: Sat, 1 Apr 2017 09:56:40 -0400 Subject: [PATCH 230/905] Added links to types in from_utf8 description --- src/libcore/str/mod.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f75a1f7ab6e0..8356fcd3cbee 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -210,11 +210,15 @@ impl Utf8Error { /// Converts a slice of bytes to a string slice. /// -/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`) -/// is made of bytes, so this function converts between the two. Not all byte -/// slices are valid string slices, however: `&str` requires that it is valid -/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and -/// then does the conversion. +/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice +/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between +/// the two. Not all byte slices are valid string slices, however: [`&str`] requires +/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid +/// UTF-8, and then does the conversion. +/// +/// [`&str`]: ../../std/primitive.str.html +/// [`u8`]: ../../std/primitive.u8.html +/// [byteslice]: ../../std/primitive.slice.html /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of @@ -228,9 +232,12 @@ impl Utf8Error { /// /// [string]: ../../std/string/struct.String.html#method.from_utf8 /// -/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of -/// it, this function is one way to have a stack-allocated string. There is -/// an example of this in the examples section below. +/// Because you can stack-allocate a `[u8; N]`, and you can take a +/// [`&[u8]`][byteslice] of it, this function is one way to have a +/// stack-allocated string. There is an example of this in the +/// examples section below. +/// +/// [byteslice]: ../../std/primitive.slice.html /// /// # Errors /// From 8ad8ba619426d76b041905258cd571538e7d4ca8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Apr 2017 06:58:11 -0700 Subject: [PATCH 231/905] Update cargo submodule Pulls in a fix for rust-lang/rust#40956 --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index 4e95c6b41eca..4729175045b4 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 +Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 From 128a313ee26b06b32e6980b4092435d7d352347d Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 1 Apr 2017 21:58:30 +0530 Subject: [PATCH 232/905] Improve docs of core::option::IntoIter --- src/libcore/option.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index d997f3592fd7..027d370f88f4 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -964,9 +964,15 @@ impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} -/// An iterator over the item contained inside an [`Option`]. +/// An iterator over the value in [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// +/// This `struct` is created by [`Option::into_iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::into_iter`]: enum.Option.html#method.into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { inner: Item } From 029ace40719baa452c7ac27e42529ec3ae8256c8 Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 1 Apr 2017 22:09:10 +0530 Subject: [PATCH 233/905] Improve docs of core::option::IterMut --- src/libcore/option.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 027d370f88f4..2d50f1b0ae5c 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -933,9 +933,15 @@ impl<'a, A> Clone for Iter<'a, A> { } } -/// An iterator over a mutable reference of the contained item in an [`Option`]. +/// An iterator over a mutable reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// +/// This `struct` is created by [`Option::iter_mut`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter_mut`]: enum.Option.html#method.iter_mut #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } From c414628782ab60817909de2b98d206782dc15200 Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sat, 1 Apr 2017 22:17:48 +0530 Subject: [PATCH 234/905] Improve docs of core::option::Iter --- src/libcore/option.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 2d50f1b0ae5c..2cdafbf2570e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -894,9 +894,15 @@ impl ExactSizeIterator for Item {} impl FusedIterator for Item {} unsafe impl TrustedLen for Item {} -/// An iterator over a reference of the contained item in an [`Option`]. +/// An iterator over a reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// +/// This `struct` is created by [`Option::iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter`]: enum.Option.html#method.iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } From 4c9f8ae4fd50b857e7a754087243100764a4e4de Mon Sep 17 00:00:00 2001 From: Irfan Hudda Date: Sun, 2 Apr 2017 06:10:34 +0530 Subject: [PATCH 235/905] Minor changes to core::option docs --- src/libcore/option.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 2cdafbf2570e..1a48f2776258 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -896,9 +896,9 @@ unsafe impl TrustedLen for Item {} /// An iterator over a reference to the [`Some`] variant of an [`Option`]. /// -/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// -/// This `struct` is created by [`Option::iter`] function. +/// This `struct` is created by the [`Option::iter`] function. /// /// [`Option`]: enum.Option.html /// [`Some`]: enum.Option.html#variant.Some @@ -941,9 +941,9 @@ impl<'a, A> Clone for Iter<'a, A> { /// An iterator over a mutable reference to the [`Some`] variant of an [`Option`]. /// -/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// -/// This `struct` is created by [`Option::iter_mut`] function. +/// This `struct` is created by the [`Option::iter_mut`] function. /// /// [`Option`]: enum.Option.html /// [`Some`]: enum.Option.html#variant.Some @@ -978,9 +978,9 @@ unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} /// An iterator over the value in [`Some`] variant of an [`Option`]. /// -/// The iterator yields one value if the [`Option`] is a [`Some`] variant, otherwise none. +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// -/// This `struct` is created by [`Option::into_iter`] function. +/// This `struct` is created by the [`Option::into_iter`] function. /// /// [`Option`]: enum.Option.html /// [`Some`]: enum.Option.html#variant.Some From bd698b9e8b02e27409123e71c0594523b926b850 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 19 Mar 2017 11:22:48 -0400 Subject: [PATCH 236/905] Don't panic if we have tidy errors. Otherwise we get the standard Rust panic message alongside "some tidy checks failed" which seems unnecessary. --- src/tools/tidy/src/main.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 501e35e03e8a..d0e8cf9c343d 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -16,9 +16,11 @@ extern crate regex; -use std::fs; -use std::path::{PathBuf, Path}; use std::env; +use std::fs; +use std::io::{self, Write}; +use std::path::{PathBuf, Path}; +use std::process; macro_rules! t { ($e:expr, $p:expr) => (match $e { @@ -60,7 +62,8 @@ fn main() { } if bad { - panic!("some tidy checks failed"); + writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr"); + process::exit(1); } } From ff4febf8eafa86bc7a3130d68f81c852a9da3661 Mon Sep 17 00:00:00 2001 From: Peter Gerber Date: Sat, 1 Apr 2017 15:58:37 +0200 Subject: [PATCH 237/905] Improve documentation for `std::fs::DirBuilder` --- src/libstd/fs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index ca26dc9527c0..1b00eb95de2b 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1726,9 +1726,9 @@ impl DirBuilder { } } - /// Indicate that directories create should be created recursively, creating - /// all parent directories if they do not exist with the same security and - /// permissions settings. + /// Indicates that directories should be created recursively, creating all + /// parent directories. Parents that do not exist are created with the same + /// security and permissions settings. /// /// This option defaults to `false`. /// @@ -1749,6 +1749,9 @@ impl DirBuilder { /// Create the specified directory with the options configured in this /// builder. /// + /// It is considered an error if the directory already exists unless + /// recursive mode is enabled. + /// /// # Examples /// /// ```no_run From 509ef4c496ffafdc635c94e52e4d19b01d0bfb6a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 2 Apr 2017 12:03:54 +0200 Subject: [PATCH 238/905] std::thread docs: fix link to current() --- src/libstd/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index edf928d61063..18c00e7c5f1b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -158,7 +158,7 @@ //! [`Err`]: ../../std/result/enum.Result.html#variant.Err //! [`panic!`]: ../../std/macro.panic.html //! [`Builder`]: ../../std/thread/struct.Builder.html -//! [`thread::current`]: ../../std/thread/fn.spawn.html +//! [`thread::current`]: ../../std/thread/fn.current.html //! [`Thread`]: ../../std/thread/struct.Thread.html //! [`park`]: ../../std/thread/fn.park.html //! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark From 09ac56d6efd41c02cbb7f8714d59bdd43f663ec8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 2 Apr 2017 16:18:39 +0300 Subject: [PATCH 239/905] mark build::cfg::start_new_block as inline(never) LLVM has a bug - PR32488 - where it fails to deduplicate allocas in some circumstances. The function `start_new_block` has allocas totalling 1216 bytes, and when LLVM inlines several copies of that function into the recursive function `expr::into`, that function's stack space usage goes into tens of kiBs, causing stack overflows. Mark `start_new_block` as inline(never) to keep it from being inlined, getting stack usage under control. Fixes #40493. Fixes #40573. --- src/librustc_mir/build/cfg.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 71e97e4bfe0d..c503b8c7fe06 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -25,6 +25,9 @@ impl<'tcx> CFG<'tcx> { &mut self.basic_blocks[blk] } + // llvm.org/PR32488 makes this function use an excess of stack space. Mark + // it as #[inline(never)] to keep rustc's stack use in check. + #[inline(never)] pub fn start_new_block(&mut self) -> BasicBlock { self.basic_blocks.push(BasicBlockData::new(None)) } From 255d9191a9509c4adfc086deacff5ec6680815a5 Mon Sep 17 00:00:00 2001 From: mandeep Date: Sun, 2 Apr 2017 11:21:05 -0500 Subject: [PATCH 240/905] Fixed typo in doc comments for swap_remove --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e0034..44ac4f1cff58 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -678,7 +678,7 @@ impl Vec { self.len = len; } - /// Removes an element from anywhere in the vector and return it, replacing + /// Removes an element from anywhere in the vector and returns it, replacing /// it with the last element. /// /// This does not preserve ordering, but is O(1). From b946ecd02018d1671c990057d7136176df60da35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Mar 2017 15:14:45 -0700 Subject: [PATCH 241/905] Suggest using enum when a variant is used as a type Given a file: ```rust enum Fruit { Apple(i64), Orange(i64), } fn should_return_fruit() -> Apple { Apple(5) } ``` Provide the following output: ```rust error[E0412]: cannot find type `Apple` in this scope --> file.rs:16:29 | 16 | fn should_return_fruit() -> Apple { | ^^^^^ not found in this scope | help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? --> file.rs:12:5 | 12 | Apple(i64), | ^^^^^^^^^^ error[E0425]: cannot find function `Apple` in this scope --> file.rs:17:5 | 17 | Apple(5) | ^^^^^ not found in this scope | = help: possible candidate is found in another module, you can import it into scope: `use Fruit::Apple;` ``` --- src/librustc_resolve/lib.rs | 30 +++++++++ src/test/ui/did_you_mean/issue-35675.rs | 44 ++++++++++++ src/test/ui/did_you_mean/issue-35675.stderr | 74 +++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 src/test/ui/did_you_mean/issue-35675.rs create mode 100644 src/test/ui/did_you_mean/issue-35675.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da..a39cd3b0d551 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2220,6 +2220,7 @@ impl<'a> Resolver<'a> { -> PathResolution { let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); + let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; // Base error is amended with one short label and possibly some longer helps/notes. let report_errors = |this: &mut Self, def: Option| { @@ -2270,6 +2271,19 @@ impl<'a> Resolver<'a> { if !candidates.is_empty() { // Report import candidates as help and proceed searching for labels. show_candidates(&mut err, &candidates, def.is_some()); + } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { + let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); + for suggestion in enum_candidates { + let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", + variant_path, + enum_path); + if suggestion.path.span == DUMMY_SP { + err.help(&msg); + } else { + err.span_help(suggestion.path.span, &msg); + } + } } if path.len() == 1 && this.self_type_is_available() { if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) { @@ -3422,6 +3436,22 @@ fn path_names_to_string(path: &Path) -> String { names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::>()) } +/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { + let variant_path = &suggestion.path; + let variant_path_string = path_names_to_string(variant_path); + + let path_len = suggestion.path.segments.len(); + let enum_path = ast::Path { + span: suggestion.path.span, + segments: suggestion.path.segments[0..path_len - 1].to_vec(), + }; + let enum_path_string = path_names_to_string(&enum_path); + + (variant_path_string, enum_path_string) +} + + /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/test/ui/did_you_mean/issue-35675.rs b/src/test/ui/did_you_mean/issue-35675.rs new file mode 100644 index 000000000000..ff29f3ad4078 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.rs @@ -0,0 +1,44 @@ +// 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. + +enum Fruit { + Apple(i64), + Orange(i64), +} + +fn should_return_fruit() -> Apple { + Apple(5) +} + +fn should_return_fruit_too() -> Fruit::Apple { + Apple(5) +} + +fn foo() -> Ok { + Ok(()) +} + +fn bar() -> Variant3 { +} + +fn qux() -> Some { + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + Variant4 {}, + } +} diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr new file mode 100644 index 000000000000..43851d76029d --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -0,0 +1,74 @@ +error[E0412]: cannot find type `Apple` in this scope + --> $DIR/issue-35675.rs:16:29 + | +16 | fn should_return_fruit() -> Apple { + | ^^^^^ not found in this scope + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:17:5 + | +17 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Fruit::Apple` + --> $DIR/issue-35675.rs:20:33 + | +20 | fn should_return_fruit_too() -> Fruit::Apple { + | ^^^^^^^^^^^^ not a type + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:21:5 + | +21 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Ok` + --> $DIR/issue-35675.rs:24:13 + | +24 | fn foo() -> Ok { + | ^^ not a type + | + = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? + = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + +error[E0412]: cannot find type `Variant3` in this scope + --> $DIR/issue-35675.rs:28:13 + | +28 | fn bar() -> Variant3 { + | ^^^^^^^^ not found in this scope + | +help: there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + --> $DIR/issue-35675.rs:41:9 + | +41 | Variant3(usize), + | ^^^^^^^^^^^^^^^ + +error[E0573]: expected type, found variant `Some` + --> $DIR/issue-35675.rs:31:13 + | +31 | fn qux() -> Some { + | ^^^^ not a type + | + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + +error: aborting due to 7 previous errors + From b83352e44c36e81db7f00eb60e78ff3828c51c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 28 Mar 2017 18:56:29 -0700 Subject: [PATCH 242/905] Introduce `TyErr` independent from `TyInfer` Add a `TyErr` type to represent unknown types in places where parse errors have happened, while still able to build the AST. Initially only used to represent incorrectly written fn arguments and avoid "expected X parameters, found Y" errors when called with the appropriate amount of parameters. We cannot use `TyInfer` for this as `_` is not allowed as a valid argument type. Example output: ```rust error: expected one of `:` or `@`, found `,` --> file.rs:12:9 | 12 | fn bar(x, y: usize) {} | ^ error[E0061]: this function takes 2 parameters but 3 parameters were supplied --> file.rs:19:9 | 12 | fn bar(x, y) {} | --------------- defined here ... 19 | bar(1, 2, 3); | ^^^^^^^ expected 2 parameters ``` --- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/mod.rs | 2 + src/librustc/hir/print.rs | 3 ++ .../calculate_svh/svh_visitor.rs | 6 ++- src/librustc_typeck/astconv.rs | 3 ++ src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/ast.rs | 2 + src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 25 +++++++++- src/libsyntax/print/pprust.rs | 3 ++ src/libsyntax/visit.rs | 2 +- src/test/ui/span/issue-34264.rs | 20 ++++++++ src/test/ui/span/issue-34264.stderr | 49 +++++++++++++++++++ 14 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/span/issue-34264.rs create mode 100644 src/test/ui/span/issue-34264.stderr diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index c7ad143c9497..2c8b145f126c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -578,7 +578,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyTypeof(expression) => { visitor.visit_nested_body(expression) } - TyInfer => {} + TyInfer | TyErr => {} } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 17185a6ab69f..acc6d21ddc69 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -555,6 +555,7 @@ impl<'a> LoweringContext<'a> { fn lower_ty(&mut self, t: &Ty) -> P { let kind = match t.node { TyKind::Infer => hir::TyInfer, + TyKind::Err => hir::TyErr, TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d5000ac9c186..0da405d1821d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1351,6 +1351,8 @@ pub enum Ty_ { /// TyInfer means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. TyInfer, + /// Placeholder for a type that has failed to be defined. + TyErr, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 04a65fd5e3aa..4a5a35aa82ca 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -450,6 +450,9 @@ impl<'a> State<'a> { hir::TyInfer => { word(&mut self.s, "_")?; } + hir::TyErr => { + word(&mut self.s, "?")?; + } } self.end() } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 5401b371888e..4700b77be076 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -432,7 +432,8 @@ enum SawTyComponent { SawTyObjectSum, SawTyImplTrait, SawTyTypeof, - SawTyInfer + SawTyInfer, + SawTyErr, } fn saw_ty(node: &Ty_) -> SawTyComponent { @@ -448,7 +449,8 @@ fn saw_ty(node: &Ty_) -> SawTyComponent { TyTraitObject(..) => SawTyObjectSum, TyImplTrait(..) => SawTyImplTrait, TyTypeof(..) => SawTyTypeof, - TyInfer => SawTyInfer + TyInfer => SawTyInfer, + TyErr => SawTyErr, } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 923ec05c22b7..66c4a81a5c0f 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1229,6 +1229,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // handled specially and will not descend into this routine. self.ty_infer(ast_ty.span) } + hir::TyErr => { + tcx.types.err + } }; cache.borrow_mut().insert(ast_ty.id, result_ty); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f3ea6c4467c4..ac72d7d29a24 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1805,7 +1805,7 @@ impl Clean for hir::Ty { } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)), - TyInfer => Infer, + TyInfer | TyErr => Infer, TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9eb86aa006d1..c6a3e8a2dedc 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1361,6 +1361,8 @@ pub enum TyKind { ImplicitSelf, // A macro in the type position. Mac(Mac), + /// Placeholder for a kind that has failed to be defined. + Err, } /// Inline assembly dialect. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a4e196ac557..92e25b00e0ac 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -358,7 +358,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { t.map(|Ty {id, node, span}| Ty { id: fld.new_id(id), node: match node { - TyKind::Infer | TyKind::ImplicitSelf => node, + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => node, TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)), TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)), TyKind::Rptr(region, mt) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855a..23fc1351426c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -407,6 +407,25 @@ impl From> for LhsExpr { } } +/// Create a placeholder argument. +fn dummy_arg(span: Span) -> Arg { + let spanned = Spanned { + span: span, + node: keywords::Invalid.ident() + }; + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), spanned, None), + span: span + }); + let ty = Ty { + node: TyKind::Err, + span: span, + id: ast::DUMMY_NODE_ID + }; + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } +} + impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, tokens: TokenStream, @@ -4343,8 +4362,12 @@ impl<'a> Parser<'a> { Ok(arg) => Ok(Some(arg)), Err(mut e) => { e.emit(); + let lo = p.prev_span; + // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); - Ok(None) + // Create a placeholder argument for proper arg count (#34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(span))) } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f042a18d6103..e7feff2b79fc 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1095,6 +1095,9 @@ impl<'a> State<'a> { ast::TyKind::Infer => { word(&mut self.s, "_")?; } + ast::TyKind::Err => { + word(&mut self.s, "?")?; + } ast::TyKind::ImplicitSelf => { word(&mut self.s, "Self")?; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a5333f3bb6a6..b5e9a1892acc 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -350,7 +350,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Typeof(ref expression) => { visitor.visit_expr(expression) } - TyKind::Infer | TyKind::ImplicitSelf => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::Mac(ref mac) => { visitor.visit_mac(mac) } diff --git a/src/test/ui/span/issue-34264.rs b/src/test/ui/span/issue-34264.rs new file mode 100644 index 000000000000..00482f50618d --- /dev/null +++ b/src/test/ui/span/issue-34264.rs @@ -0,0 +1,20 @@ +// 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 foo(Option, String) {} +fn bar(x, y: usize) {} + +fn main() { + foo(Some(42), 2); + foo(Some(42), 2, ""); + bar("", ""); + bar(1, 2); + bar(1, 2, 3); +} diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr new file mode 100644 index 000000000000..c79db54eaef0 --- /dev/null +++ b/src/test/ui/span/issue-34264.stderr @@ -0,0 +1,49 @@ +error: expected one of `:` or `@`, found `<` + --> $DIR/issue-34264.rs:11:14 + | +11 | fn foo(Option, String) {} + | ^ + +error: expected one of `:` or `@`, found `)` + --> $DIR/issue-34264.rs:11:27 + | +11 | fn foo(Option, String) {} + | ^ + +error: expected one of `:` or `@`, found `,` + --> $DIR/issue-34264.rs:12:9 + | +12 | fn bar(x, y: usize) {} + | ^ + +error[E0061]: this function takes 2 parameters but 3 parameters were supplied + --> $DIR/issue-34264.rs:16:9 + | +11 | fn foo(Option, String) {} + | ------------------------------ defined here +... +16 | foo(Some(42), 2, ""); + | ^^^^^^^^^^^^^^^ expected 2 parameters + +error[E0308]: mismatched types + --> $DIR/issue-34264.rs:17:13 + | +17 | bar("", ""); + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + = help: here are some functions which might fulfill your needs: + - .len() + +error[E0061]: this function takes 2 parameters but 3 parameters were supplied + --> $DIR/issue-34264.rs:19:9 + | +12 | fn bar(x, y: usize) {} + | ---------------------- defined here +... +19 | bar(1, 2, 3); + | ^^^^^^^ expected 2 parameters + +error: aborting due to 3 previous errors + From 584b40578d8ab999031da0855f319a94db06dc47 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:18:27 -0600 Subject: [PATCH 243/905] Vastly improve the help output. - Don't print 'unknown subcommand' at the top of the help message. The help message now clearly instructs the user to provide a subcommand. - Clarify the usage line. Subcommand is required. Don't echo invalid input back out in the usage line (what the...???). args renamed to paths, because that's what all the args are referred to elsewhere. - List the available subcommands immediately following the usage line. It's the one required argument, after all. - Slightly improve the extra documentation for the build, test, and doc commands. - Don't print 'Available invocations:' at all. It occurred immediately before 'Available paths:'. - Clearly state that running with '-h -v' will produce a list of available paths. --- src/bootstrap/flags.rs | 53 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 556a362a8749..1a260050a942 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -90,19 +90,31 @@ impl Flags { opts.optflag("h", "help", "print this help message"); let usage = |n, opts: &Options| -> ! { - let subcommand = args.get(0).map(|s| &**s); - let brief = format!("Usage: x.py [options] [...]"); + let subcommand_help = format!("\ +Usage: x.py [options] [...] - println!("{}", opts.usage(&brief)); +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + bench Build and run some benchmarks + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py -h`"); + + println!("{}", opts.usage(&subcommand_help)); + + let subcommand = args.get(0).map(|s| &**s); match subcommand { Some("build") => { println!("\ Arguments: - This subcommand accepts a number of positional arguments of directories to - the crates and/or artifacts to compile. For example: + This subcommand accepts a number of paths to directories to the crates + and/or artifacts to compile. For example: ./x.py build src/libcore - ./x.py build src/libproc_macro + ./x.py build src/libcore src/libproc_macro ./x.py build src/libstd --stage 1 If no arguments are passed then the complete artifacts for that stage are @@ -120,8 +132,8 @@ Arguments: Some("test") => { println!("\ Arguments: - This subcommand accepts a number of positional arguments of directories to - tests that should be compiled and run. For example: + This subcommand accepts a number of paths to directories to tests that + should be compiled and run. For example: ./x.py test src/test/run-pass ./x.py test src/libstd --test-args hash_map @@ -138,12 +150,12 @@ Arguments: Some("doc") => { println!("\ Arguments: - This subcommand accepts a number of positional arguments of directories of - documentation to build. For example: + This subcommand accepts a number of paths to directories of documentation + to build. For example: ./x.py doc src/doc/book ./x.py doc src/doc/nomicon - ./x.py doc src/libstd + ./x.py doc src/doc/book src/libstd If no arguments are passed then everything is documented: @@ -155,6 +167,7 @@ Arguments: _ => {} } + if let Some(subcommand) = subcommand { if subcommand == "build" || subcommand == "test" || @@ -162,7 +175,6 @@ Arguments: subcommand == "doc" || subcommand == "clean" || subcommand == "dist" { - println!("Available invocations:"); if args.iter().any(|a| a == "-v") { let flags = Flags::parse(&["build".to_string()]); let mut config = Config::default(); @@ -171,7 +183,7 @@ Arguments: metadata::build(&mut build); step::build_rules(&build).print_help(subcommand); } else { - println!(" ... elided, run `./x.py {} -h -v` to see", + println!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand); } @@ -179,18 +191,6 @@ Arguments: } } -println!("\ -Subcommands: - build Compile either the compiler or libraries - test Build and run some test suites - bench Build and run some benchmarks - doc Build documentation - clean Clean out build directories - dist Build and/or install distribution artifacts - -To learn more about a subcommand, run `./x.py -h` -"); - process::exit(n); }; if args.len() == 0 { @@ -256,8 +256,7 @@ To learn more about a subcommand, run `./x.py -h` } } "--help" => usage(0, &opts), - cmd => { - println!("unknown subcommand: {}", cmd); + _ => { usage(1, &opts); } }; From 992a59efc3e3fd976728fc19a1a854afcbb06adf Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:20:51 -0600 Subject: [PATCH 244/905] Using an untyped, one-letter variable binding as an argument to a function and then not using it until over 100 lines later is just mean. --- src/bootstrap/flags.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 1a260050a942..64b66d9c6bc3 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -89,7 +89,7 @@ impl Flags { opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - let usage = |n, opts: &Options| -> ! { + let usage = |exit_code, opts: &Options| -> ! { let subcommand_help = format!("\ Usage: x.py [options] [...] @@ -191,7 +191,7 @@ Arguments: } } - process::exit(n); + process::exit(exit_code); }; if args.len() == 0 { println!("a subcommand must be passed"); From 5ba579e7f43e607315737899a779d8bd0f378f53 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 30 Mar 2017 22:35:55 -0600 Subject: [PATCH 245/905] Save my TODO's as comments, so I don't forget. --- src/bootstrap/flags.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 64b66d9c6bc3..684a39953e2e 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -212,6 +212,8 @@ Arguments: let remaining_as_path = |m: &Matches| { m.free.iter().map(|p| cwd.join(p)).collect::>() }; + // TODO: Parse subcommand nicely up at top, so options can occur before the subcommand. + // TODO: Get the subcommand-specific options below into the help output let m: Matches; let cmd = match &args[0][..] { From aa4bd0ec0ea0e4edd2a4507c776f9979a05005d1 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 1 Apr 2017 15:48:03 -0600 Subject: [PATCH 246/905] Finish the improvements I planned. - No more manual args manipulation -- getopts used for everything. As a result, options can be in any position, now, even before the subcommand. - The additional options for test, bench, and dist now appear in the help output. - No more single-letter variable bindings used internally for large scopes. - Don't output the time measurement when just invoking 'x.py' - Logic is now much more linear. We build strings up, and then print them. --- src/bootstrap/bootstrap.py | 5 +- src/bootstrap/flags.rs | 222 ++++++++++++++++++------------------- src/bootstrap/step.rs | 11 +- 3 files changed, 113 insertions(+), 125 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 73f3b1d1ceba..0e5991a51bc8 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -591,9 +591,10 @@ def bootstrap(): def main(): start_time = time() + help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) try: bootstrap() - if ('-h' not in sys.argv) and ('--help' not in sys.argv): + if not help_triggered: print("Build completed successfully in %s" % format_build_time(time() - start_time)) except (SystemExit, KeyboardInterrupt) as e: if hasattr(e, 'code') and isinstance(e.code, int): @@ -601,7 +602,7 @@ def main(): else: exit_code = 1 print(e) - if ('-h' not in sys.argv) and ('--help' not in sys.argv): + if not help_triggered: print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) sys.exit(exit_code) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 684a39953e2e..e60e279876c3 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; use std::process; -use getopts::{Matches, Options}; +use getopts::{Options}; use Build; use config::Config; @@ -75,7 +75,22 @@ pub enum Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { + let mut extra_help = String::new(); + let mut subcommand_help = format!("\ +Usage: x.py [options] [...] + +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + bench Build and run some benchmarks + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py -h`"); + let mut opts = Options::new(); + // Options common to all subcommands opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)"); opts.optflag("i", "incremental", "use incremental compilation"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); @@ -89,26 +104,38 @@ impl Flags { opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - let usage = |exit_code, opts: &Options| -> ! { - let subcommand_help = format!("\ -Usage: x.py [options] [...] + // fn usage() + let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; -Subcommands: - build Compile either the compiler or libraries - test Build and run some test suites - bench Build and run some benchmarks - doc Build documentation - clean Clean out build directories - dist Build and/or install distribution artifacts + // Get subcommand + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + let subcommand = match matches.free.get(0) { + Some(s) => { s }, + None => { + // No subcommand -- lets only show the general usage and subcommand help in this case. + println!("{}\n", subcommand_help); + process::exit(0); + } + }; -To learn more about a subcommand, run `./x.py -h`"); + // Get any optional paths which occur after the subcommand + let cwd = t!(env::current_dir()); + let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); - println!("{}", opts.usage(&subcommand_help)); - - let subcommand = args.get(0).map(|s| &**s); - match subcommand { - Some("build") => { - println!("\ + // Some subcommands have specific arguments help text + match subcommand.as_str() { + "build" => { + subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: @@ -125,12 +152,11 @@ Arguments: For a quick build with a usable compile, you can pass: - ./x.py build --stage 1 src/libtest -"); - } - - Some("test") => { - println!("\ + ./x.py build --stage 1 src/libtest"); + } + "test" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories to tests that should be compiled and run. For example: @@ -143,12 +169,13 @@ Arguments: compiled and tested. ./x.py test - ./x.py test --stage 1 -"); - } - - Some("doc") => { - println!("\ + ./x.py test --stage 1"); + } + "bench" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + } + "doc" => { + subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories of documentation to build. For example: @@ -160,111 +187,74 @@ Arguments: If no arguments are passed then everything is documented: ./x.py doc - ./x.py doc --stage 1 -"); - } - - _ => {} + ./x.py doc --stage 1"); } - - - if let Some(subcommand) = subcommand { - if subcommand == "build" || - subcommand == "test" || - subcommand == "bench" || - subcommand == "doc" || - subcommand == "clean" || - subcommand == "dist" { - if args.iter().any(|a| a == "-v") { - let flags = Flags::parse(&["build".to_string()]); - let mut config = Config::default(); - config.build = flags.build.clone(); - let mut build = Build::new(flags, config); - metadata::build(&mut build); - step::build_rules(&build).print_help(subcommand); - } else { - println!("Run `./x.py {} -h -v` to see a list of available paths.", - subcommand); - } - - println!(""); - } + "dist" => { + opts.optflag("", "install", "run installer as well"); } - - process::exit(exit_code); + _ => { } }; - if args.len() == 0 { - println!("a subcommand must be passed"); - usage(1, &opts); + + // All subcommands can have an optional "Available paths" section + if matches.opt_present("verbose") { + let flags = Flags::parse(&["build".to_string()]); + let mut config = Config::default(); + config.build = flags.build.clone(); + let mut build = Build::new(flags, config); + metadata::build(&mut build); + let maybe_rules_help = step::build_rules(&build).get_help(subcommand); + if maybe_rules_help.is_some() { + extra_help.push_str(maybe_rules_help.unwrap().as_str()); + } + } else { + extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.", + subcommand).as_str()); } - let parse = |opts: &Options| { - let m = opts.parse(&args[1..]).unwrap_or_else(|e| { - println!("failed to parse options: {}", e); - usage(1, opts); - }); - if m.opt_present("h") { - usage(0, opts); - } - return m - }; - let cwd = t!(env::current_dir()); - let remaining_as_path = |m: &Matches| { - m.free.iter().map(|p| cwd.join(p)).collect::>() - }; - // TODO: Parse subcommand nicely up at top, so options can occur before the subcommand. - // TODO: Get the subcommand-specific options below into the help output + // User passed in -h/--help? + if matches.opt_present("help") { + usage(0, &opts, &subcommand_help, &extra_help); + } - let m: Matches; - let cmd = match &args[0][..] { + let cmd = match subcommand.as_str() { "build" => { - m = parse(&opts); - Subcommand::Build { paths: remaining_as_path(&m) } + Subcommand::Build { paths: paths } } "test" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Test { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } "bench" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Bench { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } "doc" => { - m = parse(&opts); - Subcommand::Doc { paths: remaining_as_path(&m) } + Subcommand::Doc { paths: paths } } "clean" => { - m = parse(&opts); - if m.free.len() > 0 { - println!("clean takes no arguments"); - usage(1, &opts); + if matches.free.len() > 0 { + println!("\nclean takes no arguments\n"); + usage(1, &opts, &subcommand_help, &extra_help); } Subcommand::Clean } "dist" => { - opts.optflag("", "install", "run installer as well"); - m = parse(&opts); Subcommand::Dist { - paths: remaining_as_path(&m), - install: m.opt_present("install"), + paths: paths, + install: matches.opt_present("install"), } } - "--help" => usage(0, &opts), _ => { - usage(1, &opts); + usage(1, &opts, &subcommand_help, &extra_help); } }; - let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { + let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { Some(PathBuf::from("config.toml")) } else { @@ -272,31 +262,29 @@ Arguments: } }); - let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap()); + let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap()); - let incremental = m.opt_present("i"); - - if incremental { + if matches.opt_present("incremental") { if stage.is_none() { stage = Some(1); } } Flags { - verbose: m.opt_count("v"), + verbose: matches.opt_count("verbose"), stage: stage, - on_fail: m.opt_str("on-fail"), - keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), - build: m.opt_str("build").unwrap_or_else(|| { + on_fail: matches.opt_str("on-fail"), + keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), + build: matches.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() }), - host: split(m.opt_strs("host")), - target: split(m.opt_strs("target")), + host: split(matches.opt_strs("host")), + target: split(matches.opt_strs("target")), config: cfg_file, - src: m.opt_str("src").map(PathBuf::from), - jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), + src: matches.opt_str("src").map(PathBuf::from), + jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd: cmd, - incremental: incremental, + incremental: matches.opt_present("incremental"), } } } diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6eb12fed5abb..5560b5b0333c 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -978,26 +978,25 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } } - pub fn print_help(&self, command: &str) { + pub fn get_help(&self, command: &str) -> Option { let kind = match command { "build" => Kind::Build, "doc" => Kind::Doc, "test" => Kind::Test, "bench" => Kind::Bench, "dist" => Kind::Dist, - _ => return, + _ => return None, }; let rules = self.rules.values().filter(|r| r.kind == kind); let rules = rules.filter(|r| !r.path.contains("nowhere")); let mut rules = rules.collect::>(); rules.sort_by_key(|r| r.path); - println!("Available paths:\n"); + let mut help_string = String::from("Available paths:\n"); for rule in rules { - print!(" ./x.py {} {}", command, rule.path); - - println!(""); + help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str()); } + Some(help_string) } /// Construct the top-level build steps that we're going to be executing, From 2c9ae48149cb714e7cfd49c038af9b54e261da44 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 1 Apr 2017 23:16:46 -0600 Subject: [PATCH 247/905] Oops, we can't parse options until all options have been defined. Tiny bit of manual arg-parsing. Fixed tidy stuff too. --- src/bootstrap/flags.rs | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index e60e279876c3..9b45246bc500 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -113,31 +113,28 @@ To learn more about a subcommand, run `./x.py -h`"); process::exit(exit_code); }; - // Get subcommand - let matches = opts.parse(&args[..]).unwrap_or_else(|e| { - // Invalid argument/option format - println!("\n{}\n", e); - usage(1, &opts, &subcommand_help, &extra_help); - }); - let subcommand = match matches.free.get(0) { - Some(s) => { s }, - None => { - // No subcommand -- lets only show the general usage and subcommand help in this case. + // We can't use getopt to parse the options until we have completed specifying which + // options are valid, but under the current implementation, some options are conditional on + // the subcommand. Therefore we must manually identify the subcommand first, so that we can + // complete the definition of the options. Then we can use the getopt::Matches object from + // there on out. + let mut possible_subcommands = args.iter().collect::>(); + possible_subcommands.retain(|&s| !s.starts_with('-')); + let subcommand = match possible_subcommands.first() { + Some(s) => s, + None => { + // No subcommand -- show the general usage and subcommand help println!("{}\n", subcommand_help); process::exit(0); } }; - // Get any optional paths which occur after the subcommand - let cwd = t!(env::current_dir()); - let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); - // Some subcommands have specific arguments help text match subcommand.as_str() { "build" => { subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of paths to directories to the crates + This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: ./x.py build src/libcore @@ -195,6 +192,17 @@ Arguments: _ => { } }; + // Done specifying what options are possible, so do the getopts parsing + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + // Get any optional paths which occur after the subcommand + let cwd = t!(env::current_dir()); + let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); + + // All subcommands can have an optional "Available paths" section if matches.opt_present("verbose") { let flags = Flags::parse(&["build".to_string()]); From 6b7258670f606e6951e3ad34c02a598d595dfa6e Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 2 Apr 2017 10:28:36 -0600 Subject: [PATCH 248/905] Simplify a "use" statement as per @grunweg's feedback. --- src/bootstrap/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 9b45246bc500..c374d27fe4f3 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; use std::process; -use getopts::{Options}; +use getopts::Options; use Build; use config::Config; From 1e5389853ca3a99a338f3a40cbb96150f711410c Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 2 Apr 2017 13:11:53 -0600 Subject: [PATCH 249/905] Fix breaking the 'clean' subcommand caused replacing a single-letter variable with the same value in two contexts where it was used differently. That's why you don't use "m" as a variable for hundreds of lines in an outer function, and re-use it in closures several times in the same function. Sheesh. --- src/bootstrap/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c374d27fe4f3..2e133664a05b 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -244,7 +244,7 @@ Arguments: Subcommand::Doc { paths: paths } } "clean" => { - if matches.free.len() > 0 { + if paths.len() > 0 { println!("\nclean takes no arguments\n"); usage(1, &opts, &subcommand_help, &extra_help); } From efd6eab366ad44ac6e9b0b12cd4b9688ab71df6d Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 2 Apr 2017 16:26:43 -0600 Subject: [PATCH 250/905] Handle symlinks in src/bootstrap/clean.rs (mostly) -- resolves #40860. The broken condition can be replicated with: ``shell export MYARCH=x86_64-apple-darwin && mkdir -p build/$MYARCH/subdir && touch build/$MYARCH/subdir/file && ln -s build/$MYARCH/subdir/file build/$MYARCH/subdir/symlink `` `src/bootstrap/clean.rs` has a custom implementation of removing a tree `fn rm_rf` that used `std::path::Path::{is_file, is_dir, exists}` while recursively deleting directories and files. Unfortunately, `Path`'s implementation of `is_file()` and `is_dir()` and `exists()` always unconditionally follow symlinks, which is the exact opposite of standard implementations of deleting file trees. It appears that this custom implementation is being used to workaround a behavior in Windows where the files often get marked as read-only, which prevents us from simply using something nice and simple like `std::fs::remove_dir_all`, which properly deletes links instead of following them. So it looks like the fix is to use `.symlink_metadata()` to figure out whether tree items are files/symlinks/directories. The one corner case this won't cover is if there is a broken symlink in the "root" `build/$MYARCH` directory, because those initial entries are run through `Path::canonicalize()`, which panics with broken symlinks. So lets just never use symlinks in that one directory. :-) --- src/bootstrap/clean.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index e9547ee42d07..308a0ab3076d 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -44,26 +44,25 @@ pub fn clean(build: &Build) { } fn rm_rf(path: &Path) { - if !path.exists() { - return - } - if path.is_file() { - return do_op(path, "remove file", |p| fs::remove_file(p)); - } + match path.symlink_metadata() { + Err(e) => { + if e.kind() == ErrorKind::NotFound { + return; + } + panic!("failed to get metadata for file {}: {}", path.display(), e); + }, + Ok(metadata) => { + if metadata.file_type().is_file() || metadata.file_type().is_symlink() { + do_op(path, "remove file", |p| fs::remove_file(p)); + return; + } - for file in t!(fs::read_dir(path)) { - let file = t!(file).path(); - - if file.is_dir() { - rm_rf(&file); - } else { - // On windows we can't remove a readonly file, and git will - // often clone files as readonly. As a result, we have some - // special logic to remove readonly files on windows. - do_op(&file, "remove file", |p| fs::remove_file(p)); - } - } - do_op(path, "remove dir", |p| fs::remove_dir(p)); + for file in t!(fs::read_dir(path)) { + rm_rf(&t!(file).path()); + } + do_op(path, "remove dir", |p| fs::remove_dir(p)); + }, + }; } fn do_op(path: &Path, desc: &str, mut f: F) @@ -71,9 +70,12 @@ fn do_op(path: &Path, desc: &str, mut f: F) { match f(path) { Ok(()) => {} + // On windows we can't remove a readonly file, and git will often clone files as readonly. + // As a result, we have some special logic to remove readonly files on windows. + // This is also the reason that we can't use things like fs::remove_dir_all(). Err(ref e) if cfg!(windows) && e.kind() == ErrorKind::PermissionDenied => { - let mut p = t!(path.metadata()).permissions(); + let mut p = t!(path.symlink_metadata()).permissions(); p.set_readonly(false); t!(fs::set_permissions(path, p)); f(path).unwrap_or_else(|e| { From 29a6a9e8d23e9dc178851f0bc49e2b46afcc8c49 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 3 Apr 2017 02:03:12 +0200 Subject: [PATCH 251/905] iter: Use underlying find/rfind for the same methods in Rev --- src/libcore/iter/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 04394e0a3a87..273f9d0e6f6d 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -358,12 +358,24 @@ impl Iterator for Rev where I: DoubleEndedIterator { fn next(&mut self) -> Option<::Item> { self.iter.next_back() } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + fn find

    (&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.rfind(predicate) + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option<::Item> { self.iter.next() } + + fn rfind

    (&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.find(predicate) + } } #[stable(feature = "rust1", since = "1.0.0")] From 74f8ea263e119f947264f373229a8f1a940ae877 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 3 Apr 2017 02:03:12 +0200 Subject: [PATCH 252/905] iter: Simplification in rfind's provided implementation - Prefer simpler constructs instead of going through &mut I's Iterator implementation. --- src/libcore/iter/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 34f14ef53f89..798dda199281 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -467,7 +467,7 @@ pub trait DoubleEndedIterator: Iterator { Self: Sized, P: FnMut(&Self::Item) -> bool { - for x in self.by_ref().rev() { + while let Some(x) = self.next_back() { if predicate(&x) { return Some(x) } } None From 7b89bd7ccacd0908d7e22a5cf383c8cc147bc3d5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 31 Mar 2017 13:52:46 +0100 Subject: [PATCH 253/905] Add ptr::offset_to --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/offset-to.md | 7 +++ src/libcollections/lib.rs | 1 + src/libcollections/vec.rs | 12 ++-- src/libcore/ptr.rs | 76 ++++++++++++++++++++++++++ src/libcore/slice/mod.rs | 7 ++- 6 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 src/doc/unstable-book/src/offset-to.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index fe491d7f9018..0c3b7990c93b 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -123,6 +123,7 @@ - [no_debug](no-debug.md) - [non_ascii_idents](non-ascii-idents.md) - [nonzero](nonzero.md) +- [offset_to](offset-to.md) - [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md) - [on_unimplemented](on-unimplemented.md) - [once_poison](once-poison.md) diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md new file mode 100644 index 000000000000..376f3ff5d219 --- /dev/null +++ b/src/doc/unstable-book/src/offset-to.md @@ -0,0 +1,7 @@ +# `offset_to` + +The tracking issue for this feature is: [#0] + +[#0]: https://github.com/rust-lang/rust/issues/0 + +------------------------ diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 72e950bc91fa..2b345e3d0a59 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -61,6 +61,7 @@ #![feature(unique)] #![feature(untagged_unions)] #![cfg_attr(test, feature(rand, test))] +#![feature(offset_to)] #![no_std] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e0034..f12380a9ea53 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2073,14 +2073,10 @@ impl Iterator for IntoIter { #[inline] fn size_hint(&self) -> (usize, Option) { - let diff = (self.end as usize) - (self.ptr as usize); - let size = mem::size_of::(); - let exact = diff / - (if size == 0 { - 1 - } else { - size - }); + 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), + }; (exact, Some(exact)) } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d2830a6d00ce..6bcce76af04e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -500,6 +500,44 @@ impl *const T { intrinsics::arith_offset(self, count) } } + + /// 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 ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "0")] + #[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) + } + } } #[lang = "mut_ptr"] @@ -653,6 +691,44 @@ impl *mut T { Some(&mut *self) } } + + /// 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 ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "0")] + #[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) + } + } } // Equality for pointers diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index af492b3c6397..5a978ccc7415 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1502,9 +1502,10 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} // Return the arithmetic difference if `T` is zero size. #[inline(always)] fn ptrdistance(start: *const T, end: *const T) -> usize { - let diff = (end as usize).wrapping_sub(start as usize); - let size = mem::size_of::(); - diff / (if size == 0 { 1 } else { size }) + match start.offset_to(end) { + Some(x) => x as usize, + None => (end as usize).wrapping_sub(start as usize), + } } // Extension methods for raw pointers, used by the iterators From 282029526646fc93cd8bc098191c4e110a4c4938 Mon Sep 17 00:00:00 2001 From: "Stephen M. Coakley" Date: Sat, 1 Apr 2017 22:17:59 -0500 Subject: [PATCH 254/905] Derive Hash for ThreadId + better example --- src/libstd/thread/mod.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index edf928d61063..21f9757ad116 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -652,8 +652,8 @@ pub fn park_timeout(dur: Duration) { /// A unique identifier for a running thread. /// /// A `ThreadId` is an opaque object that has a unique value for each thread -/// that creates one. `ThreadId`s do not correspond to a thread's system- -/// designated identifier. +/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's +/// system-designated identifier. /// /// # Examples /// @@ -662,17 +662,15 @@ pub fn park_timeout(dur: Duration) { /// /// use std::thread; /// -/// let handler = thread::Builder::new() -/// .spawn(|| { -/// let thread = thread::current(); -/// let thread_id = thread.id(); -/// }) -/// .unwrap(); +/// let other_thread = thread::spawn(|| { +/// thread::current().id() +/// }); /// -/// handler.join().unwrap(); +/// let other_thread_id = other_thread.join().unwrap(); +/// assert!(thread::current().id() != other_thread_id); /// ``` #[unstable(feature = "thread_id", issue = "21507")] -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Clone, Copy, Eq, PartialEq, Hash)] pub struct ThreadId(u64); impl ThreadId { @@ -795,14 +793,12 @@ impl Thread { /// /// use std::thread; /// - /// let handler = thread::Builder::new() - /// .spawn(|| { - /// let thread = thread::current(); - /// println!("thread id: {:?}", thread.id()); - /// }) - /// .unwrap(); + /// let other_thread = thread::spawn(|| { + /// thread::current().id() + /// }); /// - /// handler.join().unwrap(); + /// let other_thread_id = other_thread.join().unwrap(); + /// assert!(thread::current().id() != other_thread_id); /// ``` #[unstable(feature = "thread_id", issue = "21507")] pub fn id(&self) -> ThreadId { From 79efca10934b3ea0a172db0ab514fdd72ddeacfb Mon Sep 17 00:00:00 2001 From: Dylan Maccora Date: Mon, 3 Apr 2017 07:57:20 +1000 Subject: [PATCH 255/905] Wrapped to 80 characters. Fix links. --- src/libcore/convert.rs | 94 +++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 5546d2a13c47..19cd2d3398f3 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -26,16 +26,16 @@ //! As a library author, you should prefer implementing [`From`][`From`] or //! [`TryFrom`][`TryFrom`] rather than [`Into`][`Into`] or [`TryInto`][`TryInto`], //! as [`From`] and [`TryFrom`] provide greater flexibility and offer -//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a blanket implementation -//! in the standard library. +//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a +//! blanket implementation in the standard library. //! //! # Generic Implementations //! //! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference //! - [`From`]` for T` implies [`Into`]` for U` //! - [`TryFrom`]` for T` implies [`TryInto`]` for U` -//! - [`From`] and [`Into`] are reflexive, which means that all types can `into()` -//! themselves and `from()` themselves +//! - [`From`] and [`Into`] are reflexive, which means that all types can +//! `into()` themselves and `from()` themselves //! //! See each trait for usage examples. //! @@ -50,26 +50,31 @@ use str::FromStr; -/// A cheap reference-to-reference conversion. Used to convert a value to a reference value -/// within generic code. +/// A cheap reference-to-reference conversion. Used to convert a value to a +/// reference value within generic code. /// -/// `AsRef` is very similar to, but serves a slightly different purpose than, [`Borrow`]. +/// `AsRef` is very similar to, but serves a slightly different purpose than, +/// [`Borrow`]. /// -/// `AsRef` is to be used when wishing to convert to a reference of another type. -/// `Borrow` is more related to the notion of taking the reference. It is useful when wishing to abstract -/// over the type of reference (`&T`, `&mut T`) or allow both the referenced and owned type to be treated in the same manner. +/// `AsRef` is to be used when wishing to convert to a reference of another +/// type. +/// `Borrow` is more related to the notion of taking the reference. It is +/// useful when wishing to abstract +/// over the type of reference (`&T`, `&mut T`) or allow both the referenced +/// and owned type to be treated in the same manner. /// 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 `Borrow` when goal is related to writing code that is agnostic to the +/// type of borrow and if is reference or value /// /// See [the book][book] for a more detailed comparison. /// /// [book]: ../../book/borrow-and-asref.html /// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an [`Option`] or a [`Result`]. +/// **Note: this trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html @@ -77,12 +82,13 @@ use str::FromStr; /// # Generic Implementations /// /// - `AsRef` 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`) +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) /// /// # Examples /// An example implementation of the trait is [`Path`]. /// -/// [`Path`]: ../../std/struct.Path.html +/// [`Path`]: ../../std/path/struct.Path.html /// /// ``` /// impl AsRef for str { @@ -119,8 +125,8 @@ pub trait AsRef { /// /// This trait is similar to `AsRef` but used for converting mutable references. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an [`Option`] or a [`Result`]. +/// **Note: this trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html @@ -128,7 +134,8 @@ 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`) +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) /// /// # Examples /// @@ -161,14 +168,17 @@ pub trait AsMut { fn as_mut(&mut self) -> &mut T; } -/// A conversion that consumes `self`, which may or may not be expensive. The reciprocal of [`From`][From]. +/// A conversion that consumes `self`, which may or may not be expensive. The +/// reciprocal of [`From`][From]. /// -/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated -/// method which returns an [`Option`] or a [`Result`]. +/// **Note: this trait must not fail**. If the conversion can fail, use +/// [`TryInto`] or a dedicated method which returns an [`Option`] or a +/// [`Result`]. /// -/// Library authors should not directly implement this trait, but should prefer implementing -/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into` -/// implementation for free, thanks to a blanket implementation in the standard library. +/// Library authors should not directly implement this trait, but should prefer +/// implementing the [`From`][From] trait, which offers greater flexibility and +/// provides an equivalent `Into` implementation for free, thanks to a blanket +/// implementation in the standard library. /// /// # Generic Implementations /// @@ -202,18 +212,24 @@ pub trait Into: Sized { fn into(self) -> T; } -/// Simple and safe type conversions in to `Self`. It is the reciprocal of `Into`. +/// Simple and safe type conversions in to `Self`. It is the reciprocal of +/// `Into`. /// -/// This trait is useful when performing error handling as described by [the book][book] and is closely related to the `?` operator. +/// This trait is useful when performing error handling as described by +/// [the book][book] and is closely related to the `?` operator. /// -/// When constructing a function that is capable of failing the return type will generally be of the form `Result`. -/// The `From` trait allows for simplification of error handling by providing a means of returning a single error type that encapsulates -/// numerous possible erroneous situations. -/// This trait is not limited to error handling, rather the general case for this trait would be in any type conversions to have an -/// explicit definition of how they are performed. +/// When constructing a function that is capable of failing the return type +/// will generally be of the form `Result`. +/// The `From` trait allows for simplification of error handling by providing a +/// means of returning a single error type that encapsulates numerous possible +/// erroneous situations. +/// This trait is not limited to error handling, rather the general case for +/// this trait would be in any type conversions to have an explicit definition +/// of how they are performed. /// -/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated -/// method which returns an [`Option`] or a [`Result`]. +/// **Note: this trait must not fail**. If the conversion can fail, use +/// [`TryFrom`] or a dedicated method which returns an [`Option`] or a +/// [`Result`]. /// /// # Generic Implementations /// @@ -265,7 +281,7 @@ pub trait Into: Sized { /// [`String`]: ../../std/string/struct.String.html /// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from -/// [book]: ../../book/error-handling.html#the-from-trait +/// [book]: ../../book/error-handling.html #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. @@ -273,11 +289,13 @@ pub trait From: Sized { fn from(T) -> Self; } -/// An attempted conversion that consumes `self`, which may or may not be expensive. +/// An attempted conversion that consumes `self`, which may or may not be +/// expensive. /// -/// Library authors should not directly implement this trait, but should prefer implementing -/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto` -/// implementation for free, thanks to a blanket implementation in the standard library. +/// Library authors should not directly implement this trait, but should prefer +/// implementing the [`TryFrom`] trait, which offers greater flexibility and +/// provides an equivalent `TryInto` implementation for free, thanks to a +/// blanket implementation in the standard library. /// /// [`TryFrom`]: trait.TryFrom.html #[unstable(feature = "try_from", issue = "33417")] From 9c1b7ae3f37a34a39f837ad8ae90da3fad052798 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Mon, 3 Apr 2017 10:14:10 -0400 Subject: [PATCH 256/905] Revert "Implement AsRawFd/IntoRawFd for RawFd" This reverts commit 2cf686f2cdd6446a3cd47df0305ead40fabe85df (#40842) RawFd is a type alias for c_int, which is itself a type alias for i32. As a result, adding AsRawFd and IntoRawFd impls for RawFd actually adds them for i32. As a result, the reverted commit makes this valid: ``` use std::os::unix::io::AsRawFd; fn arf(_: T) {} fn main() { arf(32i32) } ``` Implimenting AsRawFd and IntoRawFd for i32 breaks the promises of both those traits that their methods return a valid RawFd. r? @aturon cc @Mic92 @kamalmarhubi --- src/libstd/sys/unix/ext/io.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 75aa72e3cff8..296235e173d1 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -72,13 +72,6 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for RawFd { - fn as_raw_fd(&self) -> RawFd { - *self - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -91,14 +84,6 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for RawFd { - fn into_raw_fd(self) -> RawFd { - self - } -} - #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { fn into_raw_fd(self) -> RawFd { From f74ca38686e84542657136bd063f8042d9bbb641 Mon Sep 17 00:00:00 2001 From: mandeep Date: Mon, 3 Apr 2017 09:51:34 -0500 Subject: [PATCH 257/905] Refactored swap_remove doc comment upon discussing with BurntSushi and steveklabnik --- src/libcollections/vec.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 44ac4f1cff58..8a3fa94d4c1e 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -678,8 +678,9 @@ impl Vec { self.len = len; } - /// Removes an element from anywhere in the vector and returns it, replacing - /// it with the last element. + /// Removes an element from the vector and returns it. + /// + /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is O(1). /// From e7c2160f8a36468c38a0c4d9fb2a71bd6c4fefd8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Mar 2017 18:32:17 +0100 Subject: [PATCH 258/905] Fix mutex's docs inconsistency --- src/libstd/sync/mutex.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index d79be2944c9e..f2c178a1ad50 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -30,7 +30,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// /// The mutexes in this module implement a strategy called "poisoning" where a /// mutex is considered poisoned whenever a thread panics while holding the -/// lock. Once a mutex is poisoned, all other threads are unable to access the +/// mutex. Once a mutex is poisoned, all other threads are unable to access the /// data by default as it is likely tainted (some invariant is not being /// upheld). /// @@ -115,7 +115,7 @@ pub struct Mutex { // Note that this mutex is in a *box*, not inlined into the struct itself. // Once a native mutex has been used once, its address can never change (it // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner lock to + // ensure that the native mutex is used correctly we box the inner mutex to // give it a constant address. inner: Box, poison: poison::Flag, @@ -183,7 +183,7 @@ impl Mutex { /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the local thread until it is available to acquire - /// the mutex. Upon returning, the thread is the only thread with the mutex + /// the mutex. Upon returning, the thread is the only thread with the lock /// held. An RAII guard is returned to allow scoped unlock of the lock. When /// the guard goes out of scope, the mutex will be unlocked. /// @@ -267,9 +267,9 @@ impl Mutex { } } - /// Determines whether the lock is poisoned. + /// Determines whether the mutex is poisoned. /// - /// If another thread is active, the lock can still become poisoned at any + /// If another thread is active, the mutex can still become poisoned at any /// time. You should not trust a `false` value for program correctness /// without additional synchronization. /// @@ -312,7 +312,7 @@ impl Mutex { #[stable(feature = "mutex_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult where T: Sized { // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner lock. + // `self` so there's no need to lock the inner mutex. // // To get the inner value, we'd like to call `data.into_inner()`, // but because `Mutex` impl-s `Drop`, we can't move out of it, so @@ -353,7 +353,7 @@ impl Mutex { #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. + // there's no need to lock the inner mutex. let data = unsafe { &mut *self.data.get() }; poison::map_result(self.poison.borrow(), |_| data ) } From 73f6f5e0968ebe032a0730e2e3dfccea5a61c384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 3 Apr 2017 07:46:35 -0700 Subject: [PATCH 259/905] Sort enum suggestions --- src/librustc_resolve/lib.rs | 14 ++++++++------ src/test/ui/did_you_mean/issue-35675.stderr | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a39cd3b0d551..e191fadc01be 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2273,15 +2273,17 @@ impl<'a> Resolver<'a> { show_candidates(&mut err, &candidates, def.is_some()); } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); - for suggestion in enum_candidates { - let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let mut enum_candidates = enum_candidates.iter() + .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); + enum_candidates.sort(); + for (sp, variant_path, enum_path) in enum_candidates { let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", variant_path, enum_path); - if suggestion.path.span == DUMMY_SP { + if sp == DUMMY_SP { err.help(&msg); } else { - err.span_help(suggestion.path.span, &msg); + err.span_help(sp, &msg); } } } @@ -3437,7 +3439,7 @@ fn path_names_to_string(path: &Path) -> String { } /// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) { let variant_path = &suggestion.path; let variant_path_string = path_names_to_string(variant_path); @@ -3448,7 +3450,7 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) }; let enum_path_string = path_names_to_string(&enum_path); - (variant_path_string, enum_path_string) + (suggestion.path.span, variant_path_string, enum_path_string) } diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr index 43851d76029d..3d615785b25f 100644 --- a/src/test/ui/did_you_mean/issue-35675.stderr +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -46,8 +46,8 @@ error[E0573]: expected type, found variant `Ok` 24 | fn foo() -> Ok { | ^^ not a type | - = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Result::Ok`, did you mean to use `std::prelude::v1::Result`? error[E0412]: cannot find type `Variant3` in this scope --> $DIR/issue-35675.rs:28:13 @@ -67,8 +67,8 @@ error[E0573]: expected type, found variant `Some` 31 | fn qux() -> Some { | ^^^^ not a type | - = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? error: aborting due to 7 previous errors From 13c744f30d1540f36a6437224d16e3aea0a2ff71 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 3 Apr 2017 16:53:04 +0200 Subject: [PATCH 260/905] Move libXtest into libX/tests This change moves: 1. `libcoretest` into `libcore/tests` 2. `libcollectionstest` into `libcollections/tests` This is a follow-up to #39561. --- src/libcollections/Cargo.toml | 4 ++-- .../tests}/binary_heap.rs | 0 src/{libcollectionstest => libcollections/tests}/btree/map.rs | 0 src/{libcollectionstest => libcollections/tests}/btree/mod.rs | 0 src/{libcollectionstest => libcollections/tests}/btree/set.rs | 0 src/{libcollectionstest => libcollections/tests}/cow_str.rs | 0 src/{libcollectionstest => libcollections/tests}/fmt.rs | 0 src/{libcollectionstest => libcollections/tests}/lib.rs | 0 .../tests}/linked_list.rs | 0 src/{libcollectionstest => libcollections/tests}/slice.rs | 0 src/{libcollectionstest => libcollections/tests}/str.rs | 0 src/{libcollectionstest => libcollections/tests}/string.rs | 0 src/{libcollectionstest => libcollections/tests}/vec.rs | 0 src/{libcollectionstest => libcollections/tests}/vec_deque.rs | 0 src/libcore/Cargo.toml | 4 ++-- src/libcore/num/bignum.rs | 2 +- src/libcore/num/diy_float.rs | 2 +- src/libcore/num/flt2dec/mod.rs | 2 +- src/libcore/num/mod.rs | 2 +- src/{libcoretest => libcore/tests}/any.rs | 0 src/{libcoretest => libcore/tests}/array.rs | 0 src/{libcoretest => libcore/tests}/atomic.rs | 0 src/{libcoretest => libcore/tests}/cell.rs | 0 src/{libcoretest => libcore/tests}/char.rs | 0 src/{libcoretest => libcore/tests}/clone.rs | 0 src/{libcoretest => libcore/tests}/cmp.rs | 0 src/{libcoretest => libcore/tests}/fmt/builders.rs | 0 src/{libcoretest => libcore/tests}/fmt/float.rs | 0 src/{libcoretest => libcore/tests}/fmt/mod.rs | 0 src/{libcoretest => libcore/tests}/fmt/num.rs | 0 src/{libcoretest => libcore/tests}/hash/mod.rs | 0 src/{libcoretest => libcore/tests}/hash/sip.rs | 0 src/{libcoretest => libcore/tests}/intrinsics.rs | 0 src/{libcoretest => libcore/tests}/iter.rs | 0 src/{libcoretest => libcore/tests}/lib.rs | 0 src/{libcoretest => libcore/tests}/mem.rs | 0 src/{libcoretest => libcore/tests}/nonzero.rs | 0 src/{libcoretest => libcore/tests}/num/bignum.rs | 0 src/{libcoretest => libcore/tests}/num/dec2flt/mod.rs | 0 src/{libcoretest => libcore/tests}/num/dec2flt/parse.rs | 0 src/{libcoretest => libcore/tests}/num/dec2flt/rawfp.rs | 0 src/{libcoretest => libcore/tests}/num/flt2dec/estimator.rs | 0 src/{libcoretest => libcore/tests}/num/flt2dec/mod.rs | 0 .../tests}/num/flt2dec/strategy/dragon.rs | 0 .../tests}/num/flt2dec/strategy/grisu.rs | 0 src/{libcoretest => libcore/tests}/num/i16.rs | 0 src/{libcoretest => libcore/tests}/num/i32.rs | 0 src/{libcoretest => libcore/tests}/num/i64.rs | 0 src/{libcoretest => libcore/tests}/num/i8.rs | 0 src/{libcoretest => libcore/tests}/num/int_macros.rs | 0 src/{libcoretest => libcore/tests}/num/mod.rs | 0 src/{libcoretest => libcore/tests}/num/u16.rs | 0 src/{libcoretest => libcore/tests}/num/u32.rs | 0 src/{libcoretest => libcore/tests}/num/u64.rs | 0 src/{libcoretest => libcore/tests}/num/u8.rs | 0 src/{libcoretest => libcore/tests}/num/uint_macros.rs | 0 src/{libcoretest => libcore/tests}/ops.rs | 0 src/{libcoretest => libcore/tests}/option.rs | 0 src/{libcoretest => libcore/tests}/ptr.rs | 0 src/{libcoretest => libcore/tests}/result.rs | 0 src/{libcoretest => libcore/tests}/slice.rs | 0 src/{libcoretest => libcore/tests}/str.rs | 2 +- src/{libcoretest => libcore/tests}/tuple.rs | 0 src/tools/tidy/src/pal.rs | 2 +- 64 files changed, 10 insertions(+), 10 deletions(-) rename src/{libcollectionstest => libcollections/tests}/binary_heap.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/map.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/mod.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/set.rs (100%) rename src/{libcollectionstest => libcollections/tests}/cow_str.rs (100%) rename src/{libcollectionstest => libcollections/tests}/fmt.rs (100%) rename src/{libcollectionstest => libcollections/tests}/lib.rs (100%) rename src/{libcollectionstest => libcollections/tests}/linked_list.rs (100%) rename src/{libcollectionstest => libcollections/tests}/slice.rs (100%) rename src/{libcollectionstest => libcollections/tests}/str.rs (100%) rename src/{libcollectionstest => libcollections/tests}/string.rs (100%) rename src/{libcollectionstest => libcollections/tests}/vec.rs (100%) rename src/{libcollectionstest => libcollections/tests}/vec_deque.rs (100%) rename src/{libcoretest => libcore/tests}/any.rs (100%) rename src/{libcoretest => libcore/tests}/array.rs (100%) rename src/{libcoretest => libcore/tests}/atomic.rs (100%) rename src/{libcoretest => libcore/tests}/cell.rs (100%) rename src/{libcoretest => libcore/tests}/char.rs (100%) rename src/{libcoretest => libcore/tests}/clone.rs (100%) rename src/{libcoretest => libcore/tests}/cmp.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/builders.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/float.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/mod.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/num.rs (100%) rename src/{libcoretest => libcore/tests}/hash/mod.rs (100%) rename src/{libcoretest => libcore/tests}/hash/sip.rs (100%) rename src/{libcoretest => libcore/tests}/intrinsics.rs (100%) rename src/{libcoretest => libcore/tests}/iter.rs (100%) rename src/{libcoretest => libcore/tests}/lib.rs (100%) rename src/{libcoretest => libcore/tests}/mem.rs (100%) rename src/{libcoretest => libcore/tests}/nonzero.rs (100%) rename src/{libcoretest => libcore/tests}/num/bignum.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/parse.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/rawfp.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/estimator.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/strategy/dragon.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/strategy/grisu.rs (100%) rename src/{libcoretest => libcore/tests}/num/i16.rs (100%) rename src/{libcoretest => libcore/tests}/num/i32.rs (100%) rename src/{libcoretest => libcore/tests}/num/i64.rs (100%) rename src/{libcoretest => libcore/tests}/num/i8.rs (100%) rename src/{libcoretest => libcore/tests}/num/int_macros.rs (100%) rename src/{libcoretest => libcore/tests}/num/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/u16.rs (100%) rename src/{libcoretest => libcore/tests}/num/u32.rs (100%) rename src/{libcoretest => libcore/tests}/num/u64.rs (100%) rename src/{libcoretest => libcore/tests}/num/u8.rs (100%) rename src/{libcoretest => libcore/tests}/num/uint_macros.rs (100%) rename src/{libcoretest => libcore/tests}/ops.rs (100%) rename src/{libcoretest => libcore/tests}/option.rs (100%) rename src/{libcoretest => libcore/tests}/ptr.rs (100%) rename src/{libcoretest => libcore/tests}/result.rs (100%) rename src/{libcoretest => libcore/tests}/slice.rs (100%) rename src/{libcoretest => libcore/tests}/str.rs (90%) rename src/{libcoretest => libcore/tests}/tuple.rs (100%) diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 02b2171a224d..7e92404bc0d6 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -13,8 +13,8 @@ core = { path = "../libcore" } std_unicode = { path = "../libstd_unicode" } [[test]] -name = "collectionstest" -path = "../libcollectionstest/lib.rs" +name = "collectionstests" +path = "../libcollections/tests/lib.rs" [[bench]] name = "collectionsbenches" diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollections/tests/binary_heap.rs similarity index 100% rename from src/libcollectionstest/binary_heap.rs rename to src/libcollections/tests/binary_heap.rs diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollections/tests/btree/map.rs similarity index 100% rename from src/libcollectionstest/btree/map.rs rename to src/libcollections/tests/btree/map.rs diff --git a/src/libcollectionstest/btree/mod.rs b/src/libcollections/tests/btree/mod.rs similarity index 100% rename from src/libcollectionstest/btree/mod.rs rename to src/libcollections/tests/btree/mod.rs diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollections/tests/btree/set.rs similarity index 100% rename from src/libcollectionstest/btree/set.rs rename to src/libcollections/tests/btree/set.rs diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollections/tests/cow_str.rs similarity index 100% rename from src/libcollectionstest/cow_str.rs rename to src/libcollections/tests/cow_str.rs diff --git a/src/libcollectionstest/fmt.rs b/src/libcollections/tests/fmt.rs similarity index 100% rename from src/libcollectionstest/fmt.rs rename to src/libcollections/tests/fmt.rs diff --git a/src/libcollectionstest/lib.rs b/src/libcollections/tests/lib.rs similarity index 100% rename from src/libcollectionstest/lib.rs rename to src/libcollections/tests/lib.rs diff --git a/src/libcollectionstest/linked_list.rs b/src/libcollections/tests/linked_list.rs similarity index 100% rename from src/libcollectionstest/linked_list.rs rename to src/libcollections/tests/linked_list.rs diff --git a/src/libcollectionstest/slice.rs b/src/libcollections/tests/slice.rs similarity index 100% rename from src/libcollectionstest/slice.rs rename to src/libcollections/tests/slice.rs diff --git a/src/libcollectionstest/str.rs b/src/libcollections/tests/str.rs similarity index 100% rename from src/libcollectionstest/str.rs rename to src/libcollections/tests/str.rs diff --git a/src/libcollectionstest/string.rs b/src/libcollections/tests/string.rs similarity index 100% rename from src/libcollectionstest/string.rs rename to src/libcollections/tests/string.rs diff --git a/src/libcollectionstest/vec.rs b/src/libcollections/tests/vec.rs similarity index 100% rename from src/libcollectionstest/vec.rs rename to src/libcollections/tests/vec.rs diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollections/tests/vec_deque.rs similarity index 100% rename from src/libcollectionstest/vec_deque.rs rename to src/libcollections/tests/vec_deque.rs diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index e847c7fa3a0e..5af63aa970f2 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -10,8 +10,8 @@ test = false bench = false [[test]] -name = "coretest" -path = "../libcoretest/lib.rs" +name = "coretests" +path = "../libcore/tests/lib.rs" [[bench]] name = "corebenches" diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 8904322ca48f..b5553fb29475 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -19,7 +19,7 @@ //! inputs, but we don't do so to avoid the code bloat. Each bignum is still //! tracked for the actual usages, so it normally doesn't matter. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_bignum", diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs index 11eea753f93f..6635d95155f4 100644 --- a/src/libcore/num/diy_float.rs +++ b/src/libcore/num/diy_float.rs @@ -10,7 +10,7 @@ //! Extended precision "soft float", for internal use only. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_diy_float", diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index f6c03a59f81e..5123e42df61c 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -118,7 +118,7 @@ provide a large enough buffer and `Part` array, and to assemble the final string from resulting `Part`s itself. All algorithms and formatting functions are accompanied by extensive tests -in `coretest::num::flt2dec` module. It also shows how to use individual +in `coretests::num::flt2dec` module. It also shows how to use individual functions. */ diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index df343c9d45f2..f665cfdee77a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -90,7 +90,7 @@ impl fmt::UpperHex for Wrapping { mod wrapping; -// All these modules are technically private and only exposed for libcoretest: +// All these modules are technically private and only exposed for coretests: pub mod flt2dec; pub mod dec2flt; pub mod bignum; diff --git a/src/libcoretest/any.rs b/src/libcore/tests/any.rs similarity index 100% rename from src/libcoretest/any.rs rename to src/libcore/tests/any.rs diff --git a/src/libcoretest/array.rs b/src/libcore/tests/array.rs similarity index 100% rename from src/libcoretest/array.rs rename to src/libcore/tests/array.rs diff --git a/src/libcoretest/atomic.rs b/src/libcore/tests/atomic.rs similarity index 100% rename from src/libcoretest/atomic.rs rename to src/libcore/tests/atomic.rs diff --git a/src/libcoretest/cell.rs b/src/libcore/tests/cell.rs similarity index 100% rename from src/libcoretest/cell.rs rename to src/libcore/tests/cell.rs diff --git a/src/libcoretest/char.rs b/src/libcore/tests/char.rs similarity index 100% rename from src/libcoretest/char.rs rename to src/libcore/tests/char.rs diff --git a/src/libcoretest/clone.rs b/src/libcore/tests/clone.rs similarity index 100% rename from src/libcoretest/clone.rs rename to src/libcore/tests/clone.rs diff --git a/src/libcoretest/cmp.rs b/src/libcore/tests/cmp.rs similarity index 100% rename from src/libcoretest/cmp.rs rename to src/libcore/tests/cmp.rs diff --git a/src/libcoretest/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs similarity index 100% rename from src/libcoretest/fmt/builders.rs rename to src/libcore/tests/fmt/builders.rs diff --git a/src/libcoretest/fmt/float.rs b/src/libcore/tests/fmt/float.rs similarity index 100% rename from src/libcoretest/fmt/float.rs rename to src/libcore/tests/fmt/float.rs diff --git a/src/libcoretest/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs similarity index 100% rename from src/libcoretest/fmt/mod.rs rename to src/libcore/tests/fmt/mod.rs diff --git a/src/libcoretest/fmt/num.rs b/src/libcore/tests/fmt/num.rs similarity index 100% rename from src/libcoretest/fmt/num.rs rename to src/libcore/tests/fmt/num.rs diff --git a/src/libcoretest/hash/mod.rs b/src/libcore/tests/hash/mod.rs similarity index 100% rename from src/libcoretest/hash/mod.rs rename to src/libcore/tests/hash/mod.rs diff --git a/src/libcoretest/hash/sip.rs b/src/libcore/tests/hash/sip.rs similarity index 100% rename from src/libcoretest/hash/sip.rs rename to src/libcore/tests/hash/sip.rs diff --git a/src/libcoretest/intrinsics.rs b/src/libcore/tests/intrinsics.rs similarity index 100% rename from src/libcoretest/intrinsics.rs rename to src/libcore/tests/intrinsics.rs diff --git a/src/libcoretest/iter.rs b/src/libcore/tests/iter.rs similarity index 100% rename from src/libcoretest/iter.rs rename to src/libcore/tests/iter.rs diff --git a/src/libcoretest/lib.rs b/src/libcore/tests/lib.rs similarity index 100% rename from src/libcoretest/lib.rs rename to src/libcore/tests/lib.rs diff --git a/src/libcoretest/mem.rs b/src/libcore/tests/mem.rs similarity index 100% rename from src/libcoretest/mem.rs rename to src/libcore/tests/mem.rs diff --git a/src/libcoretest/nonzero.rs b/src/libcore/tests/nonzero.rs similarity index 100% rename from src/libcoretest/nonzero.rs rename to src/libcore/tests/nonzero.rs diff --git a/src/libcoretest/num/bignum.rs b/src/libcore/tests/num/bignum.rs similarity index 100% rename from src/libcoretest/num/bignum.rs rename to src/libcore/tests/num/bignum.rs diff --git a/src/libcoretest/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs similarity index 100% rename from src/libcoretest/num/dec2flt/mod.rs rename to src/libcore/tests/num/dec2flt/mod.rs diff --git a/src/libcoretest/num/dec2flt/parse.rs b/src/libcore/tests/num/dec2flt/parse.rs similarity index 100% rename from src/libcoretest/num/dec2flt/parse.rs rename to src/libcore/tests/num/dec2flt/parse.rs diff --git a/src/libcoretest/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs similarity index 100% rename from src/libcoretest/num/dec2flt/rawfp.rs rename to src/libcore/tests/num/dec2flt/rawfp.rs diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs similarity index 100% rename from src/libcoretest/num/flt2dec/estimator.rs rename to src/libcore/tests/num/flt2dec/estimator.rs diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs similarity index 100% rename from src/libcoretest/num/flt2dec/mod.rs rename to src/libcore/tests/num/flt2dec/mod.rs diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs similarity index 100% rename from src/libcoretest/num/flt2dec/strategy/dragon.rs rename to src/libcore/tests/num/flt2dec/strategy/dragon.rs diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs similarity index 100% rename from src/libcoretest/num/flt2dec/strategy/grisu.rs rename to src/libcore/tests/num/flt2dec/strategy/grisu.rs diff --git a/src/libcoretest/num/i16.rs b/src/libcore/tests/num/i16.rs similarity index 100% rename from src/libcoretest/num/i16.rs rename to src/libcore/tests/num/i16.rs diff --git a/src/libcoretest/num/i32.rs b/src/libcore/tests/num/i32.rs similarity index 100% rename from src/libcoretest/num/i32.rs rename to src/libcore/tests/num/i32.rs diff --git a/src/libcoretest/num/i64.rs b/src/libcore/tests/num/i64.rs similarity index 100% rename from src/libcoretest/num/i64.rs rename to src/libcore/tests/num/i64.rs diff --git a/src/libcoretest/num/i8.rs b/src/libcore/tests/num/i8.rs similarity index 100% rename from src/libcoretest/num/i8.rs rename to src/libcore/tests/num/i8.rs diff --git a/src/libcoretest/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs similarity index 100% rename from src/libcoretest/num/int_macros.rs rename to src/libcore/tests/num/int_macros.rs diff --git a/src/libcoretest/num/mod.rs b/src/libcore/tests/num/mod.rs similarity index 100% rename from src/libcoretest/num/mod.rs rename to src/libcore/tests/num/mod.rs diff --git a/src/libcoretest/num/u16.rs b/src/libcore/tests/num/u16.rs similarity index 100% rename from src/libcoretest/num/u16.rs rename to src/libcore/tests/num/u16.rs diff --git a/src/libcoretest/num/u32.rs b/src/libcore/tests/num/u32.rs similarity index 100% rename from src/libcoretest/num/u32.rs rename to src/libcore/tests/num/u32.rs diff --git a/src/libcoretest/num/u64.rs b/src/libcore/tests/num/u64.rs similarity index 100% rename from src/libcoretest/num/u64.rs rename to src/libcore/tests/num/u64.rs diff --git a/src/libcoretest/num/u8.rs b/src/libcore/tests/num/u8.rs similarity index 100% rename from src/libcoretest/num/u8.rs rename to src/libcore/tests/num/u8.rs diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs similarity index 100% rename from src/libcoretest/num/uint_macros.rs rename to src/libcore/tests/num/uint_macros.rs diff --git a/src/libcoretest/ops.rs b/src/libcore/tests/ops.rs similarity index 100% rename from src/libcoretest/ops.rs rename to src/libcore/tests/ops.rs diff --git a/src/libcoretest/option.rs b/src/libcore/tests/option.rs similarity index 100% rename from src/libcoretest/option.rs rename to src/libcore/tests/option.rs diff --git a/src/libcoretest/ptr.rs b/src/libcore/tests/ptr.rs similarity index 100% rename from src/libcoretest/ptr.rs rename to src/libcore/tests/ptr.rs diff --git a/src/libcoretest/result.rs b/src/libcore/tests/result.rs similarity index 100% rename from src/libcoretest/result.rs rename to src/libcore/tests/result.rs diff --git a/src/libcoretest/slice.rs b/src/libcore/tests/slice.rs similarity index 100% rename from src/libcoretest/slice.rs rename to src/libcore/tests/slice.rs diff --git a/src/libcoretest/str.rs b/src/libcore/tests/str.rs similarity index 90% rename from src/libcoretest/str.rs rename to src/libcore/tests/str.rs index b7d9ba4463d9..08daafccc540 100644 --- a/src/libcoretest/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 libcollectiontest::str +// All `str` tests live in collectionstests::str diff --git a/src/libcoretest/tuple.rs b/src/libcore/tests/tuple.rs similarity index 100% rename from src/libcoretest/tuple.rs rename to src/libcore/tests/tuple.rs diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 3808c05c6b93..0dbf0d4316ab 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -75,7 +75,7 @@ const EXCEPTION_PATHS: &'static [&'static str] = &[ "src/libtest", // Probably should defer to unstable std::sys APIs // std testing crates, ok for now at least - "src/libcoretest", + "src/libcore/tests", // non-std crates "src/test", From 7a07a73eb15d497efcd544ec6e332160ee46dd5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 3 Apr 2017 21:17:47 +0200 Subject: [PATCH 261/905] Replace ^ with html balise --- src/libcore/intrinsics.rs | 6 +++--- src/libcore/num/dec2flt/rawfp.rs | 13 +++++++------ src/librustc/ty/layout.rs | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ae8b6bb4511..d8db450fb1c1 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1253,17 +1253,17 @@ extern "rust-intrinsic" { #[cfg(not(stage0))] pub fn unchecked_shr(x: T, y: T) -> T; - /// Returns (a + b) mod 2^N, where N is the width of T in bits. + /// Returns (a + b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) pub fn overflowing_add(a: T, b: T) -> T; - /// Returns (a - b) mod 2^N, where N is the width of T in bits. + /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) pub fn overflowing_sub(a: T, b: T) -> T; - /// Returns (a * b) mod 2^N, where N is the width of T in bits. + /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index e3b58b6cc7ce..45fa721a5a33 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -10,12 +10,12 @@ //! Bit fiddling on positive IEEE 754 floats. Negative numbers aren't and needn't be handled. //! Normal floating point numbers have a canonical representation as (frac, exp) such that the -//! value is 2^exp * (1 + sum(frac[N-i] / 2^i)) where N is the number of bits. Subnormals are -//! slightly different and weird, but the same principle applies. +//! value is 2exp * (1 + sum(frac[N-i] / 2i)) where N is the number of bits. +//! Subnormals are slightly different and weird, but the same principle applies. //! -//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * 2^e. -//! Besides making the "hidden bit" explicit, this changes the exponent by the so-called -//! mantissa shift. +//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * +//! 2e. Besides making the "hidden bit" explicit, this changes the exponent by the +//! so-called mantissa shift. //! //! Put another way, normally floats are written as (1) but here they are written as (2): //! @@ -94,7 +94,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp /// represented, the other code in this module makes sure to never let that happen. fn from_int(x: u64) -> Self; - /// Get the value 10^e from a pre-computed table. Panics for e >= ceil_log5_of_max_sig(). + /// Get the value 10e from a pre-computed table. Panics for e >= + /// ceil_log5_of_max_sig(). fn short_fast_pow10(e: usize) -> Self; // FIXME Everything that follows should be associated constants, but taking the value of an diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 123db6e89476..571ef30b6b90 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -267,7 +267,7 @@ impl Size { /// Alignment of a type in bytes, both ABI-mandated and preferred. /// Since alignments are always powers of 2, we can pack both in one byte, -/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768. +/// giving each a nibble (4 bits) for a maximum alignment of 215 = 32768. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Align { raw: u8 From 541512b0bf71bf2d57f42a66519a927b6e2503d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Apr 2017 07:18:43 -0700 Subject: [PATCH 262/905] travis: Split all dist builders in two Previously we would use one builder on Travis to produce two sets of host compilers for two different targets. Unfortunately though we've recently increased how much we're building for each target so this is starting to take unnecessarily long (#40804). This commit splits the dist builders in two by ensuring that we only dist one target on each builder, which should take a much shorter amount of time. This should also unblock other work such as landing the RLS (#40584). --- .travis.yml | 18 ++- .../Dockerfile | 12 +- .../aarch64-linux-gnu.config | 0 .../dist-aarch64-linux/build-toolchains.sh | 37 ++++++ src/ci/docker/dist-arm-linux/Dockerfile | 9 +- .../docker/dist-arm-linux/build-toolchains.sh | 8 -- src/ci/docker/dist-armhf-linux/Dockerfile | 77 ++++++++++++ .../arm-linux-gnueabihf.config | 0 .../dist-armhf-linux/build-toolchains.sh | 37 ++++++ src/ci/docker/dist-armv7-linux/Dockerfile | 77 ++++++++++++ .../armv7-linux-gnueabihf.config | 0 .../build-toolchains.sh | 8 -- .../Dockerfile | 7 +- .../build-toolchain.sh | 0 .../Dockerfile | 1 - .../build-binutils.sh | 0 .../build-cmake.sh | 0 .../build-curl.sh | 0 .../build-gcc.sh | 0 .../build-git.sh | 0 .../build-headers.sh | 0 .../build-openssl.sh | 0 .../build-python.sh | 0 .../shared.sh | 0 src/ci/docker/dist-mips-linux/Dockerfile | 2 - src/ci/docker/dist-mips64-linux/Dockerfile | 2 - src/ci/docker/dist-mips64el-linux/Dockerfile | 31 +++++ src/ci/docker/dist-mipsel-linux/Dockerfile | 31 +++++ src/ci/docker/dist-powerpc64-linux/Dockerfile | 10 +- .../docker/dist-powerpc64le-linux/Dockerfile | 77 ++++++++++++ .../build-powerpc64le-toolchain.sh | 0 .../docker/dist-powerpc64le-linux/shared.sh | 25 ++++ .../Dockerfile | 11 +- .../build-s390x-toolchain.sh | 0 ...prevent-AS-from-complaining-about-z9.patch | 0 .../s390x-linux-gnu.config | 0 src/ci/docker/dist-x86_64-freebsd/Dockerfile | 39 ++++++ .../dist-x86_64-freebsd/build-toolchain.sh | 112 ++++++++++++++++++ src/ci/docker/dist-x86_64-linux/Dockerfile | 95 +++++++++++++++ .../dist-x86_64-linux/build-binutils.sh | 26 ++++ .../docker/dist-x86_64-linux/build-cmake.sh | 25 ++++ src/ci/docker/dist-x86_64-linux/build-curl.sh | 43 +++++++ src/ci/docker/dist-x86_64-linux/build-gcc.sh | 33 ++++++ src/ci/docker/dist-x86_64-linux/build-git.sh | 24 ++++ .../docker/dist-x86_64-linux/build-headers.sh | 25 ++++ .../docker/dist-x86_64-linux/build-openssl.sh | 27 +++++ .../docker/dist-x86_64-linux/build-python.sh | 30 +++++ src/ci/docker/dist-x86_64-linux/shared.sh | 25 ++++ src/ci/docker/dist-x86_64-netbsd/Dockerfile | 78 ++++++++++++ .../build-netbsd-toolchain.sh | 0 50 files changed, 996 insertions(+), 66 deletions(-) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-aarch64-linux}/Dockerfile (79%) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-aarch64-linux}/aarch64-linux-gnu.config (100%) create mode 100755 src/ci/docker/dist-aarch64-linux/build-toolchains.sh create mode 100644 src/ci/docker/dist-armhf-linux/Dockerfile rename src/ci/docker/{dist-arm-linux => dist-armhf-linux}/arm-linux-gnueabihf.config (100%) create mode 100755 src/ci/docker/dist-armhf-linux/build-toolchains.sh create mode 100644 src/ci/docker/dist-armv7-linux/Dockerfile rename src/ci/docker/{dist-armv7-aarch64-linux => dist-armv7-linux}/armv7-linux-gnueabihf.config (100%) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-armv7-linux}/build-toolchains.sh (88%) rename src/ci/docker/{dist-freebsd => dist-i686-freebsd}/Dockerfile (77%) rename src/ci/docker/{dist-freebsd => dist-i686-freebsd}/build-toolchain.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/Dockerfile (98%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-binutils.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-cmake.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-curl.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-gcc.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-git.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-headers.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-openssl.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-python.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/shared.sh (100%) create mode 100644 src/ci/docker/dist-mips64el-linux/Dockerfile create mode 100644 src/ci/docker/dist-mipsel-linux/Dockerfile create mode 100644 src/ci/docker/dist-powerpc64le-linux/Dockerfile rename src/ci/docker/{dist-powerpc64-linux => dist-powerpc64le-linux}/build-powerpc64le-toolchain.sh (100%) create mode 100644 src/ci/docker/dist-powerpc64le-linux/shared.sh rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/Dockerfile (83%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/build-s390x-toolchain.sh (100%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch (100%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/s390x-linux-gnu.config (100%) create mode 100644 src/ci/docker/dist-x86_64-freebsd/Dockerfile create mode 100755 src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh create mode 100644 src/ci/docker/dist-x86_64-linux/Dockerfile create mode 100755 src/ci/docker/dist-x86_64-linux/build-binutils.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-cmake.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-curl.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-gcc.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-git.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-headers.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-openssl.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-python.sh create mode 100644 src/ci/docker/dist-x86_64-linux/shared.sh create mode 100644 src/ci/docker/dist-x86_64-netbsd/Dockerfile rename src/ci/docker/{dist-s390x-linux-netbsd => dist-x86_64-netbsd}/build-netbsd-toolchain.sh (100%) diff --git a/.travis.yml b/.travis.yml index 8fe92ff7d028..a8c9337fa81b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,19 +15,27 @@ matrix: - env: IMAGE=arm-android - env: IMAGE=armhf-gnu - env: IMAGE=cross DEPLOY=1 + - env: IMAGE=dist-aarch64-linux DEPLOY=1 - env: IMAGE=dist-android DEPLOY=1 - env: IMAGE=dist-arm-linux DEPLOY=1 - - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1 - - env: IMAGE=dist-freebsd DEPLOY=1 - - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-armhf-linux DEPLOY=1 + - env: IMAGE=dist-armv7-linux DEPLOY=1 - env: IMAGE=dist-fuchsia DEPLOY=1 + - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-i686-freebsd DEPLOY=1 + - env: IMAGE=dist-i686-linux DEPLOY=1 - env: IMAGE=dist-mips-linux DEPLOY=1 - env: IMAGE=dist-mips64-linux DEPLOY=1 + - env: IMAGE=dist-mips64el-linux DEPLOY=1 + - env: IMAGE=dist-mipsel-linux DEPLOY=1 - env: IMAGE=dist-powerpc-linux DEPLOY=1 - env: IMAGE=dist-powerpc64-linux DEPLOY=1 - - env: IMAGE=dist-s390x-linux-netbsd DEPLOY=1 - - env: IMAGE=dist-x86-linux DEPLOY=1 + - env: IMAGE=dist-powerpc64le-linux DEPLOY=1 + - env: IMAGE=dist-s390x-linux DEPLOY=1 + - env: IMAGE=dist-x86_64-freebsd DEPLOY=1 + - env: IMAGE=dist-x86_64-linux DEPLOY=1 - env: IMAGE=dist-x86_64-musl DEPLOY=1 + - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 - env: IMAGE=emscripten - env: IMAGE=i686-gnu - env: IMAGE=i686-gnu-nopt diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile similarity index 79% rename from src/ci/docker/dist-armv7-aarch64-linux/Dockerfile rename to src/ci/docker/dist-aarch64-linux/Dockerfile index 369e5a7dffe2..c468a689a056 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -56,8 +56,7 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY armv7-linux-gnueabihf.config /tmp/ -COPY armv7-linux-gnueabihf.config aarch64-linux-gnu.config build-toolchains.sh /tmp/ +COPY aarch64-linux-gnu.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root @@ -67,17 +66,12 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \ AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \ - CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ \ - CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ - AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ - CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ -ENV HOSTS=armv7-unknown-linux-gnueabihf -ENV HOSTS=$HOSTS,aarch64-unknown-linux-gnu +ENV HOSTS=aarch64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config rename to src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config diff --git a/src/ci/docker/dist-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh new file mode 100755 index 000000000000..94f785c96f81 --- /dev/null +++ b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../aarch64-linux-gnu.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 7facc52390ff..1e448dd43fd5 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -56,7 +56,7 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY arm-linux-gnueabihf.config arm-linux-gnueabi.config build-toolchains.sh /tmp/ +COPY arm-linux-gnueabi.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root @@ -66,17 +66,12 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ - CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ \ - CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ - AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ - CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ ENV HOSTS=arm-unknown-linux-gnueabi -ENV HOSTS=$HOSTS,arm-unknown-linux-gnueabihf ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/build-toolchains.sh b/src/ci/docker/dist-arm-linux/build-toolchains.sh index ed1406bd7cfa..f78ecf9381a1 100755 --- a/src/ci/docker/dist-arm-linux/build-toolchains.sh +++ b/src/ci/docker/dist-arm-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../arm-linux-gnueabihf.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile new file mode 100644 index 000000000000..cad96b4bde48 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY arm-linux-gnueabihf.config build-toolchains.sh /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin + +ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ + AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ + CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + +ENV HOSTS=arm-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config rename to src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armhf-linux/build-toolchains.sh b/src/ci/docker/dist-armhf-linux/build-toolchains.sh new file mode 100755 index 000000000000..df1134d5483c --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../arm-linux-gnueabihf.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile new file mode 100644 index 000000000000..d5be52eba5c2 --- /dev/null +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-toolchains.sh armv7-linux-gnueabihf.config /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin + +ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ + AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ + CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + +ENV HOSTS=armv7-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config rename to src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-armv7-linux/build-toolchains.sh similarity index 88% rename from src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh rename to src/ci/docker/dist-armv7-linux/build-toolchains.sh index ebd5ef4cfc49..2d395fee792e 100755 --- a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh +++ b/src/ci/docker/dist-armv7-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../aarch64-linux-gnu.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile similarity index 77% rename from src/ci/docker/dist-freebsd/Dockerfile rename to src/ci/docker/dist-i686-freebsd/Dockerfile index 633f58ea474b..beda2512741e 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -17,7 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config COPY build-toolchain.sh /tmp/ -RUN /tmp/build-toolchain.sh x86_64 RUN /tmp/build-toolchain.sh i686 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -30,15 +29,11 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ \ AR_i686_unknown_freebsd=i686-unknown-freebsd10-ar \ CC_i686_unknown_freebsd=i686-unknown-freebsd10-gcc \ CXX_i686_unknown_freebsd=i686-unknown-freebsd10-g++ -ENV HOSTS=x86_64-unknown-freebsd -ENV HOSTS=$HOSTS,i686-unknown-freebsd +ENV HOSTS=i686-unknown-freebsd ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-freebsd/build-toolchain.sh b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh similarity index 100% rename from src/ci/docker/dist-freebsd/build-toolchain.sh rename to src/ci/docker/dist-i686-freebsd/build-toolchain.sh diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile similarity index 98% rename from src/ci/docker/dist-x86-linux/Dockerfile rename to src/ci/docker/dist-i686-linux/Dockerfile index 18c7a4d2b3e7..4540f4b0ceb2 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -80,7 +80,6 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu -ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ diff --git a/src/ci/docker/dist-x86-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-binutils.sh rename to src/ci/docker/dist-i686-linux/build-binutils.sh diff --git a/src/ci/docker/dist-x86-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-cmake.sh rename to src/ci/docker/dist-i686-linux/build-cmake.sh diff --git a/src/ci/docker/dist-x86-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-curl.sh rename to src/ci/docker/dist-i686-linux/build-curl.sh diff --git a/src/ci/docker/dist-x86-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-gcc.sh rename to src/ci/docker/dist-i686-linux/build-gcc.sh diff --git a/src/ci/docker/dist-x86-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-git.sh rename to src/ci/docker/dist-i686-linux/build-git.sh diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-headers.sh rename to src/ci/docker/dist-i686-linux/build-headers.sh diff --git a/src/ci/docker/dist-x86-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-openssl.sh rename to src/ci/docker/dist-i686-linux/build-openssl.sh diff --git a/src/ci/docker/dist-x86-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-python.sh rename to src/ci/docker/dist-i686-linux/build-python.sh diff --git a/src/ci/docker/dist-x86-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/shared.sh rename to src/ci/docker/dist-i686-linux/shared.sh diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 938c53ae4883..e3df1cc7192d 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -13,7 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips-linux-gnu \ - g++-mipsel-linux-gnu \ libssl-dev \ pkg-config @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips-unknown-linux-gnu -ENV HOSTS=$HOSTS,mipsel-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 45de8100b4f2..e4b3bc378c89 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -13,7 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips64-linux-gnuabi64 \ - g++-mips64el-linux-gnuabi64 \ libssl-dev \ pkg-config @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV HOSTS=$HOSTS,mips64el-unknown-linux-gnuabi64 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile new file mode 100644 index 000000000000..06f42397a3ea --- /dev/null +++ b/src/ci/docker/dist-mips64el-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mips64el-linux-gnuabi64 \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mips64el-unknown-linux-gnuabi64 + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile new file mode 100644 index 000000000000..17f9913b5aec --- /dev/null +++ b/src/ci/docker/dist-mipsel-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mipsel-linux-gnu \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mipsel-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 7413c327323e..7c143b414d46 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -62,10 +62,6 @@ RUN ./build-powerpc64-toolchain.sh USER root -RUN apt-get install -y --no-install-recommends rpm2cpio cpio -COPY build-powerpc64le-toolchain.sh /tmp/ -RUN ./build-powerpc64le-toolchain.sh - RUN curl -o /usr/local/bin/sccache \ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache @@ -75,13 +71,9 @@ ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin ENV \ AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \ - CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \ - AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ ENV HOSTS=powerpc64-unknown-linux-gnu -ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile new file mode 100644 index 000000000000..19b0d625d361 --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +USER root + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY shared.sh build-powerpc64le-toolchain.sh /tmp/ +RUN ./build-powerpc64le-toolchain.sh + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + +ENV HOSTS=powerpc64le-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh similarity index 100% rename from src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh rename to src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh diff --git a/src/ci/docker/dist-powerpc64le-linux/shared.sh b/src/ci/docker/dist-powerpc64le-linux/shared.sh new file mode 100644 index 000000000000..97e6d2908cf8 --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/shared.sh @@ -0,0 +1,25 @@ +# 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. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile similarity index 83% rename from src/ci/docker/dist-s390x-linux-netbsd/Dockerfile rename to src/ci/docker/dist-s390x-linux/Dockerfile index 4180006690fc..0d218771cf1c 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux/Dockerfile @@ -60,27 +60,20 @@ COPY patches/ /tmp/patches/ COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/ RUN ./build-s390x-toolchain.sh -COPY build-netbsd-toolchain.sh /tmp/ -RUN ./build-netbsd-toolchain.sh - USER root RUN curl -o /usr/local/bin/sccache \ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache -ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin +ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin ENV \ - AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ - CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ - CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot \ CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ -ENV HOSTS=x86_64-unknown-netbsd -ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu +ENV HOSTS=s390x-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh rename to src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch rename to src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config rename to src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile new file mode 100644 index 000000000000..14444d69d2a8 --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + bzip2 \ + xz-utils \ + wget \ + libssl-dev \ + pkg-config + +COPY build-toolchain.sh /tmp/ +RUN /tmp/build-toolchain.sh x86_64 + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ + +ENV HOSTS=x86_64-unknown-freebsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh new file mode 100755 index 000000000000..5642e6fc937f --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# 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. + +set -ex + +ARCH=$1 +BINUTILS=2.25.1 +GCC=5.3.0 + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir binutils +cd binutils + +# First up, build binutils +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +hide_output ../binutils-$BINUTILS/configure \ + --target=$ARCH-unknown-freebsd10 +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf binutils + +# Next, download the FreeBSD libc and relevant header files + +mkdir freebsd +case "$ARCH" in + x86_64) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz + ;; + i686) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz + ;; +esac +curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib + +dst=/usr/local/$ARCH-unknown-freebsd10 + +cp -r freebsd/usr/include $dst/ +cp freebsd/usr/lib/crt1.o $dst/lib +cp freebsd/usr/lib/Scrt1.o $dst/lib +cp freebsd/usr/lib/crti.o $dst/lib +cp freebsd/usr/lib/crtn.o $dst/lib +cp freebsd/usr/lib/libc.a $dst/lib +cp freebsd/usr/lib/libutil.a $dst/lib +cp freebsd/usr/lib/libutil_p.a $dst/lib +cp freebsd/usr/lib/libm.a $dst/lib +cp freebsd/usr/lib/librt.so.1 $dst/lib +cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib +cp freebsd/lib/libc.so.7 $dst/lib +cp freebsd/lib/libm.so.5 $dst/lib +cp freebsd/lib/libutil.so.9 $dst/lib +cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so + +ln -s libc.so.7 $dst/lib/libc.so +ln -s libm.so.5 $dst/lib/libm.so +ln -s librt.so.1 $dst/lib/librt.so +ln -s libutil.so.9 $dst/lib/libutil.so +ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so +rm -rf freebsd + +# Finally, download and build gcc to target FreeBSD +mkdir gcc +cd gcc +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --enable-languages=c,c++ \ + --target=$ARCH-unknown-freebsd10 \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf gcc diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile new file mode 100644 index 000000000000..021c6683cc1c --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -0,0 +1,95 @@ +FROM centos:5 + +WORKDIR /build + +RUN yum upgrade -y && yum install -y \ + curl \ + bzip2 \ + gcc \ + gcc-c++ \ + make \ + glibc-devel \ + perl \ + zlib-devel \ + file \ + xz \ + which \ + pkgconfig \ + wget \ + autoconf \ + gettext + +ENV PATH=/rustroot/bin:$PATH +ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib +ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig +WORKDIR /tmp +COPY shared.sh build-binutils.sh /tmp/ + +# We need a build of openssl which supports SNI to download artifacts from +# static.rust-lang.org. This'll be used to link into libcurl below (and used +# later as well), so build a copy of OpenSSL with dynamic libraries into our +# generic root. +COPY build-openssl.sh /tmp/ +RUN ./build-openssl.sh + +# The `curl` binary on CentOS doesn't support SNI which is needed for fetching +# some https urls we have, so install a new version of libcurl + curl which is +# using the openssl we just built previously. +# +# Note that we also disable a bunch of optional features of curl that we don't +# really need. +COPY build-curl.sh /tmp/ +RUN ./build-curl.sh + +# binutils < 2.22 has a bug where the 32-bit executables it generates +# immediately segfault in Rust, so we need to install our own binutils. +# +# See https://github.com/rust-lang/rust/issues/20440 for more info +RUN ./build-binutils.sh + +# Need a newer version of gcc than centos has to compile LLVM nowadays +COPY build-gcc.sh /tmp/ +RUN ./build-gcc.sh + +# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ +COPY build-python.sh /tmp/ +RUN ./build-python.sh + +# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for +# cloning, so download and build it here. +COPY build-git.sh /tmp/ +RUN ./build-git.sh + +# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS +# only has 2.6.4, so build our own +COPY build-cmake.sh /tmp/ +RUN ./build-cmake.sh + +# for sanitizers, we need kernel headers files newer than the ones CentOS ships +# with so we install newer ones here +COPY build-headers.sh /tmp/ +RUN ./build-headers.sh + +RUN curl -Lo /rustroot/dumb-init \ + https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \ + chmod +x /rustroot/dumb-init +ENTRYPOINT ["/rustroot/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV HOSTS=x86_64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS \ + --host=$HOSTS \ + --enable-extended \ + --enable-sanitizers +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS + +# This is the only builder which will create source tarballs +ENV DIST_SRC 1 + +# When we build cargo in this container, we don't want it to use the system +# libcurl, instead it should compile its own. +ENV LIBCURL_NO_PKG_CONFIG 1 diff --git a/src/ci/docker/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/dist-x86_64-linux/build-binutils.sh new file mode 100755 index 000000000000..80aa1f2a0161 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-binutils.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# 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. + +set -ex + +source shared.sh + +curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj - + +mkdir binutils-build +cd binutils-build +hide_output ../binutils-2.25.1/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf binutils-build +rm -rf binutils-2.25.1 diff --git a/src/ci/docker/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/dist-x86_64-linux/build-cmake.sh new file mode 100755 index 000000000000..82e46455cb0f --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-cmake.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# 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. + +set -ex +source shared.sh + +curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf - + +mkdir cmake-build +cd cmake-build +hide_output ../cmake-3.6.3/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf cmake-build +rm -rf cmake-3.6.3 diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh new file mode 100755 index 000000000000..b7d22755a571 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# 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. + +set -ex +source shared.sh + +VERSION=7.51.0 + +curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - + +mkdir curl-build +cd curl-build +hide_output ../curl-$VERSION/configure \ + --prefix=/rustroot \ + --with-ssl=/rustroot \ + --disable-sspi \ + --disable-gopher \ + --disable-smtp \ + --disable-smb \ + --disable-imap \ + --disable-pop3 \ + --disable-tftp \ + --disable-telnet \ + --disable-manual \ + --disable-dict \ + --disable-rtsp \ + --disable-ldaps \ + --disable-ldap +hide_output make -j10 +hide_output make install + +cd .. +rm -rf curl-build +rm -rf curl-$VERSION +yum erase -y curl diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh new file mode 100755 index 000000000000..ab2562538d6d --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# 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. + +set -ex + +source shared.sh + +GCC=4.8.5 + +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --prefix=/rustroot \ + --enable-languages=c,c++ +hide_output make -j10 +hide_output make install +ln -nsf gcc /rustroot/bin/cc + +cd .. +rm -rf gcc-build +rm -rf gcc-$GCC +yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-x86_64-linux/build-git.sh b/src/ci/docker/dist-x86_64-linux/build-git.sh new file mode 100755 index 000000000000..92fa66b496d9 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-git.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# 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. + +set -ex +source shared.sh + +curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - + +cd git-2.10.0 +make configure +hide_output ./configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf git-2.10.0 diff --git a/src/ci/docker/dist-x86_64-linux/build-headers.sh b/src/ci/docker/dist-x86_64-linux/build-headers.sh new file mode 100755 index 000000000000..4ce38fd9205e --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-headers.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# 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. + +set -ex +source shared.sh + +curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x + +cd linux-3.2.84 +hide_output make mrproper +hide_output make INSTALL_HDR_PATH=dest headers_install + +find dest/include \( -name .install -o -name ..install.cmd \) -delete +yes | cp -fr dest/include/* /usr/include + +cd .. +rm -rf linux-3.2.84 diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh new file mode 100755 index 000000000000..64b1abf82a82 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# 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. + +set -ex +source shared.sh + +VERSION=1.0.2j + +curl https://www.openssl.org/source/openssl-$VERSION.tar.gz | tar xzf - + +cd openssl-$VERSION +hide_output ./config --prefix=/rustroot shared -fPIC +hide_output make -j10 +hide_output make install +cd .. +rm -rf openssl-$VERSION + +# Make the system cert collection available to the new install. +ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/dist-x86_64-linux/build-python.sh b/src/ci/docker/dist-x86_64-linux/build-python.sh new file mode 100755 index 000000000000..a7a450f3c8de --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-python.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# 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. + +set -ex +source shared.sh + +curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \ + tar xzf - + +mkdir python-build +cd python-build + +# Gotta do some hackery to tell python about our custom OpenSSL build, but other +# than that fairly normal. +CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ + hide_output ../Python-2.7.12/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf python-build +rm -rf Python-2.7.12 diff --git a/src/ci/docker/dist-x86_64-linux/shared.sh b/src/ci/docker/dist-x86_64-linux/shared.sh new file mode 100644 index 000000000000..97e6d2908cf8 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/shared.sh @@ -0,0 +1,25 @@ +# 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. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile new file mode 100644 index 000000000000..053300b9c168 --- /dev/null +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -0,0 +1,78 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-netbsd-toolchain.sh /tmp/ +RUN ./build-netbsd-toolchain.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin + +ENV \ + AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ + CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ + CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot + +ENV HOSTS=x86_64-unknown-netbsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh rename to src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh From 802c11c33e4efee699d35dfe60604cfcad38ec62 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Mon, 3 Apr 2017 22:14:45 +0200 Subject: [PATCH 263/905] switch to vault.centos.org --- src/ci/docker/dist-x86-linux/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 18c7a4d2b3e7..0c86568d71e1 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -2,6 +2,12 @@ FROM centos:5 WORKDIR /build +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1vault.centos.org/' /etc/yum.repos.d/*.repo + RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ From 3fb1a849ddd162444e2894bce52f7bb2dbc53d69 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 3 Apr 2017 13:46:50 -0700 Subject: [PATCH 264/905] Add a common Build::src_is_git flag --- src/bootstrap/lib.rs | 8 ++++---- src/bootstrap/sanity.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84254d7d6ae5..f80ba017f077 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -162,6 +162,7 @@ pub struct Build { cxx: HashMap, crates: HashMap, is_sudo: bool, + src_is_git: bool, } #[derive(Debug)] @@ -233,6 +234,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); + let src_is_git = src.join(".git").is_dir(); Build { flags: flags, @@ -251,6 +253,7 @@ impl Build { lldb_version: None, lldb_python_dir: None, is_sudo: is_sudo, + src_is_git: src_is_git, } } @@ -307,10 +310,7 @@ impl Build { OutOfSync, } - if !self.config.submodules { - return - } - if fs::metadata(self.src.join(".git")).is_err() { + if !self.src_is_git || !self.config.submodules { return } let git = || { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 235ce9360eff..d1b235f4691d 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -65,7 +65,7 @@ pub fn check(build: &mut Build) { // If we've got a git directory we're gona need git to update // submodules and learn about various other aspects. - if fs::metadata(build.src.join(".git")).is_ok() { + if build.src_is_git { need_cmd("git".as_ref()); } From e9cfc300a3a5b5a6f6f27df3305338f4b451366d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 3 Apr 2017 13:46:53 -0700 Subject: [PATCH 265/905] Only use cargo-vendor if building from git sources --- src/bootstrap/dist.rs | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index ec992b47a6e4..6472b1a928ca 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -433,29 +433,32 @@ pub fn rust_src(build: &Build) { copy(&build.src.join(item), &dst_src.join(item)); } - // Get cargo-vendor installed, if it isn't already. - let mut has_cargo_vendor = false; - let mut cmd = Command::new(&build.cargo); - for line in output(cmd.arg("install").arg("--list")).lines() { - has_cargo_vendor |= line.starts_with("cargo-vendor "); - } - if !has_cargo_vendor { + // If we're building from git sources, we need to vendor a complete distribution. + if build.src_is_git { + // Get cargo-vendor installed, if it isn't already. + let mut has_cargo_vendor = false; let mut cmd = Command::new(&build.cargo); - cmd.arg("install") - .arg("--force") - .arg("--debug") - .arg("--vers").arg(CARGO_VENDOR_VERSION) - .arg("cargo-vendor") - .env("RUSTC", &build.rustc); + for line in output(cmd.arg("install").arg("--list")).lines() { + has_cargo_vendor |= line.starts_with("cargo-vendor "); + } + if !has_cargo_vendor { + let mut cmd = Command::new(&build.cargo); + cmd.arg("install") + .arg("--force") + .arg("--debug") + .arg("--vers").arg(CARGO_VENDOR_VERSION) + .arg("cargo-vendor") + .env("RUSTC", &build.rustc); + build.run(&mut cmd); + } + + // Vendor all Cargo dependencies + let mut cmd = Command::new(&build.cargo); + cmd.arg("vendor") + .current_dir(&dst_src.join("src")); build.run(&mut cmd); } - // Vendor all Cargo dependencies - let mut cmd = Command::new(&build.cargo); - cmd.arg("vendor") - .current_dir(&dst_src.join("src")); - build.run(&mut cmd); - // Create source tarball in rust-installer format let mut cmd = Command::new(SH_CMD); cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) From 5787808d07b27d12a397cd20bd630a2ed1f35ca2 Mon Sep 17 00:00:00 2001 From: mandeep Date: Mon, 3 Apr 2017 15:48:12 -0500 Subject: [PATCH 266/905] Removed trailing whitespace on line 682 --- src/libcollections/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 8a3fa94d4c1e..be613e06b02e 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -679,7 +679,7 @@ impl Vec { } /// Removes an element from the vector and returns it. - /// + /// /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is O(1). From 6dc8869f389e5b98d69b449befcf763cf897db67 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Mon, 3 Apr 2017 22:51:06 +0200 Subject: [PATCH 267/905] use fixed ip for vault.centos.org until updates have propagated to all mirrors --- src/ci/docker/dist-x86-linux/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 0c86568d71e1..a2afe4b1290f 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1vault.centos.org/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \ From b02cb1978c9c7532c93af4761fc61a72cb529da8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Apr 2017 00:24:08 +0200 Subject: [PATCH 268/905] Handle ordered lists as well --- src/librustdoc/html/markdown.rs | 16 ++++++++++++---- src/test/rustdoc/test-lists.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/test/rustdoc/test-lists.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 0b098fb14f19..245a3946a370 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -427,12 +427,15 @@ pub fn render(w: &mut fmt::Formatter, looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } + if shorter.is_compact() { + break + } } buffer.push_str(&format!("

  • {}
  • ", content)); } fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { + shorter: MarkdownOutputStyle, is_sorted_list: bool) { debug!("List"); let mut content = String::new(); while let Some(event) = parser.next() { @@ -445,8 +448,13 @@ pub fn render(w: &mut fmt::Formatter, looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); } } + if shorter.is_compact() { + break + } } - buffer.push_str(&format!("
      {}
    ", content)); + buffer.push_str(&format!("<{0}>{1}", + if is_sorted_list { "ol" } else { "ul" }, + content)); } fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, @@ -516,8 +524,8 @@ pub fn render(w: &mut fmt::Formatter, Event::Start(Tag::BlockQuote) => { blockquote(parser, buffer, toc_builder, shorter); } - Event::Start(Tag::List(_)) => { - list(parser, buffer, toc_builder, shorter); + Event::Start(Tag::List(x)) => { + list(parser, buffer, toc_builder, shorter, x.is_some()); } Event::Start(Tag::Emphasis) => { emphasis(parser, buffer, toc_builder, shorter, id); diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs new file mode 100644 index 000000000000..71a826a2bed7 --- /dev/null +++ b/src/test/rustdoc/test-lists.rs @@ -0,0 +1,32 @@ +// 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. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/fn.f.html +// @has - "
    pub fn f()
    1. list
      1. fooooo
      2. x
    2. foo
    " +/// 1. list +/// 1. fooooo +/// 2. x +/// 2. foo +pub fn f() {} + +// @has foo/fn.foo2.html +// @has - "
    pub fn foo2()
    • normal list
      • sub list

      • new elem still same elem

        and again same elem!

    • new big elem
    " +/// * normal list +/// * sub list +/// * new elem +/// still same elem +/// +/// and again same elem! +/// * new big elem +pub fn foo2() {} \ No newline at end of file From bb8474682366592fa9d52cb11723a5fd5cd9421e Mon Sep 17 00:00:00 2001 From: Dylan Maccora Date: Tue, 4 Apr 2017 08:27:20 +1000 Subject: [PATCH 269/905] AsMut example --- src/libcore/convert.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 19cd2d3398f3..0bc055064136 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -91,6 +91,8 @@ use str::FromStr; /// [`Path`]: ../../std/path/struct.Path.html /// /// ``` +/// use std::path::Path; +/// /// impl AsRef for str { /// fn as_ref(&self) -> &Path { /// Path::new(self) @@ -123,7 +125,8 @@ pub trait AsRef { /// A cheap, mutable reference-to-mutable reference conversion. /// -/// This trait is similar to `AsRef` but used for converting mutable references. +/// This trait is similar to `AsRef` but used for converting between mutable +/// references. /// /// **Note: this trait must not fail**. If the conversion can fail, use a /// dedicated method which returns an [`Option`] or a [`Result`]. @@ -153,11 +156,13 @@ pub trait AsRef { /// assert_eq!(*boxed_num, 1); /// ``` /// -/// Implementing `AsMut`: +/// `Vec` implements `AsMut` for converting between itself and a primitive array: /// /// ``` -/// impl Type { -/// let a = 1; +/// impl AsMut<[T]> for Vec { +/// fn as_mut(&mut self) -> &mut [T] { +/// self +/// } /// } /// ``` /// @@ -250,19 +255,22 @@ pub trait Into: Sized { /// An example usage for error handling: /// /// ``` +/// use std::io::{self, Read}; +/// use std::num; +/// /// enum CliError { /// IoError(io::Error), /// ParseError(num::ParseIntError), /// } /// -/// impl From for MyError { +/// impl From for CliError { /// fn from(error: io::Error) -> Self { /// CliError::IoError(error) /// } /// } /// -/// impl From for MyError { -/// fn from(error: io::Error) -> Self { +/// impl From for CliError { +/// fn from(error: num::ParseIntError) -> Self { /// CliError::ParseError(error) /// } /// } From 4d32ff4e498c391d65b44d26cfb453651dc3da7b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 3 Apr 2017 15:28:06 -0700 Subject: [PATCH 270/905] Loosen src_is_git to just check exists() --- src/bootstrap/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f80ba017f077..8303a40bb696 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -234,7 +234,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); - let src_is_git = src.join(".git").is_dir(); + let src_is_git = src.join(".git").exists(); Build { flags: flags, From 6a9448b523b95dbc850e856508342644fc17db45 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 3 Apr 2017 22:23:32 +0000 Subject: [PATCH 271/905] Fix bug parsing `#[derive]` macro invocations. --- src/librustc_resolve/macros.rs | 6 ++++-- src/libsyntax/ext/derive.rs | 3 ++- src/libsyntax/parse/parser.rs | 20 ++++++++++++++++++++ src/test/run-pass/issue-40962.rs | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-40962.rs diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 05f30f039c8f..966cb7ee8d8d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -222,8 +222,10 @@ impl<'a> base::Resolver for Resolver<'a> { let name = unwrap_or!(attrs[i].name(), continue); if name == "derive" { - let result = attrs[i].parse_list(&self.session.parse_sess, - |parser| parser.parse_path(PathStyle::Mod)); + let result = attrs[i].parse_list(&self.session.parse_sess, |parser| { + parser.parse_path_allowing_meta(PathStyle::Mod) + }); + let mut traits = match result { Ok(traits) => traits, Err(mut e) => { diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index c79040424f61..e7c5d8278d97 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec return true; } - match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) { + match attr.parse_list(cx.parse_sess, + |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { Ok(ref traits) if traits.is_empty() => { cx.span_warn(attr.span, "empty trait list in `derive`"); false diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855a..a89811d8abb0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1754,6 +1754,26 @@ impl<'a> Parser<'a> { }) } + /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. + /// This is used when parsing derive macro paths in `#[derive]` attributes. + pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + let meta_ident = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref meta) => match meta.node { + ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)), + _ => None, + }, + _ => None, + }, + _ => None, + }; + if let Some(ident) = meta_ident { + self.bump(); + return Ok(ast::Path::from_ident(self.prev_span, ident)); + } + self.parse_path(mode) + } + /// Examples: /// - `a::b::c` /// - `a::b::c(V) -> W` diff --git a/src/test/run-pass/issue-40962.rs b/src/test/run-pass/issue-40962.rs new file mode 100644 index 000000000000..b35cfa12eab1 --- /dev/null +++ b/src/test/run-pass/issue-40962.rs @@ -0,0 +1,20 @@ +// 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. + +macro_rules! m { + ($i:meta) => { + #[derive($i)] + struct S; + } +} + +m!(Clone); + +fn main() {} From ab4f4428e778d45e0e8db2a254e55f5ec786410c Mon Sep 17 00:00:00 2001 From: Bryan Tan Date: Mon, 3 Apr 2017 16:09:19 -0700 Subject: [PATCH 272/905] Fix styling issues --- src/libstd/sync/mpsc/mod.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 33ffd5548fb8..0da65a4f2e12 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -23,12 +23,12 @@ //! //! These channels come in two flavors: //! -//! 1. An asynchronous, infinitely buffered channel. The [`channel()`] function +//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function //! will return a `(Sender, Receiver)` tuple where all sends will be //! **asynchronous** (they never block). The channel conceptually has an //! infinite buffer. //! -//! 2. A synchronous, bounded channel. The [`sync_channel()`] function will +//! 2. A synchronous, bounded channel. The [`sync_channel`] function will //! return a `(SyncSender, Receiver)` tuple where the storage for pending //! messages is a pre-allocated buffer of a fixed size. All sends will be //! **synchronous** by blocking until there is buffer space available. Note @@ -39,8 +39,8 @@ //! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html //! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html //! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -//! [`channel()`]: ../../../std/sync/mpsc/fn.channel.html -//! [`sync_channel()`]: ../../../std/sync/mpsc/fn.sync_channel.html +//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html +//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html //! //! ## Disconnection //! @@ -51,12 +51,12 @@ //! //! Once half of a channel has been deallocated, most operations can no longer //! continue to make progress, so [`Err`] will be returned. Many applications -//! will continue to [`unwrap()`] the results returned from this module, +//! will continue to [`unwrap`] the results returned from this module, //! instigating a propagation of failure among threads if one unexpectedly dies. //! //! [`Result`]: ../../../std/result/enum.Result.html //! [`Err`]: ../../../std/result/enum.Result.html#variant.Err -//! [`unwrap()`]: ../../../std/result/enum.Result.html#method.unwrap +//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap //! //! # Examples //! @@ -310,12 +310,15 @@ mod spsc_queue; /// use std::sync::mpsc::channel; /// use std::thread; /// use std::time::Duration; +/// /// let (send, recv) = channel(); +/// /// thread::spawn(move || { /// send.send("Hello world!").unwrap(); /// thread::sleep(Duration::from_secs(2)); // block for two seconds /// send.send("Delayed for 2 seconds").unwrap(); /// }); +/// /// println!("{}", recv.recv().unwrap()); // Received immediately /// println!("Waiting..."); /// println!("{}", recv.recv().unwrap()); // Received after 2 seconds @@ -384,18 +387,23 @@ pub struct IntoIter { /// ```rust /// use std::sync::mpsc::channel; /// use std::thread; +/// /// let (sender, receiver) = channel(); /// let sender2 = sender.clone(); +/// /// // First thread owns sender /// thread::spawn(move || { /// sender.send(1).unwrap(); /// }); +/// /// // Second thread owns sender2 /// thread::spawn(move || { /// sender2.send(2).unwrap(); /// }); +/// /// let msg = receiver.recv().unwrap(); /// let msg2 = receiver.recv().unwrap(); +/// /// assert_eq!(3, msg + msg2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1097,12 +1105,15 @@ impl Receiver { /// ```rust /// use std::sync::mpsc::channel; /// use std::thread; + /// /// let (send, recv) = channel(); + /// /// thread::spawn(move || { /// send.send(1u8).unwrap(); /// send.send(2u8).unwrap(); /// send.send(3u8).unwrap(); /// }); + /// /// for x in recv.iter() { /// println!("Got: {}", x); /// } From 20cb7005b0c1e12383a4c2f9031c5c5f5c907efc Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Mon, 3 Apr 2017 19:15:31 -0600 Subject: [PATCH 273/905] Handle options-with-arguments before subcommands such as './x.py -j 10 build' and detect pathological cases like './x.py --option-that-takes-argument clean build' --- src/bootstrap/flags.rs | 60 +++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2e133664a05b..3af3b76163c1 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -119,7 +119,13 @@ To learn more about a subcommand, run `./x.py -h`"); // complete the definition of the options. Then we can use the getopt::Matches object from // there on out. let mut possible_subcommands = args.iter().collect::>(); - possible_subcommands.retain(|&s| !s.starts_with('-')); + possible_subcommands.retain(|&s| + (s == "build") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist")); let subcommand = match possible_subcommands.first() { Some(s) => s, None => { @@ -129,7 +135,43 @@ To learn more about a subcommand, run `./x.py -h`"); } }; - // Some subcommands have specific arguments help text + // Some subcommands get extra options + match subcommand.as_str() { + "test" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), + "bench" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), + "dist" => opts.optflag("", "install", "run installer as well"), + _ => { } + }; + + // Done specifying what options are possible, so do the getopts parsing + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + // Extra sanity check to make sure we didn't hit this crazy corner case: + // + // ./x.py --frobulate clean build + // ^-- option ^ ^- actual subcommand + // \_ arg to option could be mistaken as subcommand + let mut pass_sanity_check = true; + match matches.free.get(0) { + Some(check_subcommand) => { + if &check_subcommand != subcommand { + pass_sanity_check = false; + } + }, + None => { + pass_sanity_check = false; + } + } + if !pass_sanity_check { + println!("{}\n", subcommand_help); + println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ + You may need to move some options to after the subcommand.\n"); + process::exit(1); + } + // Extra help text for some commands match subcommand.as_str() { "build" => { subcommand_help.push_str("\n @@ -152,7 +194,6 @@ Arguments: ./x.py build --stage 1 src/libtest"); } "test" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); subcommand_help.push_str("\n Arguments: This subcommand accepts a number of paths to directories to tests that @@ -168,9 +209,6 @@ Arguments: ./x.py test ./x.py test --stage 1"); } - "bench" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - } "doc" => { subcommand_help.push_str("\n Arguments: @@ -186,18 +224,8 @@ Arguments: ./x.py doc ./x.py doc --stage 1"); } - "dist" => { - opts.optflag("", "install", "run installer as well"); - } _ => { } }; - - // Done specifying what options are possible, so do the getopts parsing - let matches = opts.parse(&args[..]).unwrap_or_else(|e| { - // Invalid argument/option format - println!("\n{}\n", e); - usage(1, &opts, &subcommand_help, &extra_help); - }); // Get any optional paths which occur after the subcommand let cwd = t!(env::current_dir()); let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); From 018c5c929820af8e8b455a64a9d7d5456b01b1ed Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 4 Apr 2017 10:43:16 +0900 Subject: [PATCH 274/905] Make 'overlapping_inherent_impls' lint a hard error --- .../coherence/inherent_impls_overlap.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 4b36072243c8..33280fb931aa 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -11,7 +11,6 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::lint; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt}; @@ -53,12 +52,16 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for &item2 in &impl_items2[..] { if (name, namespace) == name_and_namespace(item2) { - let msg = format!("duplicate definitions with name `{}`", name); - let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); - self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, - node_id, - self.tcx.span_of_impl(item1).unwrap(), - msg); + struct_span_err!(self.tcx.sess, + self.tcx.span_of_impl(item1).unwrap(), + E0592, + "duplicate definitions with name `{}`", + name) + .span_label(self.tcx.span_of_impl(item1).unwrap(), + &format!("duplicate definitions for `{}`", name)) + .span_label(self.tcx.span_of_impl(item2).unwrap(), + &format!("other definition for `{}`", name)) + .emit(); } } } From 4143d409eed1393a830fcc089dc68d94a20a223f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 16:30:31 +1300 Subject: [PATCH 275/905] save-analysis: only index path references once --- src/librustc_save_analysis/dump_visitor.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 7a7fa4eda05a..491618f7952d 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1401,15 +1401,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, debug!("visit_expr {:?}", ex.node); self.process_macro_use(ex.span, ex.id); match ex.node { - ast::ExprKind::Call(ref _f, ref _args) => { - // Don't need to do anything for function calls, - // because just walking the callee path does what we want. - visit::walk_expr(self, ex); - } - ast::ExprKind::Path(_, ref path) => { - self.process_path(ex.id, path, None); - visit::walk_expr(self, ex); - } ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id); let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) { @@ -1507,6 +1498,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, self.visit_expr(element); self.nest_tables(count.id, |v| v.visit_expr(count)); } + // In particular, we take this branch for call and path expressions, + // where we'll index the idents involved just by continuing to walk. _ => { visit::walk_expr(self, ex) } From ccdbb31a4773fcb44d046f02a822e54dfe132970 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 18:04:30 +1300 Subject: [PATCH 276/905] save-analysis: index extern blocks --- src/librustc_save_analysis/dump_visitor.rs | 35 +++++++++++++ src/librustc_save_analysis/lib.rs | 55 +++++++++++++++++++++ src/test/run-make/save-analysis-fail/foo.rs | 5 ++ 3 files changed, 95 insertions(+) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 491618f7952d..3fd0ce45e361 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1599,4 +1599,39 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_expr, &l.init); } + + fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) { + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(fn_data, FunctionData, item.span); + if !self.span.filter_generated(Some(fn_data.span), item.span) { + self.dumper.function(fn_data.clone().lower(self.tcx)); + } + + self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, + &fn_data.qualname)); + self.process_generic_params(generics, item.span, &fn_data.qualname, item.id); + } + + for arg in &decl.inputs { + self.visit_ty(&arg.ty); + } + + if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { + self.visit_ty(&ret_ty); + } + } + ast::ForeignItemKind::Static(ref ty, _) => { + if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(var_data, VariableData, item.span); + if !self.span.filter_generated(Some(var_data.span), item.span) { + self.dumper.variable(var_data.lower(self.tcx)); + } + } + + self.visit_ty(ty); + } + } + } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1de9fbc8e494..b34cffd2d15b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -120,6 +120,46 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result } + pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option { + let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); + Some(Data::FunctionData(FunctionData { + id: item.id, + name: item.ident.to_string(), + qualname: qualname, + declaration: None, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + value: make_signature(decl, generics), + visibility: From::from(&item.vis), + parent: None, + docs: docs_for_attrs(&item.attrs), + sig: self.sig_base_extern(item), + })) + } + ast::ForeignItemKind::Static(ref ty, m) => { + let keyword = if m { keywords::Mut } else { keywords::Static }; + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); + Some(Data::VariableData(VariableData { + id: item.id, + kind: VariableKind::Static, + name: item.ident.to_string(), + qualname: qualname, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + parent: None, + value: String::new(), + type_value: ty_to_string(ty), + visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), + sig: Some(self.sig_base_extern(item)), + })) + } + } + } + pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { ast::ItemKind::Fn(ref decl, .., ref generics, _) => { @@ -751,6 +791,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } + fn sig_base_extern(&self, item: &ast::ForeignItem) -> Signature { + let text = self.span_utils.signature_string_for_span(item.span); + let name = item.ident.to_string(); + let ident_start = text.find(&name).expect("Name not in signature?"); + let ident_end = ident_start + name.len(); + Signature { + span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + text: text, + ident_start: ident_start, + ident_end: ident_end, + defs: vec![], + refs: vec![], + } + } + #[inline] pub fn enclosing_scope(&self, id: NodeId) -> NodeId { self.tcx.hir.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID) diff --git a/src/test/run-make/save-analysis-fail/foo.rs b/src/test/run-make/save-analysis-fail/foo.rs index e331f65abb7b..a996aa4fad5a 100644 --- a/src/test/run-make/save-analysis-fail/foo.rs +++ b/src/test/run-make/save-analysis-fail/foo.rs @@ -448,3 +448,8 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +extern { + static EXTERN_FOO: u8; + fn extern_foo(a: u8, b: i32) -> String; +} From d76daf5c616f7969752e5370287f4495b95fe00c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Mar 2017 10:43:11 +1300 Subject: [PATCH 277/905] rebased --- src/librustc_save_analysis/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b34cffd2d15b..44615071a56a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -125,6 +125,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); + filter!(self.span_utils, sub_span, item.span, None); Some(Data::FunctionData(FunctionData { id: item.id, name: item.ident.to_string(), @@ -137,11 +138,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base_extern(item), + attributes: item.attrs.clone(), })) } ast::ForeignItemKind::Static(ref ty, m) => { let keyword = if m { keywords::Mut } else { keywords::Static }; let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); + filter!(self.span_utils, sub_span, item.span, None); Some(Data::VariableData(VariableData { id: item.id, kind: VariableKind::Static, @@ -155,6 +158,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base_extern(item)), + attributes: item.attrs.clone(), })) } } @@ -797,7 +801,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ident_start = text.find(&name).expect("Name not in signature?"); let ident_end = ident_start + name.len(); Signature { - span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, text: text, ident_start: ident_start, ident_end: ident_end, From e753dfa9a945043c7c465fc3f1e9389585e096d0 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Tue, 28 Mar 2017 16:16:23 +0900 Subject: [PATCH 278/905] Fixed ICEs with pattern matching in const fn. Fixes #38199, fixes #31577, fixes #29093, and fixes #40012. --- src/librustc_mir/transform/qualify_consts.rs | 6 ++--- src/librustc_typeck/check/dropck.rs | 9 ++++--- .../compile-fail/const-match-pattern-arm.rs | 25 +++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/const-match-pattern-arm.rs diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9d236bd013c4..cdbc0bd8858a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -722,11 +722,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } Rvalue::Discriminant(..) => { - // FIXME discriminant + // FIXME implement discriminant const qualify self.add(Qualif::NOT_CONST); - if self.mode != Mode::Fn { - bug!("implement discriminant const qualify"); - } + // Discriminants in consts will error elsewhere as an unimplemented expression type } Rvalue::Box(_) => { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 90d2a15cf086..9f41373dab1b 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -278,9 +278,12 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", typ, scope); - let parent_scope = rcx.tcx.region_maps.opt_encl_scope(scope).unwrap_or_else(|| { - span_bug!(span, "no enclosing scope found for scope: {:?}", scope) - }); + + let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) { + Some(parent_scope) => parent_scope, + // If no enclosing scope, then it must be the root scope which cannot be outlived. + None => return + }; let result = iterate_over_potentially_unsafe_regions_in_type( &mut DropckContext { diff --git a/src/test/compile-fail/const-match-pattern-arm.rs b/src/test/compile-fail/const-match-pattern-arm.rs new file mode 100644 index 000000000000..452aa87d6ba5 --- /dev/null +++ b/src/test/compile-fail/const-match-pattern-arm.rs @@ -0,0 +1,25 @@ +// 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. + +const x: bool = match Some(true) { + Some(value) => true, + //~^ ERROR: constant contains unimplemented expression type [E0019] + _ => false +}; + +const y: bool = { + match Some(true) { + Some(value) => true, + //~^ ERROR: constant contains unimplemented expression type [E0019] + _ => false + } +}; + +fn main() {} From 6132fb83b45cc9c519c2fee29e497460db06ba2a Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Mon, 3 Apr 2017 22:41:55 -0700 Subject: [PATCH 279/905] Replace magic number with readable sig constant SIG_ERR is defined as 'pub const SIG_ERR: sighandler_t = !0 as sighandler_t;' --- src/libstd/sys/unix/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c57751a01d7c..854d380d128c 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -92,7 +92,7 @@ pub fn init() { #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} From 09f42ee3331815347767b5a821813a927758a421 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 4 Apr 2017 21:00:56 +0900 Subject: [PATCH 280/905] Move 'overlapping_inherent_impls' test to ui --- .../overlapping_inherent_impls.rs} | 6 ++-- .../overlapping_inherent_impls.stderr | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) rename src/test/{compile-fail/inherent-overlap.rs => ui/codemap_tests/overlapping_inherent_impls.rs} (84%) create mode 100644 src/test/ui/codemap_tests/overlapping_inherent_impls.stderr diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs similarity index 84% rename from src/test/compile-fail/inherent-overlap.rs rename to src/test/ui/codemap_tests/overlapping_inherent_impls.rs index 18e77ddfd2c5..a626b63b31ba 100644 --- a/src/test/compile-fail/inherent-overlap.rs +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs @@ -16,7 +16,7 @@ struct Foo; impl Foo { - fn id() {} //~ ERROR duplicate definitions + fn id() {} } impl Foo { @@ -26,7 +26,7 @@ impl Foo { struct Bar(T); impl Bar { - fn bar(&self) {} //~ ERROR duplicate definitions + fn bar(&self) {} } impl Bar { @@ -36,7 +36,7 @@ impl Bar { struct Baz(T); impl Baz { - fn baz(&self) {} //~ ERROR duplicate definitions + fn baz(&self) {} } impl Baz> { diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr new file mode 100644 index 000000000000..de8a24cf33f4 --- /dev/null +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr @@ -0,0 +1,29 @@ +error[E0592]: duplicate definitions with name `id` + --> $DIR/overlapping_inherent_impls.rs:19:5 + | +19 | fn id() {} + | ^^^^^^^^^^ duplicate definitions for `id` +... +23 | fn id() {} + | ---------- other definition for `id` + +error[E0592]: duplicate definitions with name `bar` + --> $DIR/overlapping_inherent_impls.rs:29:5 + | +29 | fn bar(&self) {} + | ^^^^^^^^^^^^^^^^ duplicate definitions for `bar` +... +33 | fn bar(&self) {} + | ---------------- other definition for `bar` + +error[E0592]: duplicate definitions with name `baz` + --> $DIR/overlapping_inherent_impls.rs:39:5 + | +39 | fn baz(&self) {} + | ^^^^^^^^^^^^^^^^ duplicate definitions for `baz` +... +43 | fn baz(&self) {} + | ---------------- other definition for `baz` + +error: aborting due to 3 previous errors + From db60b0b374ef4999e3c960a7230b18bcddf82ea0 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Tue, 4 Apr 2017 21:08:56 +0900 Subject: [PATCH 281/905] Move 'coherence-overlapping-inherent-impl-trait' test to ui --- .../coherence-overlapping-inherent-impl-trait.rs | 2 +- .../coherence-overlapping-inherent-impl-trait.stderr | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) rename src/test/{compile-fail => ui/codemap_tests}/coherence-overlapping-inherent-impl-trait.rs (88%) create mode 100644 src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr diff --git a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs similarity index 88% rename from src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs rename to src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs index 158d3606104a..a72ad0351e33 100644 --- a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs @@ -11,6 +11,6 @@ #![allow(dead_code)] trait C {} -impl C { fn f() {} } //~ ERROR duplicate definitions with name `f` +impl C { fn f() {} } impl C { fn f() {} } fn main() { } diff --git a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr new file mode 100644 index 000000000000..7f1ab929c6fc --- /dev/null +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr @@ -0,0 +1,10 @@ +error[E0592]: duplicate definitions with name `f` + --> $DIR/coherence-overlapping-inherent-impl-trait.rs:14:10 + | +14 | impl C { fn f() {} } + | ^^^^^^^^^ duplicate definitions for `f` +15 | impl C { fn f() {} } + | --------- other definition for `f` + +error: aborting due to previous error + From dd7fc23a21d60233e5c1b08376cc6cca6b9e1d53 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 4 Apr 2017 15:46:48 +0200 Subject: [PATCH 282/905] fix rollup --- src/ci/docker/dist-x86_64-linux/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 021c6683cc1c..bd36c75f9f06 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -2,6 +2,12 @@ FROM centos:5 WORKDIR /build +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo + RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ From aab2cca046670295bc1a430a8b1c23d755f9bd5a Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 27 Mar 2017 15:55:56 -0700 Subject: [PATCH 283/905] On-demandify reachability --- src/librustc/middle/reachable.rs | 17 ++++++++++++++--- src/librustc/ty/maps.rs | 12 ++++++++++++ src/librustc_driver/driver.rs | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index b0e39442af98..e5dd48534a6a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,11 +15,11 @@ // makes all other generics or inline functions that it references // reachable as well. -use dep_graph::DepNode; use hir::map as hir_map; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, CrateNum}; use ty::{self, TyCtxt}; +use ty::maps::Providers; use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; @@ -362,7 +362,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { - let _task = tcx.dep_graph.in_task(DepNode::Reachability); + ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) +} + +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet { + debug_assert!(crate_num == LOCAL_CRATE); let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); @@ -408,3 +412,10 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { // Return the set of reachable symbols. reachable_context.reachable_symbols } + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + reachable_set, + ..*providers + }; +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4a183191cef2..823bdc9e092a 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -15,6 +15,7 @@ use middle::privacy::AccessLevels; use mir; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; @@ -209,6 +210,11 @@ impl<'tcx> QueryDescription for queries::typeck_item_bodies<'tcx> { } } +impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("reachability") + } +} macro_rules! define_maps { (<$tcx:tt> @@ -440,6 +446,8 @@ define_maps! { <'tcx> /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, + pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet, + pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } @@ -451,6 +459,10 @@ fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { DepNode::Coherence } +fn reachability_dep_node(_: CrateNum) -> DepNode { + DepNode::Reachability +} + fn mir_shim(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 977382b33adf..3f99d5123c9e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -889,6 +889,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); + reachable::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); From 768e7078785dd418968f26d79b1ff323403999ef Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:08:52 -0400 Subject: [PATCH 284/905] kill the `CheckLoops` DepNode --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc_passes/loops.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5aea2bcaa4f5..5142fd3c028d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,7 +60,6 @@ pub enum DepNode { CheckStaticRecursion, ResolveLifetimes, RegionResolveCrate, - CheckLoops, PluginRegistrar, StabilityIndex, CollectItem(D), @@ -219,7 +218,6 @@ impl DepNode { CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), RegionResolveCrate => Some(RegionResolveCrate), - CheckLoops => Some(CheckLoops), PluginRegistrar => Some(PluginRegistrar), StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 421181c68c4c..2ea235af1037 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -11,7 +11,6 @@ use self::Context::*; use rustc::session::Session; -use rustc::dep_graph::DepNode; use rustc::hir::map::Map; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir; @@ -50,7 +49,6 @@ struct CheckLoopVisitor<'a, 'hir: 'a> { } pub fn check_crate(sess: &Session, map: &Map) { - let _task = map.dep_graph.in_task(DepNode::CheckLoops); let krate = map.krate(); krate.visit_all_item_likes(&mut CheckLoopVisitor { sess: sess, From f3b876c4b2dec93ead8ebdcbf5eb5a0be4fa46a0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:09:12 -0400 Subject: [PATCH 285/905] kill `CheckStaticRecursion` --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc_passes/static_recursion.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5142fd3c028d..0521b50df4d2 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -57,7 +57,6 @@ pub enum DepNode { // Represents different phases in the compiler. CollectLanguageItems, - CheckStaticRecursion, ResolveLifetimes, RegionResolveCrate, PluginRegistrar, @@ -215,7 +214,6 @@ impl DepNode { MirKrate => Some(MirKrate), TypeckBodiesKrate => Some(TypeckBodiesKrate), CollectLanguageItems => Some(CollectLanguageItems), - CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), RegionResolveCrate => Some(RegionResolveCrate), PluginRegistrar => Some(PluginRegistrar), diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index fc05471ead30..d0bf49b7b337 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -11,7 +11,6 @@ // This compiler pass detects constants that refer to themselves // recursively. -use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::session::{CompileResult, Session}; use rustc::hir::def::{Def, CtorKind}; @@ -88,8 +87,6 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> { } pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> CompileResult { - let _task = hir_map.dep_graph.in_task(DepNode::CheckStaticRecursion); - let mut visitor = CheckCrateVisitor { sess: sess, hir_map: hir_map, From 60381cd9c29c51615975894e898b47da65f0b124 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 4 Apr 2017 18:11:03 +0300 Subject: [PATCH 286/905] cstore: return an immutable borrow from `visible_parent_map` Fixes #41053. --- src/librustc/middle/cstore.rs | 4 +-- src/librustc_metadata/cstore_impl.rs | 16 +++++++++--- src/test/run-pass/auxiliary/issue_41053.rs | 11 ++++++++ src/test/run-pass/issue-41053.rs | 30 ++++++++++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/auxiliary/issue_41053.rs create mode 100644 src/test/run-pass/issue-41053.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 8bc0cf2577b5..dd1941ba48af 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -172,7 +172,7 @@ pub trait CrateStore { fn stability(&self, def: DefId) -> Option; fn deprecation(&self, def: DefId) -> Option; fn visibility(&self, def: DefId) -> ty::Visibility; - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap>; + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; fn item_generics_cloned(&self, def: DefId) -> ty::Generics; fn item_attrs(&self, def_id: DefId) -> Vec; fn fn_arg_names(&self, did: DefId) -> Vec; @@ -302,7 +302,7 @@ impl CrateStore for DummyCrateStore { fn stability(&self, def: DefId) -> Option { bug!("stability") } fn deprecation(&self, def: DefId) -> Option { bug!("deprecation") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { bug!("visible_parent_map") } fn item_generics_cloned(&self, def: DefId) -> ty::Generics diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 41a2e8a8d55e..b286cb8050ea 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -507,12 +507,19 @@ impl CrateStore for cstore::CStore { /// Returns a map from a sufficiently visible external item (i.e. an external item that is /// visible from at least one local module) to a sufficiently visible parent (considering /// modules that re-export the external item to be parents). - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { - let mut visible_parent_map = self.visible_parent_map.borrow_mut(); - if !visible_parent_map.is_empty() { return visible_parent_map; } + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { + { + let visible_parent_map = self.visible_parent_map.borrow(); + if !visible_parent_map.is_empty() { + return visible_parent_map; + } + } use std::collections::vec_deque::VecDeque; use std::collections::hash_map::Entry; + + let mut visible_parent_map = self.visible_parent_map.borrow_mut(); + for cnum in (1 .. self.next_crate_num().as_usize()).map(CrateNum::new) { let cdata = self.get_crate_data(cnum); @@ -556,6 +563,7 @@ impl CrateStore for cstore::CStore { } } - visible_parent_map + drop(visible_parent_map); + self.visible_parent_map.borrow() } } diff --git a/src/test/run-pass/auxiliary/issue_41053.rs b/src/test/run-pass/auxiliary/issue_41053.rs new file mode 100644 index 000000000000..68e92b104298 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue_41053.rs @@ -0,0 +1,11 @@ +// 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. + +pub struct Test; diff --git a/src/test/run-pass/issue-41053.rs b/src/test/run-pass/issue-41053.rs new file mode 100644 index 000000000000..769d841e364d --- /dev/null +++ b/src/test/run-pass/issue-41053.rs @@ -0,0 +1,30 @@ +// 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. + +// aux-build:issue_41053.rs + +pub trait Trait { fn foo(&self) {} } + +pub struct Foo; + +impl Iterator for Foo { + type Item = Box; + fn next(&mut self) -> Option> { + extern crate issue_41053; + impl ::Trait for issue_41053::Test { + fn foo(&self) {} + } + Some(Box::new(issue_41053::Test)) + } +} + +fn main() { + Foo.next().unwrap().foo(); +} From a83734dd96e303f484972dba9b446b3dda478f2e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 4 Apr 2017 11:19:36 -0400 Subject: [PATCH 287/905] remove `EffectCheck` --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc/middle/effect.rs | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 0521b50df4d2..b3878819378f 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -64,7 +64,6 @@ pub enum DepNode { CollectItem(D), CollectItemSig(D), Coherence, - EffectCheck, Liveness, Resolve, EntryPoint, @@ -219,7 +218,6 @@ impl DepNode { PluginRegistrar => Some(PluginRegistrar), StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), - EffectCheck => Some(EffectCheck), Liveness => Some(Liveness), Resolve => Some(Resolve), EntryPoint => Some(EntryPoint), diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5af8e7e52d88..d2b8ed8c2970 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -12,7 +12,6 @@ //! `unsafe`. use self::RootUnsafeContext::*; -use dep_graph::DepNode; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; use lint; @@ -241,8 +240,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::EffectCheck); - let mut visitor = EffectCheckVisitor { tcx: tcx, tables: &ty::TypeckTables::empty(), From 6bc3d65948c3606c29beb8da359d2a45a36e5c15 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 4 Apr 2017 10:31:57 -0500 Subject: [PATCH 288/905] rustdoc: properly indent fn signatures in traits --- src/librustdoc/html/format.rs | 28 +++++++++++++++----- src/librustdoc/html/render.rs | 50 +++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fd069ed7e076..9e45ccaff32b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -41,8 +41,6 @@ pub struct UnsafetySpace(pub hir::Unsafety); /// with a space after it. #[derive(Copy, Clone)] pub struct ConstnessSpace(pub hir::Constness); -/// Wrapper struct for properly emitting a method declaration. -pub struct Method<'a>(pub &'a clean::FnDecl, pub usize); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); @@ -55,10 +53,23 @@ pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); pub struct CommaSep<'a, T: 'a>(pub &'a [T]); pub struct AbiSpace(pub Abi); +/// Wrapper struct for properly emitting a method declaration. +pub struct Method<'a> { + /// The declaration to emit. + pub decl: &'a clean::FnDecl, + /// The length of the function's "name", used to determine line-wrapping. + pub name_len: usize, + /// The number of spaces to indent each successive line with, if line-wrapping is necessary. + pub indent: usize, +} + /// Wrapper struct for emitting a where clause from Generics. pub struct WhereClause<'a>{ + /// The Generics from which to emit a where clause. pub gens: &'a clean::Generics, + /// The number of spaces to indent each line with. pub indent: usize, + /// Whether the where clause needs to add a comma and newline after the last bound. pub end_newline: bool, } @@ -936,8 +947,7 @@ impl fmt::Display for clean::FnDecl { impl<'a> fmt::Display for Method<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let decl = self.0; - let indent = self.1; + let &Method { decl, name_len, indent } = self; let amp = if f.alternate() { "&" } else { "&" }; let mut args = String::new(); let mut args_plain = String::new(); @@ -1004,15 +1014,19 @@ impl<'a> fmt::Display for Method<'a> { format!("{}", decl.output) }; - let pad = repeat(" ").take(indent).collect::(); + let pad = repeat(" ").take(name_len).collect::(); let plain = format!("{pad}({args}){arrow}", pad = pad, args = args_plain, arrow = arrow_plain); let output = if plain.len() > 80 { - let pad = "
        "; - format!("({args}
    ){arrow}", args = args.replace("
    ", pad), arrow = arrow) + let full_pad = format!("
    {}", repeat(" ").take(indent + 4).collect::()); + let close_pad = format!("
    {}", repeat(" ").take(indent).collect::()); + format!("({args}{close}){arrow}", + args = args.replace("
    ", &full_pad), + close = close_pad, + arrow = arrow) } else { format!("({args}){arrow}", args = args.replace("
    ", ""), arrow = arrow) }; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4eb228ce68f4..be69f6b8ec22 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1995,13 +1995,13 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, UnstableFeatures::Allow => f.constness, _ => hir::Constness::NotConst }; - let indent = format!("{}{}{}{:#}fn {}{:#}", - VisSpace(&it.visibility), - ConstnessSpace(vis_constness), - UnsafetySpace(f.unsafety), - AbiSpace(f.abi), - it.name.as_ref().unwrap(), - f.generics).len(); + let name_len = format!("{}{}{}{:#}fn {}{:#}", + VisSpace(&it.visibility), + ConstnessSpace(vis_constness), + UnsafetySpace(f.unsafety), + AbiSpace(f.abi), + it.name.as_ref().unwrap(), + f.generics).len(); write!(w, "
    ")?;
         render_attributes(w, it)?;
         write!(w, "{vis}{constness}{unsafety}{abi}fn \
    @@ -2013,7 +2013,11 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                name = it.name.as_ref().unwrap(),
                generics = f.generics,
                where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
    -           decl = Method(&f.decl, indent))?;
    +           decl = Method {
    +               decl: &f.decl,
    +               name_len: name_len,
    +               indent: 0,
    +           })?;
         document(w, cx, it)
     }
     
    @@ -2326,21 +2330,17 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                 UnstableFeatures::Allow => constness,
                 _ => hir::Constness::NotConst
             };
    -        let prefix = format!("{}{}{:#}fn {}{:#}",
    -                             ConstnessSpace(vis_constness),
    -                             UnsafetySpace(unsafety),
    -                             AbiSpace(abi),
    -                             name,
    -                             *g);
    -        let mut indent = prefix.len();
    -        let (where_indent, end_newline) = if parent == ItemType::Trait {
    -            indent += 4;
    +        let mut head_len = format!("{}{}{:#}fn {}{:#}",
    +                                   ConstnessSpace(vis_constness),
    +                                   UnsafetySpace(unsafety),
    +                                   AbiSpace(abi),
    +                                   name,
    +                                   *g).len();
    +        let (indent, end_newline) = if parent == ItemType::Trait {
    +            head_len += 4;
                 (4, false)
    -        } else if parent == ItemType::Impl {
    -            (0, true)
             } else {
    -            let prefix = prefix + &format!("{:#}", Method(d, indent));
    -            (prefix.lines().last().unwrap().len() + 1, true)
    +            (0, true)
             };
             write!(w, "{}{}{}fn {name}\
                        {generics}{decl}{where_clause}",
    @@ -2350,10 +2350,14 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                    href = href,
                    name = name,
                    generics = *g,
    -               decl = Method(d, indent),
    +               decl = Method {
    +                   decl: d,
    +                   name_len: head_len,
    +                   indent: indent,
    +               },
                    where_clause = WhereClause {
                        gens: g,
    -                   indent: where_indent,
    +                   indent: indent,
                        end_newline: end_newline,
                    })
         }
    
    From cd14a323f42cf57695e713a4f4fd00fddc10efd5 Mon Sep 17 00:00:00 2001
    From: "Stephen M. Coakley" 
    Date: Tue, 4 Apr 2017 10:44:57 -0500
    Subject: [PATCH 289/905] Use derived Debug for ThreadId
    
    ---
     src/libstd/thread/mod.rs | 9 +--------
     1 file changed, 1 insertion(+), 8 deletions(-)
    
    diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
    index 21f9757ad116..9116f5417365 100644
    --- a/src/libstd/thread/mod.rs
    +++ b/src/libstd/thread/mod.rs
    @@ -670,7 +670,7 @@ pub fn park_timeout(dur: Duration) {
     /// assert!(thread::current().id() != other_thread_id);
     /// ```
     #[unstable(feature = "thread_id", issue = "21507")]
    -#[derive(Clone, Copy, Eq, PartialEq, Hash)]
    +#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
     pub struct ThreadId(u64);
     
     impl ThreadId {
    @@ -699,13 +699,6 @@ impl ThreadId {
         }
     }
     
    -#[unstable(feature = "thread_id", issue = "21507")]
    -impl fmt::Debug for ThreadId {
    -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    -        f.pad("ThreadId { .. }")
    -    }
    -}
    -
     ////////////////////////////////////////////////////////////////////////////////
     // Thread
     ////////////////////////////////////////////////////////////////////////////////
    
    From 3409f8d7cdfa2c60c5638930e3e68bbb6a911fc4 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
    Date: Tue, 4 Apr 2017 08:58:27 -0700
    Subject: [PATCH 290/905] Do not recommend private fields called as method
    
    ---
     src/librustc_typeck/check/method/suggest.rs   | 26 ++++++++++-------
     .../confuse-field-and-method/private-field.rs | 29 +++++++++++++++++++
     .../private-field.stderr                      |  8 +++++
     3 files changed, 52 insertions(+), 11 deletions(-)
     create mode 100644 src/test/ui/suggestions/confuse-field-and-method/private-field.rs
     create mode 100644 src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
    
    diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
    index 67ee7ef58653..4b975d7b324f 100644
    --- a/src/librustc_typeck/check/method/suggest.rs
    +++ b/src/librustc_typeck/check/method/suggest.rs
    @@ -196,19 +196,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     
                                         let field_ty = field.ty(tcx, substs);
     
    -                                    if self.is_fn_ty(&field_ty, span) {
    -                                        err.help(&format!("use `({0}.{1})(...)` if you \
    -                                                           meant to call the function \
    -                                                           stored in the `{1}` field",
    -                                                          expr_string,
    -                                                          item_name));
    +                                    if tcx.vis_is_accessible_from(field.vis, self.body_id) {
    +                                        if self.is_fn_ty(&field_ty, span) {
    +                                            err.help(&format!("use `({0}.{1})(...)` if you \
    +                                                               meant to call the function \
    +                                                               stored in the `{1}` field",
    +                                                              expr_string,
    +                                                              item_name));
    +                                        } else {
    +                                            err.help(&format!("did you mean to write `{0}.{1}` \
    +                                                               instead of `{0}.{1}(...)`?",
    +                                                              expr_string,
    +                                                              item_name));
    +                                        }
    +                                        err.span_label(span, &"field, not a method");
                                         } else {
    -                                        err.help(&format!("did you mean to write `{0}.{1}` \
    -                                                           instead of `{0}.{1}(...)`?",
    -                                                          expr_string,
    -                                                          item_name));
    +                                        err.span_label(span, &"private field, not a method");
                                         }
    -                                    err.span_label(span, &"field, not a method");
                                         break;
                                     }
                                 }
    diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.rs b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs
    new file mode 100644
    index 000000000000..94cf38fb32f2
    --- /dev/null
    +++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs
    @@ -0,0 +1,29 @@
    +// 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.
    +
    +pub mod animal {
    +    pub struct Dog {
    +        pub age: usize,
    +        dog_age: usize,
    +    }
    +
    +    impl Dog {
    +        pub fn new(age: usize) -> Dog {
    +            Dog { age: age, dog_age: age * 7 }
    +        }
    +    }
    +}
    +
    +fn main() {
    +    let dog = animal::Dog::new(3);
    +    let dog_age = dog.dog_age();
    +    //let dog_age = dog.dog_age;
    +    println!("{}", dog_age);
    +}
    diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
    new file mode 100644
    index 000000000000..d07885915d2b
    --- /dev/null
    +++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
    @@ -0,0 +1,8 @@
    +error: no method named `dog_age` found for type `animal::Dog` in the current scope
    +  --> $DIR/private-field.rs:26:23
    +   |
    +26 |     let dog_age = dog.dog_age();
    +   |                       ^^^^^^^ private field, not a method
    +
    +error: aborting due to previous error
    +
    
    From a2a4fad6f787869bc3ae96e02082938e0a6dbef9 Mon Sep 17 00:00:00 2001
    From: Niko Matsakis 
    Date: Tue, 4 Apr 2017 11:28:48 -0400
    Subject: [PATCH 291/905] kill `Liveness`
    
    ---
     src/librustc/dep_graph/dep_node.rs | 2 --
     src/librustc/middle/liveness.rs    | 2 --
     2 files changed, 4 deletions(-)
    
    diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
    index b3878819378f..59d04ea8c771 100644
    --- a/src/librustc/dep_graph/dep_node.rs
    +++ b/src/librustc/dep_graph/dep_node.rs
    @@ -64,7 +64,6 @@ pub enum DepNode {
         CollectItem(D),
         CollectItemSig(D),
         Coherence,
    -    Liveness,
         Resolve,
         EntryPoint,
         CheckEntryFn,
    @@ -218,7 +217,6 @@ impl DepNode {
                 PluginRegistrar => Some(PluginRegistrar),
                 StabilityIndex => Some(StabilityIndex),
                 Coherence => Some(Coherence),
    -            Liveness => Some(Liveness),
                 Resolve => Some(Resolve),
                 EntryPoint => Some(EntryPoint),
                 CheckEntryFn => Some(CheckEntryFn),
    diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
    index 7cae08efc0de..b7da8480c1ce 100644
    --- a/src/librustc/middle/liveness.rs
    +++ b/src/librustc/middle/liveness.rs
    @@ -109,7 +109,6 @@ use self::LoopKind::*;
     use self::LiveNodeKind::*;
     use self::VarKind::*;
     
    -use dep_graph::DepNode;
     use hir::def::*;
     use ty::{self, TyCtxt, ParameterEnvironment};
     use traits::{self, Reveal};
    @@ -196,7 +195,6 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> {
     }
     
     pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    -    let _task = tcx.dep_graph.in_task(DepNode::Liveness);
         tcx.hir.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor());
         tcx.sess.abort_if_errors();
     }
    
    From a4d7c1fec361219d237f39b5e32c09c72ca69fac Mon Sep 17 00:00:00 2001
    From: Niko Matsakis 
    Date: Tue, 4 Apr 2017 12:06:35 -0400
    Subject: [PATCH 292/905] push `borrowck` into its own task
    
    ---
     src/librustc/hir/map/mod.rs           | 21 +++++++++++++++++++
     src/librustc/ty/maps.rs               |  2 ++
     src/librustc_borrowck/borrowck/mod.rs | 30 +++++++++++++--------------
     src/librustc_borrowck/lib.rs          |  2 ++
     src/librustc_driver/driver.rs         |  1 +
     5 files changed, 41 insertions(+), 15 deletions(-)
    
    diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
    index d7aa36b24f94..cfafec00ae20 100644
    --- a/src/librustc/hir/map/mod.rs
    +++ b/src/librustc/hir/map/mod.rs
    @@ -442,6 +442,27 @@ impl<'hir> Map<'hir> {
             self.local_def_id(self.body_owner(id))
         }
     
    +    /// Given a body owner's id, returns the `BodyId` associated with it.
    +    pub fn body_owned_by(&self, id: NodeId) -> BodyId {
    +        if let Some(entry) = self.find_entry(id) {
    +            if let Some(body_id) = entry.associated_body() {
    +                // For item-like things and closures, the associated
    +                // body has its own distinct id, and that is returned
    +                // by `associated_body`.
    +                body_id
    +            } else {
    +                // For some expressions, the expression is its own body.
    +                if let EntryExpr(_, expr) = entry {
    +                    BodyId { node_id: expr.id }
    +                } else {
    +                    span_bug!(self.span(id), "id `{}` has no associated body", id);
    +                }
    +            }
    +        } else {
    +            bug!("no entry for id `{}`", id)
    +        }
    +    }
    +
         pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
             match self.get(id) {
                 NodeItem(&Item { node: ItemTrait(..), .. }) => id,
    diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
    index 4a183191cef2..219dbc4998e0 100644
    --- a/src/librustc/ty/maps.rs
    +++ b/src/librustc/ty/maps.rs
    @@ -423,6 +423,8 @@ define_maps! { <'tcx>
     
         pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
     
    +    pub borrowck: BorrowCheck(DefId) -> (),
    +
         /// Gets a complete map from all types to their inherent impls.
         /// Not meant to be used directly outside of coherence.
         /// (Defined only for LOCAL_CRATE)
    diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
    index 0915c57b588e..e0b4a23010d2 100644
    --- a/src/librustc_borrowck/borrowck/mod.rs
    +++ b/src/librustc_borrowck/borrowck/mod.rs
    @@ -22,7 +22,6 @@ pub use self::mir::elaborate_drops::ElaborateDrops;
     
     use self::InteriorKind::*;
     
    -use rustc::dep_graph::DepNode;
     use rustc::hir::map as hir_map;
     use rustc::hir::map::blocks::FnLikeNode;
     use rustc::cfg;
    @@ -37,12 +36,13 @@ use rustc::middle::mem_categorization::Categorization;
     use rustc::middle::mem_categorization::ImmutabilityBlame;
     use rustc::middle::region;
     use rustc::ty::{self, TyCtxt};
    +use rustc::ty::maps::Providers;
     
     use std::fmt;
     use std::rc::Rc;
     use std::hash::{Hash, Hasher};
     use syntax::ast;
    -use syntax_pos::{MultiSpan, Span};
    +use syntax_pos::{DUMMY_SP, MultiSpan, Span};
     use errors::DiagnosticBuilder;
     
     use rustc::hir;
    @@ -62,16 +62,16 @@ pub struct LoanDataFlowOperator;
     pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
     
     pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    -    tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task);
    +    tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
    +        ty::queries::borrowck::get(tcx, DUMMY_SP, body_owner_def_id);
    +    });
    +}
     
    -    fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) {
    -        tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| {
    -            tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id),
    -                                    tcx,
    -                                    body_id,
    -                                    borrowck_fn);
    -        });
    -    }
    +pub fn provide(providers: &mut Providers) {
    +    *providers = Providers {
    +        borrowck: borrowck,
    +        ..*providers
    +    };
     }
     
     /// Collection of conclusions determined via borrow checker analyses.
    @@ -81,11 +81,11 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
         pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
     }
     
    -fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) {
    -    debug!("borrowck_fn(body_id={:?})", body_id);
    +fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
    +    debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
     
    -    let owner_id = tcx.hir.body_owner(body_id);
    -    let owner_def_id = tcx.hir.local_def_id(owner_id);
    +    let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap();
    +    let body_id = tcx.hir.body_owned_by(owner_id);
         let attributes = tcx.get_attrs(owner_def_id);
         let tables = tcx.item_tables(owner_def_id);
     
    diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
    index d3b22884a3d8..a1d3357faf56 100644
    --- a/src/librustc_borrowck/lib.rs
    +++ b/src/librustc_borrowck/lib.rs
    @@ -51,4 +51,6 @@ mod borrowck;
     
     pub mod graphviz;
     
    +pub use borrowck::provide;
    +
     __build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS }
    diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
    index 977382b33adf..13486d898cff 100644
    --- a/src/librustc_driver/driver.rs
    +++ b/src/librustc_driver/driver.rs
    @@ -887,6 +887,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
         let mut local_providers = ty::maps::Providers::default();
         mir::provide(&mut local_providers);
         rustc_privacy::provide(&mut local_providers);
    +    borrowck::provide(&mut local_providers);
         typeck::provide(&mut local_providers);
         ty::provide(&mut local_providers);
     
    
    From b012adc354100ee95c1695ae7934e86683f1774e Mon Sep 17 00:00:00 2001
    From: Tim Neumann 
    Date: Tue, 4 Apr 2017 18:14:14 +0200
    Subject: [PATCH 293/905] update image name for DEPLOY_ALT
    
    ---
     .travis.yml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/.travis.yml b/.travis.yml
    index a8c9337fa81b..e5b57a389ecb 100644
    --- a/.travis.yml
    +++ b/.travis.yml
    @@ -112,7 +112,7 @@ matrix:
         # turned on, they're deployed to a different location primarily for projects
         # which are stuck on nightly and don't want llvm assertions in the artifacts
         # that they use.
    -    - env: IMAGE=dist-x86-linux DEPLOY_ALT=1
    +    - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1
         - env: >
             RUST_CHECK_TARGET=dist
             RUST_CONFIGURE_ARGS="--enable-extended"
    
    From 5bffa0aa50f7456249e4ffdd3e7cbf72f743a56d Mon Sep 17 00:00:00 2001
    From: QuietMisdreavus 
    Date: Tue, 4 Apr 2017 11:16:16 -0500
    Subject: [PATCH 294/905] rustdoc: don't add a space before `{` on traits with
     where clauses
    
    cc #41025
    ---
     src/librustdoc/html/render.rs | 11 ++++++++---
     1 file changed, 8 insertions(+), 3 deletions(-)
    
    diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
    index be69f6b8ec22..b1ac6a5127f2 100644
    --- a/src/librustdoc/html/render.rs
    +++ b/src/librustdoc/html/render.rs
    @@ -2045,13 +2045,18 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
         // Output the trait definition
         write!(w, "
    ")?;
         render_attributes(w, it)?;
    -    write!(w, "{}{}trait {}{}{}{} ",
    +    write!(w, "{}{}trait {}{}{}",
                VisSpace(&it.visibility),
                UnsafetySpace(t.unsafety),
                it.name.as_ref().unwrap(),
                t.generics,
    -           bounds,
    -           WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
    +           bounds)?;
    +
    +    if !t.generics.where_predicates.is_empty() {
    +        write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
    +    } else {
    +        write!(w, " ")?;
    +    }
     
         let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>();
         let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>();
    
    From 8c01ce3d2552529af7597a60329d0552d2b0f325 Mon Sep 17 00:00:00 2001
    From: Alex Crichton 
    Date: Mon, 3 Apr 2017 11:41:45 -0700
    Subject: [PATCH 295/905] std: Use `poll` instead of `select`
    
    This gives us the benefit of supporting file descriptors over the limit that
    select supports, which...
    
    Closes #40894
    ---
     src/libstd/sys/unix/pipe.rs | 22 +++++++++-------------
     1 file changed, 9 insertions(+), 13 deletions(-)
    
    diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
    index 51e00fc1ab96..706256ff10ec 100644
    --- a/src/libstd/sys/unix/pipe.rs
    +++ b/src/libstd/sys/unix/pipe.rs
    @@ -8,11 +8,9 @@
     // option. This file may not be copied, modified, or distributed
     // except according to those terms.
     
    -use cmp;
     use io;
     use libc::{self, c_int};
     use mem;
    -use ptr;
     use sys::{cvt, cvt_r};
     use sys::fd::FileDesc;
     
    @@ -80,16 +78,14 @@ pub fn read2(p1: AnonPipe,
         p1.set_nonblocking(true)?;
         p2.set_nonblocking(true)?;
     
    -    let max = cmp::max(p1.raw(), p2.raw());
    +    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
    +    fds[0].fd = p1.raw();
    +    fds[0].events = libc::POLLIN;
    +    fds[1].fd = p2.raw();
    +    fds[1].events = libc::POLLIN;
         loop {
    -        // wait for either pipe to become readable using `select`
    -        cvt_r(|| unsafe {
    -            let mut read: libc::fd_set = mem::zeroed();
    -            libc::FD_SET(p1.raw(), &mut read);
    -            libc::FD_SET(p2.raw(), &mut read);
    -            libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
    -                         ptr::null_mut())
    -        })?;
    +        // wait for either pipe to become readable using `poll`
    +        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
     
             // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
             // EAGAIN. If we hit EOF, then this will happen because the underlying
    @@ -109,11 +105,11 @@ pub fn read2(p1: AnonPipe,
                     }
                 }
             };
    -        if read(&p1, v1)? {
    +        if fds[0].revents != 0 && read(&p1, v1)? {
                 p2.set_nonblocking(false)?;
                 return p2.read_to_end(v2).map(|_| ());
             }
    -        if read(&p2, v2)? {
    +        if fds[1].revents != 0 && read(&p2, v2)? {
                 p1.set_nonblocking(false)?;
                 return p1.read_to_end(v1).map(|_| ());
             }
    
    From 2e3f0d845113995c26a9d59dd69146975a692516 Mon Sep 17 00:00:00 2001
    From: Jason Orendorff 
    Date: Mon, 3 Apr 2017 15:25:30 -0500
    Subject: [PATCH 296/905] add [T]::rsplit() and rsplit_mut() #41020
    
    ---
     src/doc/unstable-book/src/SUMMARY.md      |   1 +
     src/doc/unstable-book/src/slice-rsplit.md |  10 ++
     src/libcollections/lib.rs                 |   1 +
     src/libcollections/slice.rs               |  68 +++++++++++
     src/libcore/slice/mod.rs                  | 139 ++++++++++++++++++++++
     5 files changed, 219 insertions(+)
     create mode 100644 src/doc/unstable-book/src/slice-rsplit.md
    
    diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
    index 292f5a1ec816..52f33244695e 100644
    --- a/src/doc/unstable-book/src/SUMMARY.md
    +++ b/src/doc/unstable-book/src/SUMMARY.md
    @@ -171,6 +171,7 @@
     - [slice_concat_ext](slice-concat-ext.md)
     - [slice_get_slice](slice-get-slice.md)
     - [slice_patterns](slice-patterns.md)
    +- [slice_rsplit](slice-rsplit.md)
     - [sort_internals](sort-internals.md)
     - [sort_unstable](sort-unstable.md)
     - [specialization](specialization.md)
    diff --git a/src/doc/unstable-book/src/slice-rsplit.md b/src/doc/unstable-book/src/slice-rsplit.md
    new file mode 100644
    index 000000000000..8c2954f7294e
    --- /dev/null
    +++ b/src/doc/unstable-book/src/slice-rsplit.md
    @@ -0,0 +1,10 @@
    +# `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/libcollections/lib.rs b/src/libcollections/lib.rs
    index 00448b6abb2c..ff020f53e0e7 100644
    --- a/src/libcollections/lib.rs
    +++ b/src/libcollections/lib.rs
    @@ -52,6 +52,7 @@
     #![feature(shared)]
     #![feature(slice_get_slice)]
     #![feature(slice_patterns)]
    +#![feature(slice_rsplit)]
     #![cfg_attr(not(test), feature(sort_unstable))]
     #![feature(specialization)]
     #![feature(staged_api)]
    diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
    index 6f8843c2374b..6cff315a6ccd 100644
    --- a/src/libcollections/slice.rs
    +++ b/src/libcollections/slice.rs
    @@ -115,6 +115,8 @@ 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")]
    +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 = "slice_get_slice", issue = "35729")]
    @@ -779,6 +781,72 @@ impl [T] {
             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
    +    ///
    +    /// ```
    +    /// #![feature(slice_rsplit)]
    +    ///
    +    /// 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.
    +    ///
    +    /// ```
    +    /// #![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(), &[]);
    +    /// assert_eq!(it.next().unwrap(), &[3, 5]);
    +    /// assert_eq!(it.next().unwrap(), &[1, 1]);
    +    /// assert_eq!(it.next().unwrap(), &[]);
    +    /// assert_eq!(it.next(), None);
    +    /// ```
    +    #[unstable(feature = "slice_rsplit", issue = "41020")]
    +    #[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
    +    ///
    +    /// ```
    +    /// #![feature(slice_rsplit)]
    +    ///
    +    /// 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]);
    +    /// ```
    +    ///
    +    #[unstable(feature = "slice_rsplit", issue = "41020")]
    +    #[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.
    diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
    index 45667bb42993..1e0037755c1a 100644
    --- a/src/libcore/slice/mod.rs
    +++ b/src/libcore/slice/mod.rs
    @@ -81,6 +81,10 @@ pub trait SliceExt {
         fn split

    (&self, pred: P) -> Split where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + 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; @@ -159,6 +163,10 @@ pub trait SliceExt { fn split_mut

    (&mut self, pred: P) -> SplitMut where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + 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; @@ -293,6 +301,13 @@ impl SliceExt for [T] { } } + #[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 @@ -475,6 +490,13 @@ impl SliceExt for [T] { 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 @@ -1735,6 +1757,123 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where #[unstable(feature = "fused", issue = "35602")] 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 +/// function, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit`] method on [slices]. +/// +/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +#[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")] +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") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + self.inner.next() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + self.inner.finish() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +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 +/// by elements that match `pred`, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit_mut`] method on [slices]. +/// +/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { + inner: SplitMut<'a, T, P> +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +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") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + self.inner.finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + self.inner.next() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} + /// An private iterator over subslices separated by elements that /// match a predicate function, splitting at most a fixed number of /// times. From a45fedfa384fba4f972c2af26adb9cf7a0522725 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Mon, 3 Apr 2017 15:27:42 -0500 Subject: [PATCH 297/905] simplify implementation of [T]::splitn and friends #41020 --- src/libcore/slice/mod.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 1e0037755c1a..6e3f11ec7fba 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -315,8 +315,7 @@ impl SliceExt for [T] { SplitN { inner: GenericSplitN { iter: self.split(pred), - count: n, - invert: false + count: n } } } @@ -327,9 +326,8 @@ impl SliceExt for [T] { { RSplitN { inner: GenericSplitN { - iter: self.split(pred), - count: n, - invert: true + iter: self.rsplit(pred), + count: n } } } @@ -504,8 +502,7 @@ impl SliceExt for [T] { SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), - count: n, - invert: false + count: n } } } @@ -516,9 +513,8 @@ impl SliceExt for [T] { { RSplitNMut { inner: GenericSplitN { - iter: self.split_mut(pred), - count: n, - invert: true + iter: self.rsplit_mut(pred), + count: n } } } @@ -1881,7 +1877,6 @@ impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool struct GenericSplitN { iter: I, count: usize, - invert: bool } impl> Iterator for GenericSplitN { @@ -1892,10 +1887,7 @@ impl> Iterator for GenericSplitN { match self.count { 0 => None, 1 => { self.count -= 1; self.iter.finish() } - _ => { - self.count -= 1; - if self.invert {self.iter.next_back()} else {self.iter.next()} - } + _ => { self.count -= 1; self.iter.next() } } } @@ -1937,7 +1929,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitN<'a, T, P> where P: FnMut(& /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN> + inner: GenericSplitN> } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -1980,7 +1972,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitNMut<'a, T, P> where P: FnMu /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN> + inner: GenericSplitN> } #[stable(feature = "core_impl_debug", since = "1.9.0")] From 086627ecd24308d773a9e5a2765d0c1f19f0226e Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 4 Apr 2017 15:39:44 -0400 Subject: [PATCH 298/905] Fix links part of https://github.com/rust-lang/rust/issues/40912 []\n() is not actually a link. --- src/libcollections/linked_list.rs | 4 +- src/libcore/intrinsics.rs | 90 ++++++++++++++++++------------- src/libtest/stats.rs | 6 ++- 3 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 8f0488f69369..1b3eeb837d90 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -697,8 +697,8 @@ impl LinkedList { /// 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. + /// Using this method with placement syntax is equivalent to + /// [`push_front`](#method.push_front), but may be more efficient. /// /// # Examples /// diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ae8b6bb4511..7339fb56e5b4 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -61,16 +61,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -79,8 +81,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -89,16 +92,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -107,8 +112,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -117,8 +123,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -127,8 +134,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -137,8 +145,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. @@ -146,16 +155,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -164,8 +175,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -174,16 +186,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -192,8 +206,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -202,8 +217,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -212,8 +228,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -222,8 +239,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// + /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 077d57a9da38..f04394f71666 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -39,8 +39,10 @@ pub trait Stats { /// /// Note: this method sacrifices performance at the altar of accuracy /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: - /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates"] - /// (http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps) + /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric + /// Predicates"][paper] + /// + /// [paper]: http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps fn sum(&self) -> f64; /// Minimum value of the samples. From ea2bfae8694221c92857a0b3dd96f63a8a255db2 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Tue, 4 Apr 2017 13:50:24 -0600 Subject: [PATCH 299/905] Branch arms need to match the return value even if it's not being assigned to anything --- src/bootstrap/flags.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 3af3b76163c1..a1466d68a135 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -137,10 +137,10 @@ To learn more about a subcommand, run `./x.py -h`"); // Some subcommands get extra options match subcommand.as_str() { - "test" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), - "bench" => opts.optmulti("", "test-args", "extra arguments", "ARGS"), - "dist" => opts.optflag("", "install", "run installer as well"), - _ => { } + "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "dist" => { opts.optflag("", "install", "run installer as well"); }, + _ => { }, }; // Done specifying what options are possible, so do the getopts parsing From c7f2dbef90231eab0b0f2032854823d192a964eb Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Tue, 4 Apr 2017 16:23:52 -0400 Subject: [PATCH 300/905] Change docs to follow review requests --- src/libstd/process.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 265228281f85..123138daeeae 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -233,9 +233,9 @@ impl fmt::Debug for ChildStdout { } } -/// A handle to a child process's stderr. It can be used to -/// read any errors that the child process has output while -/// running. +/// A handle to a child process's stderr. +/// +/// This struct is used in the [`stderr`] field on [`Child`]. /// /// [`Child`]: struct.Child.html /// [`stderr`]: struct.Child.html#structfield.stderr From f07ebd609796226e672737e502525fbbf5e27940 Mon Sep 17 00:00:00 2001 From: arthurprs Date: Wed, 15 Mar 2017 23:26:27 +0100 Subject: [PATCH 301/905] Simplify HashMap Bucket interface * Store capacity_mask instead of capacity * Move bucket index into RawBucket * Bucket index is now always within [0..table_capacity) * Clone RawTable using RawBucket * Simplify iterators by moving logic into RawBuckets * Make retain aware of the number of elements --- src/libstd/collections/hash/map.rs | 32 ++- src/libstd/collections/hash/table.rs | 322 +++++++++++++-------------- 2 files changed, 164 insertions(+), 190 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 573321700814..a06299eaefe0 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -472,7 +472,7 @@ fn pop_internal(starting_bucket: FullBucketMut) } // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval, gap.into_bucket().into_table()) + (retkey, retval, gap.into_table()) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, mut key: K, mut val: V) -> FullBucketMut<'a, K, V> { - let start_index = bucket.index(); let size = bucket.table().size(); - // Save the *starting point*. - let mut bucket = bucket.stash(); + let raw_capacity = bucket.table().capacity(); // There can be at most `size - dib` buckets to displace, because // in the worst case, there are `size` elements and we already are // `displacement` buckets away from the initial one. - let idx_end = start_index + size - bucket.displacement(); + let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; + // Save the *starting point*. + let mut bucket = bucket.stash(); loop { let (old_hash, old_key, old_val) = bucket.replace(hash, key, val); @@ -568,11 +568,8 @@ impl HashMap // The caller should ensure that invariants by Robin Hood Hashing hold // and that there's space in the underlying table. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let raw_cap = self.raw_capacity(); let mut buckets = Bucket::new(&mut self.table, hash); - // note that buckets.index() keeps increasing - // even if the pointer wraps back to the first bucket. - let limit_bucket = buckets.index() + raw_cap; + let start_index = buckets.index(); loop { // We don't need to compare hashes for value swap. @@ -585,7 +582,7 @@ impl HashMap Full(b) => b.into_bucket(), }; buckets.next(); - debug_assert!(buckets.index() < limit_bucket); + debug_assert!(buckets.index() != start_index); } } } @@ -1244,24 +1241,25 @@ impl HashMap pub fn retain(&mut self, mut f: F) where F: FnMut(&K, &mut V) -> bool { - if self.table.capacity() == 0 || self.table.size() == 0 { + if self.table.size() == 0 { return; } + let mut elems_left = self.table.size(); let mut bucket = Bucket::head_bucket(&mut self.table); bucket.prev(); - let tail = bucket.index(); - loop { + let start_index = bucket.index(); + while elems_left != 0 { bucket = match bucket.peek() { Full(mut full) => { + elems_left -= 1; let should_remove = { let (k, v) = full.read_mut(); !f(k, v) }; if should_remove { - let prev_idx = full.index(); let prev_raw = full.raw(); let (_, _, t) = pop_internal(full); - Bucket::new_from(prev_raw, prev_idx, t) + Bucket::new_from(prev_raw, t) } else { full.into_bucket() } @@ -1271,9 +1269,7 @@ impl HashMap } }; bucket.prev(); // reverse iteration - if bucket.index() == tail { - break; - } + debug_assert!(elems_left == 0 || bucket.index() != start_index); } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index da5fb1a47333..9623706548b3 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -113,7 +113,7 @@ impl TaggedHashUintPtr { /// when the RawTable is created and is accessible with the `tag` and `set_tag` /// functions. pub struct RawTable { - capacity: usize, + capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, @@ -125,10 +125,13 @@ pub struct RawTable { unsafe impl Send for RawTable {} unsafe impl Sync for RawTable {} +// An unsafe view of a RawTable bucket +// Valid indexes are within [0..table_capacity) pub struct RawBucket { - hash: *mut HashUint, + hash_start: *mut HashUint, // We use *const to ensure covariance with respect to K and V - pair: *const (K, V), + pair_start: *const (K, V), + idx: usize, _marker: marker::PhantomData<(K, V)>, } @@ -141,7 +144,6 @@ impl Clone for RawBucket { pub struct Bucket { raw: RawBucket, - idx: usize, table: M, } @@ -154,13 +156,11 @@ impl Clone for Bucket { pub struct EmptyBucket { raw: RawBucket, - idx: usize, table: M, } pub struct FullBucket { raw: RawBucket, - idx: usize, table: M, } @@ -232,13 +232,17 @@ fn can_alias_safehash_as_hash() { assert_eq!(size_of::(), size_of::()) } +// RawBucket methods are unsafe as it's possible to +// make a RawBucket point to invalid memory using safe code. impl RawBucket { - unsafe fn offset(self, count: isize) -> RawBucket { - RawBucket { - hash: self.hash.offset(count), - pair: self.pair.offset(count), - _marker: marker::PhantomData, - } + unsafe fn hash(&self) -> *mut HashUint { + self.hash_start.offset(self.idx as isize) + } + unsafe fn pair(&self) -> *mut (K, V) { + self.pair_start.offset(self.idx as isize) as *mut (K, V) + } + unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) { + (self.hash(), self.pair()) } } @@ -258,7 +262,7 @@ impl FullBucket { } /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// Get the raw bucket. pub fn raw(&self) -> RawBucket { @@ -280,7 +284,7 @@ impl EmptyBucket { impl Bucket { /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// get the table. pub fn into_table(self) -> M { @@ -331,12 +335,11 @@ impl>> Bucket { Bucket::at_index(table, hash.inspect() as usize) } - pub fn new_from(r: RawBucket, i: usize, t: M) + pub fn new_from(r: RawBucket, t: M) -> Bucket { Bucket { raw: r, - idx: i, table: t, } } @@ -346,18 +349,16 @@ impl>> Bucket { // This is an uncommon case though, so avoid it in release builds. debug_assert!(table.capacity() > 0, "Table should have capacity at this point"); - let ib_index = ib_index & (table.capacity() - 1); + let ib_index = ib_index & table.capacity_mask; Bucket { - raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) }, - idx: ib_index, + raw: table.raw_bucket_at(ib_index), table: table, } } pub fn first(table: M) -> Bucket { Bucket { - raw: table.first_bucket_raw(), - idx: 0, + raw: table.raw_bucket_at(0), table: table, } } @@ -401,48 +402,30 @@ impl>> Bucket { /// the appropriate types to call most of the other functions in /// this module. pub fn peek(self) -> BucketState { - match unsafe { *self.raw.hash } { + match unsafe { *self.raw.hash() } { EMPTY_BUCKET => { Empty(EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } _ => { Full(FullBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } } } - /// Modifies the bucket pointer in place to make it point to the next slot. + /// Modifies the bucket in place to make it point to the next slot. pub fn next(&mut self) { - self.idx += 1; - let range = self.table.capacity(); - // This code is branchless thanks to a conditional move. - let dist = if self.idx & (range - 1) == 0 { - 1 - range as isize - } else { - 1 - }; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask; } - /// Modifies the bucket pointer in place to make it point to the previous slot. + /// Modifies the bucket in place to make it point to the previous slot. pub fn prev(&mut self) { - let range = self.table.capacity(); - let new_idx = self.idx.wrapping_sub(1) & (range - 1); - let dist = (new_idx as isize).wrapping_sub(self.idx as isize); - self.idx = new_idx; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask; } } @@ -458,7 +441,6 @@ impl>> EmptyBucket { pub fn into_bucket(self) -> Bucket { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -466,7 +448,6 @@ impl>> EmptyBucket { pub fn gap_peek(self) -> Result, Bucket> { let gap = EmptyBucket { raw: self.raw, - idx: self.idx, table: (), }; @@ -494,15 +475,14 @@ impl EmptyBucket /// Use `make_hash` to construct a `SafeHash` to pass to this function. pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket { unsafe { - *self.raw.hash = hash.inspect(); - ptr::write(self.raw.pair as *mut (K, V), (key, value)); + *self.raw.hash() = hash.inspect(); + ptr::write(self.raw.pair(), (key, value)); self.table.borrow_table_mut().size += 1; } FullBucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -510,15 +490,14 @@ impl EmptyBucket /// 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_mut = self.raw.pair as *mut (K, V); - ptr::write(&mut (*pair_mut).0, key); + *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, - idx: self.idx, table: self.table, } } @@ -536,7 +515,6 @@ impl>> FullBucket { pub fn into_bucket(self) -> Bucket { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -546,7 +524,6 @@ impl>> FullBucket { pub fn stash(self) -> FullBucket { FullBucket { raw: self.raw, - idx: self.idx, table: self, } } @@ -560,17 +537,20 @@ impl>> FullBucket { // Calculates the distance one has to travel when going from // `hash mod capacity` onwards to `idx mod capacity`, wrapping around // if the destination is not reached before the end of the table. - (self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1) + (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask } #[inline] pub fn hash(&self) -> SafeHash { - unsafe { SafeHash { hash: *self.raw.hash } } + unsafe { SafeHash { hash: *self.raw.hash() } } } /// Gets references to the key and value at a given index. pub fn read(&self) -> (&K, &V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -586,11 +566,10 @@ impl<'t, K, V> FullBucket> { self.table.size -= 1; unsafe { - *self.raw.hash = EMPTY_BUCKET; - let (k, v) = ptr::read(self.raw.pair); + *self.raw.hash() = EMPTY_BUCKET; + let (k, v) = ptr::read(self.raw.pair()); (EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }, k, @@ -604,9 +583,9 @@ impl<'t, K, V> FullBucket> { pub unsafe fn remove_key(&mut self) { self.table.size -= 1; - *self.raw.hash = EMPTY_BUCKET; - let pair_mut = self.raw.pair as *mut (K, V); - ptr::drop_in_place(&mut (*pair_mut).0); // only drop key + *self.raw.hash() = EMPTY_BUCKET; + let pair_ptr = self.raw.pair(); + ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key } } @@ -617,8 +596,8 @@ impl FullBucket { pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unsafe { - let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h); - let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v)); + let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); + let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); (old_hash, old_key, old_val) } @@ -630,8 +609,10 @@ impl FullBucket { /// Gets mutable references to the key and value at a given index. pub fn read_mut(&mut self) -> (&mut K, &mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -644,7 +625,10 @@ impl<'t, K, V, M> FullBucket /// in exchange for this, the returned references have a longer lifetime /// than the references returned by `read()`. pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -654,8 +638,10 @@ impl<'t, K, V, M> FullBucket /// This works similarly to `into_refs`, exchanging a bucket state /// for mutable references into the table. pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -667,22 +653,23 @@ impl GapThenFull &self.full } - pub fn into_bucket(self) -> Bucket { - self.full.into_bucket() + pub fn into_table(self) -> M { + self.full.into_table() } pub fn shift(mut self) -> Result, Bucket> { unsafe { - *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); + let (gap_hash, gap_pair) = self.gap.raw.hash_pair(); + let (full_hash, full_pair) = self.full.raw.hash_pair(); + *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET); + ptr::copy_nonoverlapping(full_pair, gap_pair, 1); } - let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full; + let FullBucket { raw: prev_raw, .. } = self.full; match self.full.next().peek() { Full(bucket) => { self.gap.raw = prev_raw; - self.gap.idx = prev_idx; self.full = bucket; @@ -761,7 +748,7 @@ impl RawTable { if capacity == 0 { return RawTable { size: 0, - capacity: 0, + capacity_mask: capacity.wrapping_sub(1), hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), marker: marker::PhantomData, }; @@ -801,25 +788,27 @@ impl RawTable { let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; RawTable { - capacity: capacity, + capacity_mask: capacity.wrapping_sub(1), size: 0, hashes: TaggedHashUintPtr::new(hashes), marker: marker::PhantomData, } } - fn first_bucket_raw(&self) -> RawBucket { - let hashes_size = self.capacity * size_of::(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + 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 buffer = self.hashes.ptr() as *mut u8; let (pairs_offset, _, oflo) = calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); debug_assert!(!oflo, "capacity overflow"); + + let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { - hash: self.hashes.ptr(), - pair: buffer.offset(pairs_offset as isize) as *const _, + hash_start: buffer as *mut HashUint, + pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + idx: index, _marker: marker::PhantomData, } } @@ -837,7 +826,7 @@ impl RawTable { /// The hashtable's capacity, similar to a vector's. pub fn capacity(&self) -> usize { - self.capacity + self.capacity_mask.wrapping_add(1) } /// The number of elements ever `put` in the hashtable, minus the number @@ -848,8 +837,8 @@ impl RawTable { fn raw_buckets(&self) -> RawBuckets { RawBuckets { - raw: self.first_bucket_raw(), - hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) }, + raw: self.raw_bucket_at(0), + elems_left: self.size, marker: marker::PhantomData, } } @@ -857,25 +846,23 @@ impl RawTable { pub fn iter(&self) -> Iter { Iter { iter: self.raw_buckets(), - elems_left: self.size(), } } pub fn iter_mut(&mut self) -> IterMut { IterMut { iter: self.raw_buckets(), - elems_left: self.size(), _marker: marker::PhantomData, } } pub fn into_iter(self) -> IntoIter { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. IntoIter { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: self, @@ -883,12 +870,12 @@ impl RawTable { } pub fn drain(&mut self) -> Drain { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. Drain { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: unsafe { Shared::new(self) }, @@ -900,18 +887,16 @@ impl RawTable { /// state and should only be used for dropping the table's remaining /// entries. It's used in the implementation of Drop. unsafe fn rev_drop_buckets(&mut self) { - let first_raw = self.first_bucket_raw(); - let mut raw = first_raw.offset(self.capacity as isize); + // initialize the raw bucket past the end of the table + let mut raw = self.raw_bucket_at(self.capacity()); let mut elems_left = self.size; while elems_left != 0 { - debug_assert!(raw.hash != first_raw.hash); + raw.idx -= 1; - raw = raw.offset(-1); - - if *raw.hash != EMPTY_BUCKET { + if *raw.hash() != EMPTY_BUCKET { elems_left -= 1; - ptr::drop_in_place(raw.pair as *mut (K, V)); + ptr::drop_in_place(raw.pair()); } } } @@ -931,7 +916,7 @@ impl RawTable { /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { raw: RawBucket, - hashes_end: *mut HashUint, + elems_left: usize, // Strictly speaking, this should be &'a (K,V), but that would // require that K:'a, and we often use RawBuckets<'static...> for @@ -946,7 +931,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> { fn clone(&self) -> RawBuckets<'a, K, V> { RawBuckets { raw: self.raw, - hashes_end: self.hashes_end, + elems_left: self.elems_left, marker: marker::PhantomData, } } @@ -957,25 +942,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { type Item = RawBucket; fn next(&mut self) -> Option> { - while self.raw.hash != self.hashes_end { + if self.elems_left == 0 { + return None; + } + + loop { unsafe { - // We are swapping out the pointer to a bucket and replacing - // it with the pointer to the next one. - let prev = ptr::replace(&mut self.raw, self.raw.offset(1)); - if *prev.hash != EMPTY_BUCKET { - return Some(prev); + let item = self.raw; + self.raw.idx += 1; + if *item.hash() != EMPTY_BUCKET { + self.elems_left -= 1; + return Some(item); } } } + } - None + fn size_hint(&self) -> (usize, Option) { + (self.elems_left, Some(self.elems_left)) + } +} + +impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> { + fn len(&self) -> usize { + self.elems_left } } /// Iterator over shared references to entries in a table. pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, } unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {} @@ -986,16 +982,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } - /// Iterator over mutable references to entries in a table. pub struct IterMut<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, // To ensure invariance with respect to V _marker: marker::PhantomData<&'a mut V>, } @@ -1009,7 +1002,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { pub fn iter(&self) -> Iter { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } @@ -1027,7 +1019,6 @@ impl IntoIter { pub fn iter(&self) -> Iter { Iter { iter: self.iter.clone(), - elems_left: self.table.size, } } } @@ -1044,11 +1035,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {} impl<'a, K, V> Drain<'a, K, V> { pub fn iter(&self) -> Iter { - unsafe { - Iter { - iter: self.iter.clone(), - elems_left: (**self.table).size, - } + Iter { + iter: self.iter.clone(), } } } @@ -1057,19 +1045,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1077,20 +1066,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - let pair_mut = bucket.pair as *mut (K, V); - unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &mut (*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1098,23 +1087,23 @@ impl Iterator for IntoIter { type Item = (SafeHash, K, V); fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { + self.iter.next().map(|raw| { self.table.size -= 1; unsafe { - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: *bucket.hash }, k, v) + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: *raw.hash() }, k, v) } }) } fn size_hint(&self) -> (usize, Option) { - let size = self.table.size(); - (size, Some(size)) + self.iter.size_hint() } } + impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { - self.table.size() + self.iter().len() } } @@ -1123,23 +1112,21 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { - unsafe { - (*self.table.as_mut_ptr()).size -= 1; - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) - } + self.iter.next().map(|raw| unsafe { + (*self.table.as_mut_ptr()).size -= 1; + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) }) } fn size_hint(&self) -> (usize, Option) { - let size = unsafe { (**self.table).size() }; - (size, Some(size)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { fn len(&self) -> usize { - unsafe { (**self.table).size() } + self.iter.len() } } @@ -1152,30 +1139,21 @@ impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { impl Clone for RawTable { fn clone(&self) -> RawTable { unsafe { - let mut new_ht = RawTable::new_uninitialized(self.capacity()); + let cap = self.capacity(); + let mut new_ht = RawTable::new_uninitialized(cap); - { - let cap = self.capacity(); - let mut new_buckets = Bucket::first(&mut new_ht); - let mut buckets = Bucket::first(self); - while buckets.index() != cap { - match buckets.peek() { - Full(full) => { - let (h, k, v) = { - let (k, v) = full.read(); - (full.hash(), k.clone(), v.clone()) - }; - *new_buckets.raw.hash = h.inspect(); - ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v)); - } - Empty(..) => { - *new_buckets.raw.hash = EMPTY_BUCKET; - } - } - new_buckets.next(); - buckets.next(); + let mut new_buckets = new_ht.raw_bucket_at(0); + let mut buckets = self.raw_bucket_at(0); + while buckets.idx < cap { + *new_buckets.hash() = *buckets.hash(); + if *new_buckets.hash() != EMPTY_BUCKET { + let pair_ptr = buckets.pair(); + let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone()); + ptr::write(new_buckets.pair(), kv); } - }; + buckets.idx += 1; + new_buckets.idx += 1; + } new_ht.size = self.size(); @@ -1186,7 +1164,7 @@ impl Clone for RawTable { unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { fn drop(&mut self) { - if self.capacity == 0 { + if self.capacity() == 0 { return; } @@ -1202,8 +1180,8 @@ 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 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, From b970bc2a79719b5c1573fb87c96773ce131dbb8d Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Tue, 4 Apr 2017 22:51:16 +0100 Subject: [PATCH 302/905] Enable appveyor cache, add more paranoia --- appveyor.yml | 7 +++++-- src/ci/init_repo.sh | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 68b2a239aff1..b0adda4bdb90 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -141,15 +141,18 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' + - if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc + - sh src/ci/init_repo.sh . /c/cache/rustsrc - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh on_failure: - - cat %CD%/sccache.log + - cat %CD%\sccache.log + - cat C:\Users\appveyor\AppData\Local\Temp\1\build-cache-logs\*.log cache: + - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 4e22907d9794..c235681cddd0 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -38,9 +38,20 @@ fi # Wipe the cache if it's not valid, or mark it as invalid while we update it if [ ! -f "$cache_valid_file" ]; then - rm -rf "$CACHE_DIR" && mkdir "$CACHE_DIR" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" else - rm "$cache_valid_file" + stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) + stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1 && echo $?) + if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then + # Something is badly wrong - the cache valid file is here, but something + # about the git repo is fishy. Nuke it all, just in case + echo "WARNING: $cache_valid_file exists but bad repo: l:$stat_lines, ec:$stat_ec" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" + else + rm "$cache_valid_file" + fi fi # Update the cache (a pristine copy of the rust source master) From e60ea55f660bfd0d34fc18efa60b2d9764840601 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 4 Apr 2017 15:55:23 -0700 Subject: [PATCH 303/905] travis: Update sccache binaries I've tracked down what I believe is the last spurious sccache failure on #40240 to behavior in mio (carllerche/mio#583), and this commit updates the binaries to a version which has that fix incorporated. --- .travis.yml | 2 +- appveyor.yml | 4 ++-- src/ci/docker/armhf-gnu/Dockerfile | 2 +- src/ci/docker/cross/Dockerfile | 2 +- src/ci/docker/dist-aarch64-linux/Dockerfile | 2 +- src/ci/docker/dist-android/Dockerfile | 2 +- src/ci/docker/dist-arm-linux/Dockerfile | 2 +- src/ci/docker/dist-armhf-linux/Dockerfile | 2 +- src/ci/docker/dist-armv7-linux/Dockerfile | 2 +- src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 2 +- src/ci/docker/dist-i686-freebsd/Dockerfile | 2 +- src/ci/docker/dist-i686-linux/Dockerfile | 2 +- src/ci/docker/dist-mips-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64-linux/Dockerfile | 2 +- src/ci/docker/dist-mips64el-linux/Dockerfile | 2 +- src/ci/docker/dist-mipsel-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64-linux/Dockerfile | 2 +- src/ci/docker/dist-powerpc64le-linux/Dockerfile | 2 +- src/ci/docker/dist-s390x-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-freebsd/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-musl/Dockerfile | 2 +- src/ci/docker/dist-x86_64-netbsd/Dockerfile | 2 +- src/ci/docker/emscripten/Dockerfile | 2 +- src/ci/docker/i686-gnu-nopt/Dockerfile | 2 +- src/ci/docker/i686-gnu/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-aux/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-debug/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-distcheck/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-incremental/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile | 2 +- src/ci/docker/x86_64-gnu-nopt/Dockerfile | 2 +- src/ci/docker/x86_64-gnu/Dockerfile | 2 +- 36 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.travis.yml b/.travis.yml index e5b57a389ecb..0ffba70d2ef4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,7 +63,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp diff --git a/appveyor.yml b/appveyor.yml index 68b2a239aff1..83cfea0dd834 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -115,8 +115,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-pc-windows-msvc - - mv 2017-03-24-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-pc-windows-msvc + - mv 2017-04-04-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 933562c79e58..d42b35d488c3 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 8dc02ab522c2..7c1984410078 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile index c468a689a056..d9a5429d2b8e 100644 --- a/src/ci/docker/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 44d6863bf0bb..31f4b8b777be 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 1e448dd43fd5..7162aa0efc0c 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile index cad96b4bde48..8fa1cbe492fa 100644 --- a/src/ci/docker/dist-armhf-linux/Dockerfile +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile index d5be52eba5c2..9fcd827fc996 100644 --- a/src/ci/docker/dist-armv7-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index ed37a9e842e2..bfffd9637fce 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index d88ec7aab346..d2727cbdb350 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-i686-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile index beda2512741e..3b81216c6431 100644 --- a/src/ci/docker/dist-i686-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -25,7 +25,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 8a01934deda3..b322f56f0d04 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -82,7 +82,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index e3df1cc7192d..33cca061103a 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index e4b3bc378c89..157de83abb78 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile index 06f42397a3ea..739d5ff6ac4a 100644 --- a/src/ci/docker/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/dist-mips64el-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile index 17f9913b5aec..9339063bc19e 100644 --- a/src/ci/docker/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/dist-mipsel-linux/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index c1e5e863ae06..92342caed2a9 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 7c143b414d46..182dfd93cc76 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc64-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile index 19b0d625d361..6b9f964d5a38 100644 --- a/src/ci/docker/dist-powerpc64le-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile @@ -63,7 +63,7 @@ COPY shared.sh build-powerpc64le-toolchain.sh /tmp/ RUN ./build-powerpc64le-toolchain.sh RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-s390x-linux/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile index 0d218771cf1c..7c94f713e187 100644 --- a/src/ci/docker/dist-s390x-linux/Dockerfile +++ b/src/ci/docker/dist-s390x-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-s390x-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile index 14444d69d2a8..a2939c8c4859 100644 --- a/src/ci/docker/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -25,7 +25,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index bd36c75f9f06..cbe5f5936a50 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -82,7 +82,7 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=x86_64-unknown-linux-gnu diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 085aa3516599..a41c0cca3b5f 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile index 053300b9c168..a1dd9a3724a8 100644 --- a/src/ci/docker/dist-x86_64-netbsd/Dockerfile +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -62,7 +62,7 @@ RUN ./build-netbsd-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index 77cf54a19a7f..ffdb1d18a94e 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index c84cf56e4e85..34d0567a440f 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index f4bb9083b858..960a0fa7a385 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index 68184c65cf17..9871df90e00d 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 6320a806fc30..197b0ec9b9bb 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 180f53ec33f3..60af302791a7 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 4500fc0f642d..4ec0b5c15257 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index ad1227fa581f..6448f88950f0 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index f12402018057..c00667fe1dd0 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index fa9707d1a735..7284d231b844 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index e5d89034dbe4..1dce84bc5fd7 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ From 56902fbe71b9b0a9b327972412fca085a8770e61 Mon Sep 17 00:00:00 2001 From: GitLab Date: Mon, 13 Mar 2017 14:44:54 -0300 Subject: [PATCH 304/905] Fixes other targets rustlibs installation When the user select more than one target to generate rustlibs for, rustbuild will only install the host one. This patch fixes it, more info in https://github.com/rust-lang/rust/issues/39235#issuecomment-285878858 --- src/bootstrap/install.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 249f241a151b..25082e3a9d09 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -49,12 +49,17 @@ pub fn install(build: &Build, stage: u32, host: &str) { install_sh(&build, "docs", "rust-docs", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } + + for target in build.config.target.iter() { + install_sh(&build, "std", "rust-std", stage, target, &prefix, + &docdir, &libdir, &mandir, &empty_dir); + } + if build.config.rust_save_analysis { install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } - install_sh(&build, "std", "rust-std", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + install_sh(&build, "rustc", "rustc", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); t!(fs::remove_dir_all(&empty_dir)); From 1f70247446914a8b58bd088f32bcca792d30d75f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 5 Apr 2017 07:45:44 +0100 Subject: [PATCH 305/905] Add tracking issue for offset_to --- src/doc/unstable-book/src/offset-to.md | 4 ++-- src/libcore/ptr.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md index 376f3ff5d219..03d990eb4ae9 100644 --- a/src/doc/unstable-book/src/offset-to.md +++ b/src/doc/unstable-book/src/offset-to.md @@ -1,7 +1,7 @@ # `offset_to` -The tracking issue for this feature is: [#0] +The tracking issue for this feature is: [#41079] -[#0]: https://github.com/rust-lang/rust/issues/0 +[#41079]: https://github.com/rust-lang/rust/issues/41079 ------------------------ diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6bcce76af04e..04480fc5d31d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -527,7 +527,7 @@ impl *const T { /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); /// } /// ``` - #[unstable(feature = "offset_to", issue = "0")] + #[unstable(feature = "offset_to", issue = "41079")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); @@ -718,7 +718,7 @@ impl *mut T { /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); /// } /// ``` - #[unstable(feature = "offset_to", issue = "0")] + #[unstable(feature = "offset_to", issue = "41079")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); From 608e8fe16c3859b61f3a43ee233cbf0119ecd35f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 5 Apr 2017 00:41:08 -0700 Subject: [PATCH 306/905] dist-powerpc-linux: use a pure 32-bit CPU profile With `-mcpu=power4`, code might use instructions like `fcfid`, excluding older CPUs like the PowerPC G4, which apparently some users would like to use. The generic `-mcpu=powerpc` should stick to pure 32-bit PowerPC instructions. Fixes rust-lang/cargo#3852. --- src/ci/docker/README.md | 7 +------ src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config | 8 ++++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 52f74ba90de6..6f3a7e091e1e 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -152,18 +152,13 @@ For targets: `powerpc-unknown-linux-gnu` - Path and misc options > Patches origin = Bundled, then local - Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = powerpc -- Target options > Emit assembly for CPU = power4 -- (+) -- Target options > Tune for CPU = power6 -- (+) +- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC - Operating System > Target OS = linux - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc - C compiler > gcc version = 4.9.3 -- C compiler > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) -- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) - C compiler > C++ = ENABLE -- to cross compile LLVM -(+) These CPU options match the configuration of the toolchains in RHEL6. - ## `powerpc64-linux-gnu.config` For targets: `powerpc64-unknown-linux-gnu` diff --git a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config index 26e2de863a0f..984a0a0304e4 100644 --- a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -101,8 +101,8 @@ CT_ARCH_SUPPORTS_WITH_FLOAT=y CT_ARCH_DEFAULT_BE=y CT_ARCH_DEFAULT_32=y CT_ARCH_ABI="" -CT_ARCH_CPU="power4" -CT_ARCH_TUNE="power6" +CT_ARCH_CPU="powerpc" +CT_ARCH_TUNE="" CT_ARCH_BE=y # CT_ARCH_LE is not set CT_ARCH_32=y @@ -391,8 +391,8 @@ CT_CC_GCC_HAS_LIBSANITIZER=y CT_CC_GCC_VERSION="4.9.3" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" -CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" -CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="" CT_CC_GCC_EXTRA_ENV_ARRAY="" CT_CC_GCC_STATIC_LIBSTDCXX=y # CT_CC_GCC_SYSTEM_ZLIB is not set From 36bc448c00a9fb5397d84b94485dd0279eb2af45 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 5 Apr 2017 10:02:37 -0500 Subject: [PATCH 307/905] style: space between struct name and opening brace --- src/librustdoc/html/format.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9e45ccaff32b..7c1139d7135c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -183,7 +183,7 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause{ gens, indent, end_newline } = self; + let &WhereClause { gens, indent, end_newline } = self; if gens.where_predicates.is_empty() { return Ok(()); } @@ -882,7 +882,7 @@ fn fmt_impl(i: &clean::Impl, fmt_type(&i.for_, f, use_absolute, true)?; - fmt::Display::fmt(&WhereClause{ gens: &i.generics, indent: 0, end_newline: true }, f)?; + fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?; Ok(()) } From b5cedb7c4ea74234fbf6da6bdc2ab6efc447baad Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Wed, 5 Apr 2017 11:58:53 -0400 Subject: [PATCH 308/905] tidy clean and small text fix --- src/libcore/intrinsics.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7339fb56e5b4..0806548b5aa0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -155,18 +155,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -175,9 +175,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -186,18 +186,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -206,9 +206,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -217,9 +217,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -228,9 +228,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -239,9 +239,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`][compare_exchange_weak]. + /// [`AtomicBool::compare_exchange_weak`][cew]. /// - /// [compare_exchange_weak]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. From 201b1a9032df63b40c1024cc9defd4a4b66cd73a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 5 Apr 2017 18:59:16 +0300 Subject: [PATCH 309/905] Properly adjust filenames when multiple emissions Fixes #40993 --- src/librustc_driver/driver.rs | 7 +++---- src/test/run-make/multiple-emits/Makefile | 7 +++++++ src/test/run-make/multiple-emits/foo.rs | 11 +++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 src/test/run-make/multiple-emits/Makefile create mode 100644 src/test/run-make/multiple-emits/foo.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 977382b33adf..96eb5dd602f5 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1358,10 +1358,9 @@ pub fn build_output_filenames(input: &Input, .values() .filter(|a| a.is_none()) .count(); - let ofile = if unnamed_output_types > 1 && - sess.opts.output_types.contains_key(&OutputType::Exe) { - sess.warn("ignoring specified output filename for 'link' output because multiple \ - outputs were requested"); + let ofile = if unnamed_output_types > 1 { + sess.warn("due to multiple output types requested, the explicitly specified \ + output file name will be adapted for each output type"); None } else { Some(out_file.clone()) diff --git a/src/test/run-make/multiple-emits/Makefile b/src/test/run-make/multiple-emits/Makefile new file mode 100644 index 000000000000..e126422835ca --- /dev/null +++ b/src/test/run-make/multiple-emits/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out 2>&1 + rm $(TMPDIR)/out.ll $(TMPDIR)/out.s + $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out2.ext 2>&1 + rm $(TMPDIR)/out2.ll $(TMPDIR)/out2.s diff --git a/src/test/run-make/multiple-emits/foo.rs b/src/test/run-make/multiple-emits/foo.rs new file mode 100644 index 000000000000..8ae3d072362e --- /dev/null +++ b/src/test/run-make/multiple-emits/foo.rs @@ -0,0 +1,11 @@ +// 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. + +fn main() {} From 44bcd261a7fa2a4ad873a77b67ac88b0cf09f111 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Wed, 22 Mar 2017 03:27:06 +0900 Subject: [PATCH 310/905] Reduce a table used for `Debug` impl of `str`. This commit shrinks the size of the aforementioned table from 2,102 bytes to 1,197 bytes. This is achieved by an observation that most u16 entries are common in its upper byte. Specifically: - SINGLETONS now uses two tables, one for (upper byte, lower count) and another for a series of lower bytes. For each upper byte given number of lower bytes are read and compared. - NORMAL now uses a variable length format for the count of "true" codepoints and "false" codepoints (one byte with MSB unset, or two big-endian bytes with the first MSB set). The code size and relative performance roughly remains same as this commit tries to optimize for both. The new table and algorithm has been verified for the equivalence to older ones. --- src/etc/char_private.py | 138 ++-- src/libcore/char_private.rs | 1244 +++++++++++++---------------------- 2 files changed, 571 insertions(+), 811 deletions(-) diff --git a/src/etc/char_private.py b/src/etc/char_private.py index 9d15f98e0670..75ab3f1a17be 100644 --- a/src/etc/char_private.py +++ b/src/etc/char_private.py @@ -76,6 +76,66 @@ def get_codepoints(f): 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") @@ -111,6 +171,11 @@ def main(): 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-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -125,38 +190,49 @@ def main(): // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { - break; - } - } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; +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 { + } else if xupper < upper { break; } + lowerstart = lowerend; } - true + + 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 fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else {\ """) for a, b in extra: @@ -169,22 +245,10 @@ pub fn is_printable(x: char) -> bool { }\ """) print() - print("const SINGLETONS0: &'static [u16] = &[") - for s in singletons0: - print(" 0x{:x},".format(s)) - print("];") - print("const SINGLETONS1: &'static [u16] = &[") - for s in singletons1: - print(" 0x{:x},".format(s)) - print("];") - print("const NORMAL0: &'static [u16] = &[") - for a, b in normal0: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") - print("const NORMAL1: &'static [u16] = &[") - for a, b in normal1: - print(" 0x{:x}, 0x{:x},".format(a, b)) - 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_private.rs b/src/libcore/char_private.rs index ddc473592a26..2c0f449b2760 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/char_private.rs @@ -11,38 +11,49 @@ // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { - break; - } - } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; +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 { + } else if xupper < upper { break; } + lowerstart = lowerend; } - true + + 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 fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else { if 0x2a6d7 <= x && x < 0x2a700 { return false; @@ -66,761 +77,446 @@ pub fn is_printable(x: char) -> bool { } } -const SINGLETONS0: &'static [u16] = &[ - 0xad, - 0x378, - 0x379, - 0x38b, - 0x38d, - 0x3a2, - 0x530, - 0x557, - 0x558, - 0x560, - 0x588, - 0x58b, - 0x58c, - 0x590, - 0x61c, - 0x61d, - 0x6dd, - 0x70e, - 0x70f, - 0x74b, - 0x74c, - 0x82e, - 0x82f, - 0x83f, - 0x85c, - 0x85d, - 0x8b5, - 0x8e2, - 0x984, - 0x98d, - 0x98e, - 0x991, - 0x992, - 0x9a9, - 0x9b1, - 0x9ba, - 0x9bb, - 0x9c5, - 0x9c6, - 0x9c9, - 0x9ca, - 0x9de, - 0x9e4, - 0x9e5, - 0xa04, - 0xa11, - 0xa12, - 0xa29, - 0xa31, - 0xa34, - 0xa37, - 0xa3a, - 0xa3b, - 0xa3d, - 0xa49, - 0xa4a, - 0xa5d, - 0xa84, - 0xa8e, - 0xa92, - 0xaa9, - 0xab1, - 0xab4, - 0xaba, - 0xabb, - 0xac6, - 0xaca, - 0xace, - 0xacf, - 0xae4, - 0xae5, - 0xb04, - 0xb0d, - 0xb0e, - 0xb11, - 0xb12, - 0xb29, - 0xb31, - 0xb34, - 0xb3a, - 0xb3b, - 0xb45, - 0xb46, - 0xb49, - 0xb4a, - 0xb5e, - 0xb64, - 0xb65, - 0xb84, - 0xb91, - 0xb9b, - 0xb9d, - 0xbc9, - 0xbce, - 0xbcf, - 0xc04, - 0xc0d, - 0xc11, - 0xc29, - 0xc45, - 0xc49, - 0xc57, - 0xc64, - 0xc65, - 0xc84, - 0xc8d, - 0xc91, - 0xca9, - 0xcb4, - 0xcba, - 0xcbb, - 0xcc5, - 0xcc9, - 0xcdf, - 0xce4, - 0xce5, - 0xcf0, - 0xd04, - 0xd0d, - 0xd11, - 0xd3b, - 0xd3c, - 0xd45, - 0xd49, - 0xd64, - 0xd65, - 0xd80, - 0xd81, - 0xd84, - 0xdb2, - 0xdbc, - 0xdbe, - 0xdbf, - 0xdd5, - 0xdd7, - 0xdf0, - 0xdf1, - 0xe83, - 0xe85, - 0xe86, - 0xe89, - 0xe8b, - 0xe8c, - 0xe98, - 0xea0, - 0xea4, - 0xea6, - 0xea8, - 0xea9, - 0xeac, - 0xeba, - 0xebe, - 0xebf, - 0xec5, - 0xec7, - 0xece, - 0xecf, - 0xeda, - 0xedb, - 0xf48, - 0xf98, - 0xfbd, - 0xfcd, - 0x10c6, - 0x10ce, - 0x10cf, - 0x1249, - 0x124e, - 0x124f, - 0x1257, - 0x1259, - 0x125e, - 0x125f, - 0x1289, - 0x128e, - 0x128f, - 0x12b1, - 0x12b6, - 0x12b7, - 0x12bf, - 0x12c1, - 0x12c6, - 0x12c7, - 0x12d7, - 0x1311, - 0x1316, - 0x1317, - 0x135b, - 0x135c, - 0x13f6, - 0x13f7, - 0x13fe, - 0x13ff, - 0x1680, - 0x170d, - 0x176d, - 0x1771, - 0x17de, - 0x17df, - 0x180e, - 0x180f, - 0x191f, - 0x196e, - 0x196f, - 0x1a1c, - 0x1a1d, - 0x1a5f, - 0x1a7d, - 0x1a7e, - 0x1aae, - 0x1aaf, - 0x1cf7, - 0x1f16, - 0x1f17, - 0x1f1e, - 0x1f1f, - 0x1f46, - 0x1f47, - 0x1f4e, - 0x1f4f, - 0x1f58, - 0x1f5a, - 0x1f5c, - 0x1f5e, - 0x1f7e, - 0x1f7f, - 0x1fb5, - 0x1fc5, - 0x1fd4, - 0x1fd5, - 0x1fdc, - 0x1ff0, - 0x1ff1, - 0x1ff5, - 0x2072, - 0x2073, - 0x208f, - 0x23ff, - 0x2b74, - 0x2b75, - 0x2b96, - 0x2b97, - 0x2bc9, - 0x2c2f, - 0x2c5f, - 0x2d26, - 0x2d2e, - 0x2d2f, - 0x2da7, - 0x2daf, - 0x2db7, - 0x2dbf, - 0x2dc7, - 0x2dcf, - 0x2dd7, - 0x2ddf, - 0x2e9a, - 0x3040, - 0x3097, - 0x3098, - 0x318f, - 0x321f, - 0x32ff, - 0xa7af, - 0xa8fe, - 0xa8ff, - 0xa9ce, - 0xa9ff, - 0xaa4e, - 0xaa4f, - 0xaa5a, - 0xaa5b, - 0xab07, - 0xab08, - 0xab0f, - 0xab10, - 0xab27, - 0xab2f, - 0xabee, - 0xabef, - 0xfa6e, - 0xfa6f, - 0xfb37, - 0xfb3d, - 0xfb3f, - 0xfb42, - 0xfb45, - 0xfd90, - 0xfd91, - 0xfdfe, - 0xfdff, - 0xfe53, - 0xfe67, - 0xfe75, - 0xffc8, - 0xffc9, - 0xffd0, - 0xffd1, - 0xffd8, - 0xffd9, - 0xffe7, - 0xfffe, - 0xffff, +const SINGLETONS0U: &'static [(u8, u8)] = &[ + (0x00, 1), + (0x03, 5), + (0x05, 8), + (0x06, 3), + (0x07, 4), + (0x08, 7), + (0x09, 16), + (0x0a, 27), + (0x0b, 24), + (0x0c, 22), + (0x0d, 20), + (0x0e, 22), + (0x0f, 4), + (0x10, 3), + (0x12, 18), + (0x13, 9), + (0x16, 1), + (0x17, 5), + (0x18, 2), + (0x19, 3), + (0x1a, 7), + (0x1c, 1), + (0x1f, 22), + (0x20, 3), + (0x23, 1), + (0x2b, 5), + (0x2c, 2), + (0x2d, 11), + (0x2e, 1), + (0x30, 3), + (0x31, 1), + (0x32, 2), + (0xa7, 1), + (0xa8, 2), + (0xa9, 2), + (0xaa, 4), + (0xab, 8), + (0xfa, 2), + (0xfb, 5), + (0xfd, 4), + (0xfe, 3), + (0xff, 9), ]; -const SINGLETONS1: &'static [u16] = &[ - 0xc, - 0x27, - 0x3b, - 0x3e, - 0x4e, - 0x4f, - 0x18f, - 0x39e, - 0x49e, - 0x49f, - 0x806, - 0x807, - 0x809, - 0x836, - 0x83d, - 0x83e, - 0x856, - 0x8f3, - 0x9d0, - 0x9d1, - 0xa04, - 0xa14, - 0xa18, - 0xb56, - 0xb57, - 0x10bd, - 0x1135, - 0x11ce, - 0x11cf, - 0x11e0, - 0x1212, - 0x1287, - 0x1289, - 0x128e, - 0x129e, - 0x1304, - 0x130d, - 0x130e, - 0x1311, - 0x1312, - 0x1329, - 0x1331, - 0x1334, - 0x133a, - 0x133b, - 0x1345, - 0x1346, - 0x1349, - 0x134a, - 0x134e, - 0x134f, - 0x1364, - 0x1365, - 0x145a, - 0x145c, - 0x15b6, - 0x15b7, - 0x1c09, - 0x1c37, - 0x1c90, - 0x1c91, - 0x1ca8, - 0x246f, - 0x6a5f, - 0x6aee, - 0x6aef, - 0x6b5a, - 0x6b62, - 0xbc9a, - 0xbc9b, - 0xd127, - 0xd128, - 0xd455, - 0xd49d, - 0xd4a0, - 0xd4a1, - 0xd4a3, - 0xd4a4, - 0xd4a7, - 0xd4a8, - 0xd4ad, - 0xd4ba, - 0xd4bc, - 0xd4c4, - 0xd506, - 0xd50b, - 0xd50c, - 0xd515, - 0xd51d, - 0xd53a, - 0xd53f, - 0xd545, - 0xd551, - 0xd6a6, - 0xd6a7, - 0xd7cc, - 0xd7cd, - 0xdaa0, - 0xe007, - 0xe019, - 0xe01a, - 0xe022, - 0xe025, - 0xe8c5, - 0xe8c6, - 0xee04, - 0xee20, - 0xee23, - 0xee25, - 0xee26, - 0xee28, - 0xee33, - 0xee38, - 0xee3a, - 0xee48, - 0xee4a, - 0xee4c, - 0xee50, - 0xee53, - 0xee55, - 0xee56, - 0xee58, - 0xee5a, - 0xee5c, - 0xee5e, - 0xee60, - 0xee63, - 0xee65, - 0xee66, - 0xee6b, - 0xee73, - 0xee78, - 0xee7d, - 0xee7f, - 0xee8a, - 0xeea4, - 0xeeaa, - 0xf0af, - 0xf0b0, - 0xf0c0, - 0xf0d0, - 0xf12f, - 0xf91f, - 0xf931, - 0xf932, - 0xf93f, +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, 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, 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, + 0x3b, 0x3c, 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, 0xf7, 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, 0xff, 0x74, 0x75, + 0x96, 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, + 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, + 0x9a, 0x40, 0x97, 0x98, 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 NORMAL0: &'static [u16] = &[ - 0x0, 0x20, - 0x7f, 0x22, - 0x380, 0x4, - 0x5c8, 0x8, - 0x5eb, 0x5, - 0x5f5, 0x11, - 0x7b2, 0xe, - 0x7fb, 0x5, - 0x85f, 0x41, - 0x8be, 0x16, - 0x9b3, 0x3, - 0x9cf, 0x8, - 0x9d8, 0x4, - 0x9fc, 0x5, - 0xa0b, 0x4, - 0xa43, 0x4, - 0xa4e, 0x3, - 0xa52, 0x7, - 0xa5f, 0x7, - 0xa76, 0xb, - 0xad1, 0xf, - 0xaf2, 0x7, - 0xafa, 0x7, - 0xb4e, 0x8, - 0xb58, 0x4, - 0xb78, 0xa, - 0xb8b, 0x3, - 0xb96, 0x3, - 0xba0, 0x3, - 0xba5, 0x3, - 0xbab, 0x3, - 0xbba, 0x4, - 0xbc3, 0x3, - 0xbd1, 0x6, - 0xbd8, 0xe, - 0xbfb, 0x5, - 0xc3a, 0x3, - 0xc4e, 0x7, - 0xc5b, 0x5, - 0xc70, 0x8, - 0xcce, 0x7, - 0xcd7, 0x7, - 0xcf3, 0xe, - 0xd50, 0x4, - 0xd97, 0x3, - 0xdc7, 0x3, - 0xdcb, 0x4, - 0xde0, 0x6, - 0xdf5, 0xc, - 0xe3b, 0x4, - 0xe5c, 0x25, - 0xe8e, 0x6, - 0xee0, 0x20, - 0xf6d, 0x4, - 0xfdb, 0x25, - 0x10c8, 0x5, - 0x137d, 0x3, - 0x139a, 0x6, - 0x169d, 0x3, - 0x16f9, 0x7, - 0x1715, 0xb, - 0x1737, 0x9, - 0x1754, 0xc, - 0x1774, 0xc, - 0x17ea, 0x6, - 0x17fa, 0x6, - 0x181a, 0x6, - 0x1878, 0x8, - 0x18ab, 0x5, - 0x18f6, 0xa, - 0x192c, 0x4, - 0x193c, 0x4, - 0x1941, 0x3, - 0x1975, 0xb, - 0x19ac, 0x4, - 0x19ca, 0x6, - 0x19db, 0x3, - 0x1a8a, 0x6, - 0x1a9a, 0x6, - 0x1abf, 0x41, - 0x1b4c, 0x4, - 0x1b7d, 0x3, - 0x1bf4, 0x8, - 0x1c38, 0x3, - 0x1c4a, 0x3, - 0x1c89, 0x37, - 0x1cc8, 0x8, - 0x1cfa, 0x6, - 0x1df6, 0x5, - 0x1fff, 0x11, - 0x2028, 0x8, - 0x205f, 0x11, - 0x209d, 0x3, - 0x20bf, 0x11, - 0x20f1, 0xf, - 0x218c, 0x4, - 0x2427, 0x19, - 0x244b, 0x15, - 0x2bba, 0x3, - 0x2bd2, 0x1a, - 0x2bf0, 0x10, - 0x2cf4, 0x5, - 0x2d28, 0x5, - 0x2d68, 0x7, - 0x2d71, 0xe, - 0x2d97, 0x9, - 0x2e45, 0x3b, - 0x2ef4, 0xc, - 0x2fd6, 0x1a, - 0x2ffc, 0x5, - 0x3100, 0x5, - 0x312e, 0x3, - 0x31bb, 0x5, - 0x31e4, 0xc, - 0x4db6, 0xa, - 0x9fd6, 0x2a, - 0xa48d, 0x3, - 0xa4c7, 0x9, - 0xa62c, 0x14, - 0xa6f8, 0x8, - 0xa7b8, 0x3f, - 0xa82c, 0x4, - 0xa83a, 0x6, - 0xa878, 0x8, - 0xa8c6, 0x8, - 0xa8da, 0x6, - 0xa954, 0xb, - 0xa97d, 0x3, - 0xa9da, 0x4, - 0xaa37, 0x9, - 0xaac3, 0x18, - 0xaaf7, 0xa, - 0xab17, 0x9, - 0xab66, 0xa, - 0xabfa, 0x6, - 0xd7a4, 0xc, - 0xd7c7, 0x4, - 0xd7fc, 0x2104, - 0xfada, 0x26, - 0xfb07, 0xc, - 0xfb18, 0x5, - 0xfbc2, 0x11, - 0xfd40, 0x10, - 0xfdc8, 0x28, - 0xfe1a, 0x6, - 0xfe6c, 0x4, - 0xfefd, 0x4, - 0xffbf, 0x3, - 0xffdd, 0x3, - 0xffef, 0xd, +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), + (0x1c, 5), + (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, 4), ]; -const NORMAL1: &'static [u16] = &[ +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, 0x09, 0x37, 0x90, 0x91, 0xa8, 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, 0x1f, 0x31, + 0x32, 0x3f, +]; +const NORMAL0: &'static [u8] = &[ + 0x00, 0x20, + 0x5f, 0x22, + 0x82, 0xdf, 0x04, + 0x82, 0x44, 0x08, + 0x1b, 0x05, + 0x05, 0x11, + 0x81, 0xac, 0x0e, + 0x3b, 0x05, + 0x5f, 0x41, + 0x1e, 0x16, + 0x80, 0xdf, 0x03, + 0x19, 0x08, + 0x01, 0x04, + 0x20, 0x05, + 0x0a, 0x04, + 0x34, 0x04, + 0x07, 0x03, + 0x01, 0x07, + 0x06, 0x07, + 0x10, 0x0b, + 0x50, 0x0f, + 0x12, 0x07, + 0x01, 0x07, + 0x4d, 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, 0x0e, + 0x4f, 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, + 0x80, 0xf6, 0x05, + 0x82, 0x04, 0x11, + 0x18, 0x08, + 0x2f, 0x11, + 0x2d, 0x03, + 0x1f, 0x11, + 0x21, 0x0f, + 0x80, 0x8c, 0x04, + 0x82, 0x97, 0x19, + 0x0b, 0x15, + 0x87, 0x5a, 0x03, + 0x15, 0x1a, + 0x04, 0x10, + 0x80, 0xf4, 0x05, + 0x2f, 0x05, + 0x3b, 0x07, + 0x02, 0x0e, + 0x18, 0x09, + 0x80, 0xa5, 0x3b, + 0x74, 0x0c, + 0x80, 0xd6, 0x1a, + 0x0c, 0x05, + 0x80, 0xff, 0x05, + 0x29, 0x03, + 0x80, 0x8a, 0x05, + 0x24, 0x0c, + 0x9b, 0xc6, 0x0a, + 0xd2, 0x16, 0x2a, + 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, - 0xfb, 0x5, - 0x103, 0x4, - 0x134, 0x3, - 0x19c, 0x4, - 0x1a1, 0x2f, - 0x1fe, 0x82, - 0x29d, 0x3, - 0x2d1, 0xf, - 0x2fc, 0x4, - 0x324, 0xc, - 0x34b, 0x5, - 0x37b, 0x5, - 0x3c4, 0x4, - 0x3d6, 0x2a, - 0x4aa, 0x6, - 0x4d4, 0x4, - 0x4fc, 0x4, - 0x528, 0x8, - 0x564, 0xb, - 0x570, 0x90, - 0x737, 0x9, - 0x756, 0xa, - 0x768, 0x98, - 0x839, 0x3, - 0x89f, 0x8, - 0x8b0, 0x30, - 0x8f6, 0x5, - 0x91c, 0x3, - 0x93a, 0x5, - 0x940, 0x40, - 0x9b8, 0x4, - 0xa07, 0x5, - 0xa34, 0x4, - 0xa3b, 0x4, - 0xa48, 0x8, - 0xa59, 0x7, - 0xaa0, 0x20, - 0xae7, 0x4, - 0xaf7, 0x9, - 0xb36, 0x3, - 0xb73, 0x5, - 0xb92, 0x7, - 0xb9d, 0xc, - 0xbb0, 0x50, - 0xc49, 0x37, - 0xcb3, 0xd, - 0xcf3, 0x7, - 0xd00, 0x160, - 0xe7f, 0x181, - 0x104e, 0x4, - 0x1070, 0xf, - 0x10c2, 0xe, - 0x10e9, 0x7, - 0x10fa, 0x6, - 0x1144, 0xc, - 0x1177, 0x9, - 0x11f5, 0xb, - 0x123f, 0x41, - 0x12aa, 0x6, - 0x12eb, 0x5, - 0x12fa, 0x6, - 0x1351, 0x6, - 0x1358, 0x5, - 0x136d, 0x3, - 0x1375, 0x8b, - 0x145e, 0x22, - 0x14c8, 0x8, - 0x14da, 0xa6, - 0x15de, 0x22, - 0x1645, 0xb, - 0x165a, 0x6, - 0x166d, 0x13, - 0x16b8, 0x8, - 0x16ca, 0x36, - 0x171a, 0x3, - 0x172c, 0x4, - 0x1740, 0x160, - 0x18f3, 0xc, - 0x1900, 0x1c0, - 0x1af9, 0x107, - 0x1c46, 0xa, - 0x1c6d, 0x3, - 0x1cb7, 0x349, - 0x239a, 0x66, - 0x2475, 0xb, - 0x2544, 0xabc, - 0x342f, 0xfd1, - 0x4647, 0x21b9, - 0x6a39, 0x7, - 0x6a6a, 0x4, - 0x6a70, 0x60, - 0x6af6, 0xa, - 0x6b46, 0xa, - 0x6b78, 0x5, - 0x6b90, 0x370, - 0x6f45, 0xb, - 0x6f7f, 0x10, - 0x6fa0, 0x40, - 0x6fe1, 0x1f, - 0x87ed, 0x13, - 0x8af3, 0x250d, - 0xb002, 0xbfe, - 0xbc6b, 0x5, - 0xbc7d, 0x3, - 0xbc89, 0x7, - 0xbca0, 0x1360, - 0xd0f6, 0xa, - 0xd173, 0x8, - 0xd1e9, 0x17, - 0xd246, 0xba, - 0xd357, 0x9, - 0xd372, 0x8e, - 0xd547, 0x3, - 0xda8c, 0xf, - 0xdab0, 0x550, - 0xe02b, 0x7d5, - 0xe8d7, 0x29, - 0xe94b, 0x5, - 0xe95a, 0x4, - 0xe960, 0x4a0, - 0xee3c, 0x6, - 0xee43, 0x4, - 0xee9c, 0x5, - 0xeebc, 0x34, - 0xeef2, 0x10e, - 0xf02c, 0x4, - 0xf094, 0xc, - 0xf0f6, 0xa, - 0xf10d, 0x3, - 0xf16c, 0x4, - 0xf1ad, 0x39, - 0xf203, 0xd, - 0xf23c, 0x4, - 0xf249, 0x7, - 0xf252, 0xae, - 0xf6d3, 0xd, - 0xf6ed, 0x3, - 0xf6f7, 0x9, - 0xf774, 0xc, - 0xf7d5, 0x2b, - 0xf80c, 0x4, - 0xf848, 0x8, - 0xf85a, 0x6, - 0xf888, 0x8, - 0xf8ae, 0x62, - 0xf928, 0x8, - 0xf94c, 0x4, - 0xf95f, 0x21, - 0xf992, 0x2e, - 0xf9c1, 0x63f, + 0x7b, 0x05, + 0x03, 0x04, + 0x2d, 0x03, + 0x65, 0x04, + 0x01, 0x2f, + 0x2e, 0x80, 0x82, + 0x1d, 0x03, + 0x31, 0x0f, + 0x1c, 0x04, + 0x24, 0x0c, + 0x1b, 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, 0xc0, + 0x39, 0x81, 0x07, + 0x46, 0x0a, + 0x1d, 0x03, + 0x47, 0x83, 0x49, + 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, + 0x01, 0x1f, + 0x97, 0xed, 0x13, + 0x82, 0xf3, 0xa5, 0x0d, + 0x02, 0x8b, 0xfe, + 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, 0x80, 0xae, + 0x83, 0xd3, 0x0d, + 0x0d, 0x03, + 0x07, 0x09, + 0x74, 0x0c, + 0x55, 0x2b, + 0x0c, 0x04, + 0x38, 0x08, + 0x0a, 0x06, + 0x28, 0x08, + 0x1e, 0x62, + 0x18, 0x08, + 0x1c, 0x04, + 0x0f, 0x21, + 0x12, 0x2e, + 0x01, 0x86, 0x3f, ]; From 44e414c4770ff0800c375ddbb8e0f46ee00bcab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 5 Apr 2017 09:50:04 -0700 Subject: [PATCH 311/905] Use proper span for tuple index parsed as float Fix diagnostic suggestion from: ```rust help: try parenthesizing the first index | (1, (2, 3)).((1, (2, 3)).1).1; ``` to the correct: ```rust help: try parenthesizing the first index | ((1, (2, 3)).1).1; ``` --- src/libsyntax/parse/parser.rs | 6 +++--- .../suggestions}/tuple-float-index.rs | 4 +--- src/test/ui/suggestions/tuple-float-index.stderr | 11 +++++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) rename src/test/{parse-fail => ui/suggestions}/tuple-float-index.rs (75%) create mode 100644 src/test/ui/suggestions/tuple-float-index.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855a..0d2c9b92ed75 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2498,10 +2498,10 @@ impl<'a> Parser<'a> { } token::Literal(token::Float(n), _suf) => { self.bump(); - let prev_span = self.prev_span; let fstr = n.as_str(); - let mut err = self.diagnostic().struct_span_err(prev_span, + let mut err = self.diagnostic().struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); + err.span_label(self.prev_span, &"unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::().ok() { Some(f) => f, @@ -2519,7 +2519,7 @@ impl<'a> Parser<'a> { word(&mut s.s, fstr.splitn(2, ".").last().unwrap()) }); err.span_suggestion( - prev_span, + lo.to(self.prev_span), "try parenthesizing the first index", sugg); } diff --git a/src/test/parse-fail/tuple-float-index.rs b/src/test/ui/suggestions/tuple-float-index.rs similarity index 75% rename from src/test/parse-fail/tuple-float-index.rs rename to src/test/ui/suggestions/tuple-float-index.rs index 57ad89ad3740..8bfbd0e74db2 100644 --- a/src/test/parse-fail/tuple-float-index.rs +++ b/src/test/ui/suggestions/tuple-float-index.rs @@ -11,7 +11,5 @@ // compile-flags: -Z parse-only fn main () { - (1, (2, 3)).1.1; //~ ERROR unexpected token - //~^ HELP try parenthesizing the first index - //~| SUGGESTION ((1, (2, 3)).1).1 + (1, (2, 3)).1.1; } diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/suggestions/tuple-float-index.stderr new file mode 100644 index 000000000000..abe04dc1aa21 --- /dev/null +++ b/src/test/ui/suggestions/tuple-float-index.stderr @@ -0,0 +1,11 @@ +error: unexpected token: `1.1` + --> $DIR/tuple-float-index.rs:14:17 + | +14 | (1, (2, 3)).1.1; + | ^^^ unexpected token + | +help: try parenthesizing the first index + | ((1, (2, 3)).1).1; + +error: aborting due to previous error + From 631f761f18d6e4e8d1d4eccaa622ee7defbb8ca4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Apr 2017 10:39:02 -0700 Subject: [PATCH 312/905] travis: Update musl for i686/x86_64 This is a random stab towards #38618, no idea if it'll work. But hey more up-to-date software is better, right? --- src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh | 9 ++++++--- src/ci/docker/dist-x86_64-musl/build-musl.sh | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh index a50a25c79134..ad285a57a84a 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh +++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh @@ -15,11 +15,14 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL -CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686 -make -j10 +CC=gcc \ + CFLAGS="$CFLAGS -m32" \ + ./configure --prefix=/musl-i686 --disable-shared \ + --target=i686 +make AR=ar RANLIB=ranlib -j10 make install cd .. diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh index 86bb259c8549..776da0093974 100644 --- a/src/ci/docker/dist-x86_64-musl/build-musl.sh +++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh @@ -15,7 +15,7 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL ./configure --prefix=/musl-x86_64 --disable-shared From 4c7e27734031d8b57cb51ad498d7f5111032468d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 20 Feb 2017 14:42:47 -0500 Subject: [PATCH 313/905] add an #[used] attribute similar to GCC's __attribute((used))__. This attribute prevents LLVM from optimizing away a non-exported symbol, within a compilation unit (object file), when there are no references to it. This is better explained with an example: ``` #[used] static LIVE: i32 = 0; static REFERENCED: i32 = 0; static DEAD: i32 = 0; fn internal() {} pub fn exported() -> &'static i32 { &REFERENCED } ``` Without optimizations, LLVM pretty much preserves all the static variables and functions within the compilation unit. ``` $ rustc --crate-type=lib --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 t drop::h1be0f8f27a2ba94a 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::DEAD::hc2ea8f9bd06f380b 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 0000000000000000 t symbols::internal::h0ac1aadbc1e3a494 ``` With optimizations, LLVM will drop dead code. Here `internal` is dropped because it's not a exported function/symbol (i.e. not `pub`lic). `DEAD` is dropped for the same reason. `REFERENCED` is preserved, even though it's not exported, because it's referenced by the `exported` function. Finally, `LIVE` survives because of the `#[used]` attribute even though it's not exported or referenced. ``` $ rustc --crate-type=lib -C opt-level=3 --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 ``` Note that the linker knows nothing about `#[used]` and will drop `LIVE` because no other object references to it. ``` $ echo 'fn main() {}' >> symbols.rs $ rustc symbols.rs && nm -C symbols | grep LIVE ``` At this time, `#[used]` only works on `static` variables. --- src/librustc_trans/base.rs | 20 +++++++++++++++++++- src/librustc_trans/consts.rs | 4 ++++ src/librustc_trans/context.rs | 7 +++++++ src/libsyntax/feature_gate.rs | 8 ++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ec45c5593632..63258b745331 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -50,7 +50,7 @@ use builder::Builder; use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; -use common::{C_struct_in_context, C_u64, C_undef}; +use common::{C_struct_in_context, C_u64, C_undef, C_array}; use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; @@ -1187,6 +1187,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Create llvm.used variable + if !ccx.used_statics().borrow().is_empty() { + debug!("llvm.used"); + + let name = CString::new("llvm.used").unwrap(); + let section = CString::new("llvm.metadata").unwrap(); + let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); + + unsafe { + let g = llvm::LLVMAddGlobal(ccx.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 ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 0c3d211912ad..9974155f7c07 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -276,6 +276,10 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); + if attr::contains_name(attrs, "used") { + ccx.used_statics().borrow_mut().push(g); + } + Ok(g) } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 73602dc420b3..2eca0a18e2b3 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -132,6 +132,8 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) statics_to_rauw: RefCell>, + used_statics: RefCell>, + lltypes: RefCell, Type>>, llsizingtypes: RefCell, Type>>, type_hashcodes: RefCell, String>>, @@ -587,6 +589,7 @@ impl<'tcx> LocalCrateContext<'tcx> { impl_method_cache: RefCell::new(FxHashMap()), closure_bare_wrapper_cache: RefCell::new(FxHashMap()), statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), lltypes: RefCell::new(FxHashMap()), llsizingtypes: RefCell::new(FxHashMap()), type_hashcodes: RefCell::new(FxHashMap()), @@ -754,6 +757,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().statics_to_rauw } + pub fn used_statics<'a>(&'a self) -> &'a RefCell> { + &self.local().used_statics + } + pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> { &self.local().lltypes } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 12d25ca4274f..66a813025c43 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -337,11 +337,15 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Used to preserve symbols + (active, used, "1.18.0", None), ); declare_features! ( @@ -748,6 +752,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unwind_attributes", "#[unwind] is experimental", cfg_fn!(unwind_attributes))), + ("used", Whitelisted, Gated( + Stability::Unstable, "used", + "the `#[used]` attribute is an experimental feature", + cfg_fn!(used))), // used in resolve ("prelude_import", Whitelisted, Gated(Stability::Unstable, From 4e1147f3406bcd368c50c89242bbba6a6fec5127 Mon Sep 17 00:00:00 2001 From: raph Date: Wed, 5 Apr 2017 20:41:43 +0200 Subject: [PATCH 314/905] Add example to std::process::abort This is a second (2/3?) step in order to complete this issue: https://github.com/rust-lang/rust/issues/29370 I submitted this PR with the help of @steveklabnik again. Thanks to him! More info here: https://github.com/rust-lang/rust/issues/29370#issuecomment-290653877 --- src/libstd/process.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 7f1a00c707c2..95e625888cce 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1070,6 +1070,28 @@ pub fn exit(code: i32) -> ! { /// // execution never gets here /// } /// ``` +/// +/// The abort function terminates the process, so the destructor will not get +/// run on the example below: +/// +/// ```no_run +/// use std::process; +/// +/// struct HasDrop; +/// +/// impl Drop for HasDrop { +/// fn drop(&mut self) { +/// println!("This will never be printed!"); +/// } +/// } +/// +/// fn main() { +/// let _x = HasDrop; +/// process::abort(); +/// // the destructor implemented for HasDrop will never get run +/// } +/// ``` +/// #[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; From bc1bd8a609823814079996ca3ca0b05774e07a74 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 5 Mar 2017 23:03:42 -0500 Subject: [PATCH 315/905] add tracking issue and feature-gate and run-make tests --- src/test/compile-fail/feature-gate-used.rs | 15 +++++++++++++++ src/test/run-make/used/Makefile | 12 ++++++++++++ src/test/run-make/used/used.rs | 17 +++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-used.rs create mode 100644 src/test/run-make/used/Makefile create mode 100644 src/test/run-make/used/used.rs diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs new file mode 100644 index 000000000000..68679d7dac89 --- /dev/null +++ b/src/test/compile-fail/feature-gate-used.rs @@ -0,0 +1,15 @@ +// 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. + +#[used] +fn foo() {} +//~^^ ERROR the `#[used]` attribute is an experimental feature + +fn main() {} diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile new file mode 100644 index 000000000000..70ac2e3802b8 --- /dev/null +++ b/src/test/run-make/used/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +ifdef IS_WINDOWS +# Do nothing on MSVC. +all: + exit 0 +else +all: + $(RUSTC) -C opt-level=3 --emit=obj used.rs + nm -C used.o | grep FOO + nm -C used.o | grep -v BAR +endif diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs new file mode 100644 index 000000000000..186cd0fdf5e3 --- /dev/null +++ b/src/test/run-make/used/used.rs @@ -0,0 +1,17 @@ +// 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. + +#![crate_type = "lib"] +#![feature(used)] + +#[used] +static FOO: u32 = 0; + +static BAR: u32 = 0; From c759eea7a60941f28e7e7a370ba95eeae06ea013 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 11:18:56 -0500 Subject: [PATCH 316/905] fix location of the emitted object file --- src/test/run-make/used/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile index 70ac2e3802b8..650464e4d845 100644 --- a/src/test/run-make/used/Makefile +++ b/src/test/run-make/used/Makefile @@ -7,6 +7,6 @@ all: else all: $(RUSTC) -C opt-level=3 --emit=obj used.rs - nm -C used.o | grep FOO - nm -C used.o | grep -v BAR + nm -C $(TMPDIR)/used.o | grep FOO + nm -C $(TMPDIR)/used.o | grep -v BAR endif From 2598e4574e9136690add3cef55fbb8ac7356f3d2 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 5 Apr 2017 15:33:24 -0400 Subject: [PATCH 317/905] Add safe wrapper for atomic_singlethreadfence_* --- src/libcore/sync/atomic.rs | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index ae47e6fdfa92..948edda832b4 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1572,6 +1572,47 @@ pub fn fence(order: Ordering) { } +/// A compiler memory barrier. +/// +/// `compiler_barrier` does not emit any machine code, but prevents the compiler from re-ordering +/// memory operations across this point. Which reorderings are disallowed is dictated by the given +/// [`Ordering`]. Note that `compiler_barrier` does *not* introduce inter-thread memory +/// synchronization; for that, a [`fence`] is needed. +/// +/// The re-ordering prevented by the different ordering semantics are: +/// +/// - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed. +/// - with [`Release`], preceding reads and writes cannot be moved past subsequent writes. +/// - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads. +/// - with [`AcqRel`], both of the above rules are enforced. +/// +/// # Panics +/// +/// Panics if `order` is [`Relaxed`]. +/// +/// [`fence`]: fn.fence.html +/// [`Ordering`]: enum.Ordering.html +/// [`Acquire`]: enum.Ordering.html#variant.Acquire +/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst +/// [`Release`]: enum.Ordering.html#variant.Release +/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel +/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed +#[inline] +#[unstable(feature = "std_compiler_fences", issue = "41091")] +pub fn compiler_barrier(order: Ordering) { + unsafe { + match order { + Acquire => intrinsics::atomic_singlethreadfence_acq(), + Release => intrinsics::atomic_singlethreadfence_rel(), + AcqRel => intrinsics::atomic_singlethreadfence_acqrel(), + SeqCst => intrinsics::atomic_singlethreadfence(), + Relaxed => panic!("there is no such thing as a relaxed barrier"), + __Nonexhaustive => panic!("invalid memory ordering"), + } + } +} + + #[cfg(target_has_atomic = "8")] #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicBool { From c1635d7e61533550d6c58d4f92a01d1e6acd28e6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Apr 2017 21:02:52 -0500 Subject: [PATCH 318/905] cast the #[used] static to *i8 to match the type signature of the llvm.used variable --- src/librustc_trans/base.rs | 2 -- src/librustc_trans/consts.rs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 63258b745331..378e1d7fc63f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1189,8 +1189,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Create llvm.used variable if !ccx.used_statics().borrow().is_empty() { - debug!("llvm.used"); - let name = CString::new("llvm.used").unwrap(); let section = CString::new("llvm.metadata").unwrap(); let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 9974155f7c07..ae8c2433fed7 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -277,7 +277,8 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); if attr::contains_name(attrs, "used") { - ccx.used_statics().borrow_mut().push(g); + let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref()); + ccx.used_statics().borrow_mut().push(cast); } Ok(g) From ecddad6920b7640ff0398a52a808703db3d4e62a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Apr 2017 21:06:53 -0500 Subject: [PATCH 319/905] don't test for the absence of BAR in the rmake test it's not related to this feature --- src/test/run-make/used/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile index 650464e4d845..5fe09e95a828 100644 --- a/src/test/run-make/used/Makefile +++ b/src/test/run-make/used/Makefile @@ -8,5 +8,4 @@ else all: $(RUSTC) -C opt-level=3 --emit=obj used.rs nm -C $(TMPDIR)/used.o | grep FOO - nm -C $(TMPDIR)/used.o | grep -v BAR endif From bbe54115873eca9d9a889be3d9eff0c01d2ba8be Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 5 Apr 2017 21:11:22 -0500 Subject: [PATCH 320/905] document the implementation a bit more --- src/librustc_trans/base.rs | 3 ++- src/librustc_trans/consts.rs | 1 + src/librustc_trans/context.rs | 2 ++ src/libsyntax/feature_gate.rs | 4 ++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 378e1d7fc63f..d204703b7759 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1187,7 +1187,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - // Create llvm.used variable + // Create the llvm.used variable + // This variable has type [N x i8*] and is stored in the llvm.metadata section if !ccx.used_statics().borrow().is_empty() { let name = CString::new("llvm.used").unwrap(); let section = CString::new("llvm.metadata").unwrap(); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index ae8c2433fed7..daf1a1ba95f9 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -277,6 +277,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, 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(ccx).to_ref()); ccx.used_statics().borrow_mut().push(cast); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 2eca0a18e2b3..afb94f546abe 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -132,6 +132,8 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) 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 used_statics: RefCell>, lltypes: RefCell, Type>>, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 66a813025c43..5f7190012038 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -344,8 +344,8 @@ declare_features! ( // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), - // Used to preserve symbols - (active, used, "1.18.0", None), + // Used to preserve symbols (see llvm.used) + (active, used, "1.18.0", Some(40289)), ); declare_features! ( From 763beff5d1bcfb74d2930decd731a43a7d3ad080 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 00:04:33 -0500 Subject: [PATCH 321/905] add documentation to the unstable book --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/used.md | 152 +++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/doc/unstable-book/src/used.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 292f5a1ec816..0459c6a25199 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -203,6 +203,7 @@ - [unwind_attributes](unwind-attributes.md) - [update_panic_count](update-panic-count.md) - [use_extern_macros](use-extern-macros.md) +- [used](used.md) - [utf8_error_error_len](utf8-error-error-len.md) - [vec_remove_item](vec-remove-item.md) - [windows_c](windows-c.md) diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md new file mode 100644 index 000000000000..749c9a8ec288 --- /dev/null +++ b/src/doc/unstable-book/src/used.md @@ -0,0 +1,152 @@ +# `used` + +The tracking issue for this feature is: 40289. + +------------------------ + +The `#[used]` attribute can be applied to `static` variables to prevent the Rust +compiler from optimizing them away even if they appear to be unused by the crate +(appear to be "dead code"). + +``` rust +#![feature(used)] + +#[used] +static FOO: i32 = 1; + +static BAR: i32 = 2; + +fn main() {} +``` + +If you compile this program into an object file, you'll see that `FOO` makes it +to the object file but `BAR` doesn't. Neither static variable is used by the +program. + +``` text +$ rustc -C opt-level=3 --emit=obj used.rs + +$ nm -C used.o +0000000000000000 T main + U std::rt::lang_start +0000000000000000 r used::FOO +0000000000000000 t used::main +``` + +Note that the *linker* knows nothing about the `#[used]` attribute and will +remove `#[used]` symbols if they are not referenced by other parts of the +program: + +``` text +$ rustc -C opt-level=3 used.rs + +$ nm -C used | grep FOO +``` + +"This doesn't sound too useful then!" you may think but keep reading. + +To preserve the symbols all the way to the final binary, you'll need the +cooperation of the linker. Here's one example: + +The ELF standard defines two special sections, `.init_array` and +`.pre_init_array`, that may contain function pointers which will be executed +*before* the `main` function is invoked. The linker will preserve symbols placed +in these sections (at least when linking programs that target the `*-*-linux-*` +targets). + +``` rust +#![feature(used)] + +extern "C" fn before_main() { + println!("Hello, world!"); +} + +#[link_section = ".init_array"] +#[used] +static INIT_ARRAY: [extern "C" fn(); 1] = [before_main]; + +fn main() {} +``` + +So, `#[used]` and `#[link_section]` can be combined to obtain "life before +main". + +``` text +$ rustc -C opt-level=3 before-main.rs + +$ ./before-main +Hello, world! +``` + +Another example: ARM Cortex-M microcontrollers need their reset handler, a +pointer to the function that will executed right after the microcontroller is +turned on, to be placed near the start of their FLASH memory to boot properly. + +This condition can be met using `#[used]` and `#[link_section]` plus a linker +script. + +``` rust +#![feature(lang_items)] +#![feature(used)] +#![no_main] +#![no_std] + +extern "C" fn reset_handler() -> ! { + loop {} +} + +#[link_section = ".reset_handler"] +#[used] +static RESET_HANDLER: extern "C" fn() -> ! = reset_handler; + +#[lang = "panic_fmt"] +fn panic_fmt() {} +``` + +``` text +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} + +SECTIONS +{ + .text ORIGIN(FLASH) : + { + /* Vector table */ + LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */ + KEEP(*(.reset_handler)); + + /* Omitted: The rest of the vector table */ + + *(.text.*); + } > FLASH + + /DISCARD/ : + { + /* Unused unwinding stuff */ + *(.ARM.exidx.*) + } +} +``` + +``` text +$ xargo rustc --target thumbv7m-none-eabi --release -- \ + -C link-arg=-Tlink.x -C link-arg=-nostartfiles + +$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app +./target/thumbv7m-none-eabi/release/app: file format elf32-littlearm + + +Disassembly of section .text: + +08000000 : + 8000000: 20005000 .word 0x20005000 + +08000004 : + 8000004: 08000009 .... + +08000008 : + 8000008: e7fe b.n 8000008 +``` From f6d262a326b3a44954773fed6983215b62fe4862 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 5 Apr 2017 21:39:43 -0400 Subject: [PATCH 322/905] Add unstable book entry --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../unstable-book/src/compiler-barriers.md | 98 +++++++++++++++++++ src/libcore/sync/atomic.rs | 2 +- 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/doc/unstable-book/src/compiler-barriers.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 292f5a1ec816..68f31ca75e08 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -37,6 +37,7 @@ - [collections](collections.md) - [collections_range](collections-range.md) - [command_envs](command-envs.md) +- [compiler_barriers](compiler-barriers.md) - [compiler_builtins](compiler-builtins.md) - [compiler_builtins_lib](compiler-builtins-lib.md) - [concat_idents](concat-idents.md) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md new file mode 100644 index 000000000000..84190dab3273 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -0,0 +1,98 @@ +# `compiler_barriers` + +The tracking issue for this feature is: [#41092] + +[#41092]: https://github.com/rust-lang/rust/issues/41092 + +------------------------ + +The `compiler_barriers` feature exposes the `compiler_barrier` function +in `std::sync::atomic`. This function is conceptually similar to C++'s +`atomic_signal_fence`, which can currently only be accessed in nightly +Rust using the `atomic_singlethreadfence_*` instrinsic functions in +`core`, or through the mostly equivalent literal assembly: + +```rust +#![feature(asm)] +unsafe { asm!("" ::: "memory" : "volatile") }; +``` + +A `compiler_barrier` restricts the kinds of memory re-ordering the +compiler is allowed to do. Specifically, depending on the given ordering +semantics, the compiler may be disallowed from moving reads or writes +from before or after the call to the other side of the call to +`compiler_barrier`. + +## Examples + +The need to prevent re-ordering of reads and writes often arises when +working with low-level devices. Consider a piece of code that interacts +with an ethernet card with a set of internal registers that are accessed +through an address port register (`a: &mut usize`) and a data port +register (`d: &usize`). To read internal register 5, the following code +might then be used: + +```rust +fn read_fifth(a: &mut usize, d: &usize) -> usize { + *a = 5; + *d +} +``` + +In this case, the compiler is free to re-order these two statements if +it thinks doing so might result in better performance, register use, or +anything else compilers care about. However, in doing so, it would break +the code, as `x` would be set to the value of some other device +register! + +By inserting a compiler barrier, we can force the compiler to not +re-arrange these two statements, making the code function correctly +again: + +```rust +#![feature(compiler_barriers)] +use std::sync::atomic; + +fn read_fifth(a: &mut usize, d: &usize) -> usize { + *a = 5; + atomic::compiler_barrier(atomic::Ordering::SeqCst); + *d +} +``` + +Compiler barriers are also useful in code that implements low-level +synchronization primitives. Consider a structure with two different +atomic variables, with a dependency chain between them: + +```rust +use std::sync::atomic; + +fn thread1(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { + x.store(1, atomic::Ordering::Release); + let v1 = y.load(atomic::Ordering::Acquire); +} +fn thread2(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { + y.store(1, atomic::Ordering::Release); + let v2 = x.load(atomic::Ordering::Acquire); +} +``` + +This code will guarantee that `thread1` sees any writes to `y` made by +`thread2`, and that `thread2` sees any writes to `x`. Intuitively, one +might also expect that if `thread2` sees `v2 == 0`, `thread1` must see +`v1 == 1` (since `thread2`'s store happened before its `load`, and its +load did not see `thread1`'s store). However, the code as written does +*not* guarantee this, because the compiler is allowed to re-order the +store and load within each thread. To enforce this particular behavior, +a call to `compiler_barrier(Ordering::SeqCst)` would need to be inserted +between the `store` and `load` in both functions. + +Compiler barriers with weaker re-ordering semantics (such as +`Ordering::Acquire`) can also be useful, but are beyond the scope of +this text. Curious readers are encouraged to read the Linux kernel's +discussion of [memory barriers][1], as well as C++ references on +[`std::memory_order`][2] and [`atomic_signal_fence`][3]. + +[1]: https://www.kernel.org/doc/Documentation/memory-barriers.txt +[2]: http://en.cppreference.com/w/cpp/atomic/memory_order +[3]: http://www.cplusplus.com/reference/atomic/atomic_signal_fence/ diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 948edda832b4..8cf1d1d54a5e 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1598,7 +1598,7 @@ pub fn fence(order: Ordering) { /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed #[inline] -#[unstable(feature = "std_compiler_fences", issue = "41091")] +#[unstable(feature = "compiler_barriers", issue = "41091")] pub fn compiler_barrier(order: Ordering) { unsafe { match order { From 5c6f7fafbdcfe412f0ee836562c3682818604132 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 6 Apr 2017 03:45:08 -0400 Subject: [PATCH 323/905] Point to tracking issue, not PR --- src/doc/unstable-book/src/compiler-barriers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 84190dab3273..5a5c539609c7 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -1,8 +1,8 @@ # `compiler_barriers` -The tracking issue for this feature is: [#41092] +The tracking issue for this feature is: [#41091] -[#41092]: https://github.com/rust-lang/rust/issues/41092 +[#41091]: https://github.com/rust-lang/rust/issues/41091 ------------------------ From 16c77d7da1d1707a90d94d9eb77e0752f974a0db Mon Sep 17 00:00:00 2001 From: raph Date: Thu, 6 Apr 2017 10:17:32 +0200 Subject: [PATCH 324/905] Update process.rs --- src/libstd/process.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 95e625888cce..8cfd8fcd8c68 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1071,8 +1071,8 @@ pub fn exit(code: i32) -> ! { /// } /// ``` /// -/// The abort function terminates the process, so the destructor will not get -/// run on the example below: +/// The [`abort`] function terminates the process, so the destructor will not +/// get run on the example below: /// /// ```no_run /// use std::process; @@ -1091,7 +1091,6 @@ pub fn exit(code: i32) -> ! { /// // the destructor implemented for HasDrop will never get run /// } /// ``` -/// #[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; From 95bd41e339ad07a2d7fb347de0a71fcdf155f2d5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Apr 2017 13:20:24 +0300 Subject: [PATCH 325/905] don't try to blame tuple fields for immutability Tuple fields don't have an `&T` in their declaration that can be changed to `&mut T` - skip them.. Fixes #41104. --- src/librustc/middle/mem_categorization.rs | 18 +++++++++++------- src/test/ui/did_you_mean/issue-39544.rs | 6 ++++++ src/test/ui/did_you_mean/issue-39544.stderr | 8 +++++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3b52e85e08e3..7d3c17a04891 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -202,11 +202,14 @@ pub enum ImmutabilityBlame<'tcx> { } impl<'tcx> cmt_<'tcx> { - fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef) + fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> { - let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| { - bug!("interior cmt {:?} is not an ADT", self) - }); + let adt_def = match self.ty.sty { + ty::TyAdt(def, _) => def, + ty::TyTuple(..) => return None, + // closures get `Categorization::Upvar` rather than `Categorization::Interior` + _ => bug!("interior cmt {:?} is not an ADT", self) + }; let variant_def = match self.cat { Categorization::Downcast(_, variant_did) => { adt_def.variant_with_id(variant_did) @@ -220,7 +223,7 @@ impl<'tcx> cmt_<'tcx> { NamedField(name) => variant_def.field_named(name), PositionalField(idx) => &variant_def.fields[idx] }; - (adt_def, field_def) + Some((adt_def, field_def)) } pub fn immutability_blame(&self) -> Option> { @@ -232,8 +235,9 @@ impl<'tcx> cmt_<'tcx> { Categorization::Local(node_id) => Some(ImmutabilityBlame::LocalDeref(node_id)), Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { - let (adt_def, field_def) = base_cmt.resolve_field(field_name); - Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)) + base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| { + ImmutabilityBlame::AdtFieldDeref(adt_def, field_def) + }) } Categorization::Upvar(Upvar { id, .. }) => { if let NoteClosureEnv(..) = self.note { diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index 6331fc5771fc..d7c893556062 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -51,3 +51,9 @@ pub fn with_arg(z: Z, w: &Z) { let _ = &mut z.x; let _ = &mut w.x; } + +pub fn with_tuple() { + let mut y = 0; + let x = (&y,); + *x.0 = 1; +} diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index e1e229a8b057..2e98bc65e9e9 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -90,5 +90,11 @@ error: cannot borrow immutable field `w.x` as mutable 52 | let _ = &mut w.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to 11 previous errors +error: cannot assign to immutable borrowed content `*x.0` + --> $DIR/issue-39544.rs:58:5 + | +58 | *x.0 = 1; + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to 12 previous errors From b4be4758361bf1b03410a523e8672b1c1fa7d385 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 6 Apr 2017 12:57:40 +0100 Subject: [PATCH 326/905] Fix Markdown issues in the docs * Since the switch to pulldown-cmark reference links need a blank line before the URLs. * Reference link references are not case sensitive. * Doc comments need to be indented uniformly otherwise rustdoc gets confused. --- src/libcollections/vec.rs | 2 +- src/libcore/sync/atomic.rs | 5 +++-- src/libstd/fs.rs | 14 ++++++++++++++ src/libstd/io/buffered.rs | 17 +++++++++-------- src/libstd/io/mod.rs | 9 +++++---- src/libstd/net/tcp.rs | 4 ++-- src/libstd/prelude/mod.rs | 12 ++++++------ src/libstd/sys/windows/ext/fs.rs | 2 +- src/libstd/sys/windows/ext/process.rs | 1 + src/libstd/thread/mod.rs | 4 ++-- 10 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c258ac2bdea9..35ecf411db4e 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1346,7 +1346,7 @@ impl Vec { /// # Examples /// /// ``` - ///# #![feature(vec_remove_item)] + /// # #![feature(vec_remove_item)] /// let mut vec = vec![1, 2, 3, 1]; /// /// vec.remove_item(&1); diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 4e5ddfb541e8..2e1058bfc341 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -153,8 +153,9 @@ unsafe impl Sync for AtomicPtr {} /// Rust's memory orderings are [the same as /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). /// -/// For more information see the [nomicon][1]. -/// [1]: ../../../nomicon/atomics.html +/// For more information see the [nomicon]. +/// +/// [nomicon]: ../../../nomicon/atomics.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug)] pub enum Ordering { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 1b00eb95de2b..6b1267d89b6d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1176,6 +1176,7 @@ impl AsInner for DirEntry { /// This function currently corresponds to the `unlink` function on Unix /// and the `DeleteFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1212,6 +1213,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// This function currently corresponds to the `stat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1245,6 +1247,7 @@ pub fn metadata>(path: P) -> io::Result { /// This function currently corresponds to the `lstat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1287,6 +1290,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// on Windows, `from` can be anything, but `to` must *not* be a directory. /// /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1330,6 +1334,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// `O_CLOEXEC` is set for returned file descriptors. /// On Windows, this function currently corresponds to `CopyFileEx`. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1366,6 +1371,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// This function currently corresponds to the `link` function on Unix /// and the `CreateHardLink` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1424,6 +1430,7 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1457,6 +1464,7 @@ pub fn read_link>(path: P) -> io::Result { /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1489,6 +1497,7 @@ pub fn canonicalize>(path: P) -> io::Result { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1522,6 +1531,7 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1562,6 +1572,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// This function currently corresponds to the `rmdir` function on Unix /// and the `RemoveDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1599,6 +1610,7 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions /// on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1633,6 +1645,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// This function currently corresponds to the `opendir` function on Unix /// and the `FindFirstFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1679,6 +1692,7 @@ pub fn read_dir>(path: P) -> io::Result { /// This function currently corresponds to the `chmod` function on Unix /// and the `SetFileAttributes` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index f98a3a87b018..3b82412716e5 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -21,12 +21,12 @@ use memchr; /// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`] on [`TcpStream`] results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying [`Read`] -/// and maintains an in-memory buffer of the results. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. /// /// [`Read`]: ../../std/io/trait.Read.html -/// [`read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples @@ -261,9 +261,10 @@ impl Seek for BufReader { /// Wraps a writer and buffers its output. /// /// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`] -/// results in a system call. A `BufWriter` keeps an in-memory buffer of data -/// and writes it to an underlying writer in large, infrequent batches. +/// implements [`Write`]. For example, every call to +/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. /// @@ -303,7 +304,7 @@ impl Seek for BufReader { /// the `stream` is dropped. /// /// [`Write`]: ../../std/io/trait.Write.html -/// [`write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write /// [`TcpStream`]: ../../std/net/struct.TcpStream.html #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 8ebc5c0a8fe2..cd096c115ba5 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -21,7 +21,8 @@ //! of other types, and you can implement them for your types too. As such, //! you'll see a few different types of I/O throughout the documentation in //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For -//! example, [`Read`] adds a [`read`] method, which we can use on `File`s: +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! `File`s: //! //! ``` //! use std::io; @@ -106,7 +107,7 @@ //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call -//! to [`write`]: +//! to [`write`][`Write::write`]: //! //! ``` //! use std::io; @@ -257,13 +258,13 @@ //! [`Vec`]: ../vec/struct.Vec.html //! [`BufReader`]: struct.BufReader.html //! [`BufWriter`]: struct.BufWriter.html -//! [`write`]: trait.Write.html#tymethod.write +//! [`Write::write`]: trait.Write.html#tymethod.write //! [`io::stdout`]: fn.stdout.html //! [`println!`]: ../macro.println.html //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html //! [`?` operator]: ../../book/syntax-index.html -//! [`read`]: trait.Read.html#tymethod.read +//! [`Read::read`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index cf119720e5a1..bc315d54100e 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -58,7 +58,7 @@ pub struct TcpStream(net_imp::TcpStream); /// /// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens /// for incoming TCP connections. These can be accepted by calling [`accept`] or by -/// iterating over the [`Incoming`] iterator returned by [`incoming`]. +/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. /// /// The socket will be closed when the value is dropped. /// @@ -68,7 +68,7 @@ pub struct TcpStream(net_imp::TcpStream); /// [`bind`]: #method.bind /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [`Incoming`]: ../../std/net/struct.Incoming.html -/// [`incoming`]: #method.incoming +/// [`TcpListener::incoming`]: #method.incoming /// /// # Examples /// diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index c71e0b2a7035..86e661d7948f 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -56,14 +56,14 @@ //! traits indicate fundamental properties of types. //! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various //! operations for both destructors and overloading `()`. -//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a -//! value. +//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly +//! dropping a value. //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a //! borrowed type. -//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone`], -//! the method for producing a copy of a value. +//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines +//! [`clone`][`Clone::clone`], the method for producing a copy of a value. //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The //! comparison traits, which implement the comparison operators and are often //! seen in trait bounds. @@ -117,8 +117,8 @@ //! [`ToOwned`]: ../borrow/trait.ToOwned.html //! [`ToString`]: ../string/trait.ToString.html //! [`Vec`]: ../vec/struct.Vec.html -//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone -//! [`drop`]: ../mem/fn.drop.html +//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone +//! [`mem::drop`]: ../mem/fn.drop.html //! [`std::borrow`]: ../borrow/index.html //! [`std::boxed`]: ../boxed/index.html //! [`std::clone`]: ../clone/index.html diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index c63dd8a47ca4..d6e2fed56be9 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -144,7 +144,7 @@ pub trait OpenOptionsExt { /// `CreateFile`). /// /// If a _new_ file is created because it does not yet exist and - ///`.create(true)` or `.create_new(true)` are specified, the new file is + /// `.create(true)` or `.create_new(true)` are specified, the new file is /// given the attributes declared with `.attributes()`. /// /// If an _existing_ file is opened with `.create(true).truncate(true)`, its diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 1419a4af4273..759f055c4b12 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -104,6 +104,7 @@ pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 18c00e7c5f1b..7ab6b82ada34 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -90,7 +90,7 @@ //! two ways: //! //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -//! function, and calling [`thread`] on the [`JoinHandle`]. +//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. //! * By requesting the current thread, using the [`thread::current`] function. //! //! The [`thread::current`] function is available even for threads not spawned @@ -151,7 +151,7 @@ //! [`Arc`]: ../../std/sync/struct.Arc.html //! [`spawn`]: ../../std/thread/fn.spawn.html //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`thread`]: ../../std/thread/struct.JoinHandle.html#method.thread +//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join //! [`Result`]: ../../std/result/enum.Result.html //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok From f9fb381b2a13260c3fcdae2f6d9546ab2c87e717 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 6 Apr 2017 13:09:20 +0100 Subject: [PATCH 327/905] rustdoc: Use pulldown-cmark for Markdown HTML rendering Instead of rendering all of the HTML in rustdoc this relies on pulldown-cmark's `push_html` to do most of the work. A few iterator adapters are used to make rustdoc specific modifications to the output. This also fixes MarkdownHtml and link titles in plain_summary_line. --- src/librustdoc/html/markdown.rs | 738 +++++++----------- src/librustdoc/html/render.rs | 12 +- src/librustdoc/markdown.rs | 4 +- src/test/rustdoc/check-hard-break.rs | 3 +- src/test/rustdoc/check-rule-image-footnote.rs | 14 +- src/test/rustdoc/test-lists.rs | 14 +- src/tools/error_index_generator/main.rs | 4 +- 7 files changed, 301 insertions(+), 488 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 245a3946a370..1e687d63f587 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -16,10 +16,10 @@ //! of `fmt::Display`. Example usage: //! //! ```rust,ignore -//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle}; +//! use rustdoc::html::markdown::Markdown; //! //! let s = "My *markdown* _text_"; -//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy)); +//! let html = format!("{}", Markdown(s)); //! // ... something using html //! ``` @@ -27,7 +27,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::default::Default; use std::fmt::{self, Write}; use std::str; @@ -37,43 +37,23 @@ use syntax::codemap::Span; use html::render::derive_id; use html::toc::TocBuilder; use html::highlight; -use html::escape::Escape; use test; -use pulldown_cmark::{self, Event, Parser, Tag}; - -#[derive(Copy, Clone)] -pub enum MarkdownOutputStyle { - Compact, - Fancy, -} - -impl MarkdownOutputStyle { - pub fn is_compact(&self) -> bool { - match *self { - MarkdownOutputStyle::Compact => true, - _ => false, - } - } - - pub fn is_fancy(&self) -> bool { - match *self { - MarkdownOutputStyle::Fancy => true, - _ => false, - } - } -} +use pulldown_cmark::{html, Event, Tag, Parser}; +use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES}; /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle); +pub struct Markdown<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. pub struct MarkdownHtml<'a>(pub &'a str); +/// A unit struct like `Markdown`, that renders only the first paragraph. +pub struct MarkdownSummaryLine<'a>(pub &'a str); /// Returns Some(code) if `s` is a line that should be stripped from /// documentation but used in example code. `code` is the portion of @@ -90,12 +70,21 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } -/// Returns a new string with all consecutive whitespace collapsed into -/// single spaces. +/// Convert chars from a title for an id. /// -/// Any leading or trailing whitespace will be trimmed. -fn collapse_whitespace(s: &str) -> String { - s.split_whitespace().collect::>().join(" ") +/// "Hello, world!" -> "hello-world" +fn slugify(c: char) -> Option { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } } // Information about the playground if a URL has been specified, containing an @@ -104,103 +93,50 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = RefCell::new(None) }); -macro_rules! event_loop_break { - ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr, - $($end_event:pat)|*) => {{ - fn inner(id: &mut Option<&mut String>, s: &str) { - if let Some(ref mut id) = *id { - id.push_str(s); +/// Adds syntax highlighting and playground Run buttons to rust code blocks. +struct CodeBlocks<'a, I: Iterator>> { + inner: I, +} + +impl<'a, I: Iterator>> CodeBlocks<'a, I> { + fn new(iter: I) -> Self { + CodeBlocks { + inner: iter, + } + } +} + +impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option { + let event = self.inner.next(); + if let Some(Event::Start(Tag::CodeBlock(lang))) = event { + if !LangString::parse(&lang).rust { + return Some(Event::Start(Tag::CodeBlock(lang))); } + } else { + return event; } - while let Some(event) = $parser.next() { - match event { - $($end_event)|* => break, - Event::Text(ref s) => { - debug!("Text"); - inner($id, s); - if $escape { - $buf.push_str(&format!("{}", Escape(s))); - } else { - $buf.push_str(s); - } - } - Event::SoftBreak => { - debug!("SoftBreak"); - if !$buf.is_empty() { - $buf.push(' '); - } - } - x => { - looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); - } - } - } - }} -} -struct ParserWrapper<'a> { - parser: Parser<'a>, - // The key is the footnote reference. The value is the footnote definition and the id. - footnotes: HashMap, -} - -impl<'a> ParserWrapper<'a> { - pub fn new(s: &'a str) -> ParserWrapper<'a> { - ParserWrapper { - parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | - pulldown_cmark::OPTION_ENABLE_FOOTNOTES), - footnotes: HashMap::new(), - } - } - - pub fn next(&mut self) -> Option> { - self.parser.next() - } - - pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) { - let new_id = self.footnotes.keys().count() + 1; - let key = key.to_owned(); - self.footnotes.entry(key).or_insert((String::new(), new_id as u16)) - } -} - -pub fn render(w: &mut fmt::Formatter, - s: &str, - print_toc: bool, - shorter: MarkdownOutputStyle) -> fmt::Result { - fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) { - debug!("CodeBlock"); let mut origtext = String::new(); - while let Some(event) = parser.next() { + for event in &mut self.inner { match event { - Event::End(Tag::CodeBlock(_)) => break, + Event::End(Tag::CodeBlock(..)) => break, Event::Text(ref s) => { origtext.push_str(s); } _ => {} } } - let origtext = origtext.trim_left(); - debug!("docblock: ==============\n{:?}\n=======", origtext); - let lines = origtext.lines().filter(|l| { stripped_filtered_line(*l).is_none() }); let text = lines.collect::>().join("\n"); - let block_info = if lang.is_empty() { - LangString::all_false() - } else { - LangString::parse(lang) - }; - if !block_info.rust { - buffer.push_str(&format!("

    {}
    ", - lang, text)); - return - } PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output - buffer.push('\n'); + let mut s = String::from("\n"); let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { if url.is_empty() { return None; @@ -210,7 +146,7 @@ pub fn render(w: &mut fmt::Formatter, }).collect::>().join("\n"); let krate = krate.as_ref().map(|s| &**s); let test = test::maketest(&test, krate, false, - &Default::default()); + &Default::default()); let channel = if test.contains("#![feature(") { "&version=nightly" } else { @@ -239,376 +175,186 @@ pub fn render(w: &mut fmt::Formatter, url, test_escaped, channel )) }); - buffer.push_str(&highlight::render_with_highlighting( - &text, - Some("rust-example-rendered"), - None, - playground_button.as_ref().map(String::as_str))); - }); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + Some(Event::Html(s.into())) + }) } +} - fn heading(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, level: i32) { - debug!("Heading"); - let mut ret = String::new(); - let mut id = String::new(); - event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), - Event::End(Tag::Header(_))); - ret = ret.trim_right().to_owned(); +/// Make headings links with anchor ids and build up TOC. +struct HeadingLinks<'a, 'b, I: Iterator>> { + inner: I, + toc: Option<&'b mut TocBuilder>, + buf: VecDeque>, +} - let id = id.chars().filter_map(|c| { - if c.is_alphanumeric() || c == '-' || c == '_' { - if c.is_ascii() { - Some(c.to_ascii_lowercase()) - } else { - Some(c) - } - } else if c.is_whitespace() && c.is_ascii() { - Some('-') - } else { - None - } - }).collect::(); - - let id = derive_id(id); - - let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| { - format!("{} ", builder.push(level as u32, ret.clone(), id.clone())) - }); - - // Render the HTML - buffer.push_str(&format!("\ - {sec}{}", - ret, lvl = level, id = id, sec = sec)); - } - - fn inline_code(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("InlineCode"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); - buffer.push_str(&format!("{}", - Escape(&collapse_whitespace(content.trim_right())))); - } - - fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, url: &str, title: &str, - id: &mut Option<&mut String>) { - debug!("Link"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::Link(_, _))); - if title.is_empty() { - buffer.push_str(&format!("{}", url, content)); - } else { - buffer.push_str(&format!("{}", - url, Escape(title), content)); +impl<'a, 'b, I: Iterator>> HeadingLinks<'a, 'b, I> { + fn new(iter: I, toc: Option<&'b mut TocBuilder>) -> Self { + HeadingLinks { + inner: iter, + toc: toc, + buf: VecDeque::new(), } } +} - fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, url: &str, mut title: String, - id: &mut Option<&mut String>) { - debug!("Image"); - event_loop_break!(parser, toc_builder, shorter, title, true, id, - Event::End(Tag::Image(_, _))); - buffer.push_str(&format!("\"{}\"", url, title)); - } +impl<'a, 'b, I: Iterator>> Iterator for HeadingLinks<'a, 'b, I> { + type Item = Event<'a>; - fn paragraph(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("Paragraph"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::Paragraph)); - buffer.push_str(&format!("

    {}

    ", content.trim_right())); - } - - fn table_cell(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("TableCell"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) | - Event::End(Tag::TableCell)); - buffer.push_str(&format!("{}", content.trim())); - } - - fn table_row(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("TableRow"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) => break, - Event::Start(Tag::TableCell) => { - table_cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } + fn next(&mut self) -> Option { + if let Some(e) = self.buf.pop_front() { + return Some(e); } - buffer.push_str(&format!("{}", content)); - } - fn table_head(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("TableHead"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableCell) => { - table_cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); + let event = self.inner.next(); + if let Some(Event::Start(Tag::Header(level))) = event { + let mut id = String::new(); + for event in &mut self.inner { + match event { + Event::End(Tag::Header(..)) => break, + Event::Text(ref text) => id.extend(text.chars().filter_map(slugify)), + _ => {}, } + self.buf.push_back(event); } + let id = derive_id(id); + + if let Some(ref mut builder) = self.toc { + let mut html_header = String::new(); + html::push_html(&mut html_header, self.buf.iter().cloned()); + let sec = builder.push(level as u32, html_header, id.clone()); + self.buf.push_front(Event::InlineHtml(format!("{} ", sec).into())); + } + + self.buf.push_back(Event::InlineHtml(format!("", level).into())); + + let start_tags = format!("\ + ", + id = id, + level = level); + return Some(Event::InlineHtml(start_tags.into())); } - if !content.is_empty() { - buffer.push_str(&format!("{}", content.replace("td>", "th>"))); + event + } +} + +/// Extracts just the first paragraph. +struct SummaryLine<'a, I: Iterator>> { + inner: I, + started: bool, + depth: u32, +} + +impl<'a, I: Iterator>> SummaryLine<'a, I> { + fn new(iter: I) -> Self { + SummaryLine { + inner: iter, + started: false, + depth: 0, } } +} - fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle) { - debug!("Table"); - let mut content = String::new(); - let mut rows = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableHead) => { - table_head(parser, &mut content, toc_builder, shorter); - } - Event::Start(Tag::TableRow) => { - table_row(parser, &mut rows, toc_builder, shorter); - } - _ => {} - } +impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option { + if self.started && self.depth == 0 { + return None; } - buffer.push_str(&format!("{}{}
    ", - content, - if shorter.is_compact() || rows.is_empty() { - String::new() - } else { - format!("{}", rows) - })); - } - - fn blockquote(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("BlockQuote"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, - Event::End(Tag::BlockQuote)); - buffer.push_str(&format!("
    {}
    ", content.trim_right())); - } - - fn list_item(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle) { - debug!("ListItem"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Item) => break, - Event::Text(ref s) => { - content.push_str(&format!("{}", Escape(s))); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } - if shorter.is_compact() { - break - } + if !self.started { + self.started = true; } - buffer.push_str(&format!("
  • {}
  • ", content)); - } - - fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, is_sorted_list: bool) { - debug!("List"); - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::List(_)) => break, - Event::Start(Tag::Item) => { - list_item(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } - if shorter.is_compact() { - break - } + let event = self.inner.next(); + match event { + Some(Event::Start(..)) => self.depth += 1, + Some(Event::End(..)) => self.depth -= 1, + _ => {} } - buffer.push_str(&format!("<{0}>{1}", - if is_sorted_list { "ol" } else { "ul" }, - content)); + event } +} - fn emphasis(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("Emphasis"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, - Event::End(Tag::Emphasis)); - buffer.push_str(&format!("{}", content)); +/// Moves all footnote definitions to the end and add back links to the +/// references. +struct Footnotes<'a, I: Iterator>> { + inner: I, + footnotes: HashMap>, u16)>, +} + +impl<'a, I: Iterator>> Footnotes<'a, I> { + fn new(iter: I) -> Self { + Footnotes { + inner: iter, + footnotes: HashMap::new(), + } } - - fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - debug!("Strong"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, - Event::End(Tag::Strong)); - buffer.push_str(&format!("{}", content)); + fn get_entry(&mut self, key: &str) -> &mut (Vec>, u16) { + let new_id = self.footnotes.keys().count() + 1; + let key = key.to_owned(); + self.footnotes.entry(key).or_insert((Vec::new(), new_id as u16)) } +} - fn footnote(parser: &mut ParserWrapper, buffer: &mut String, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) { - debug!("FootnoteDefinition"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::FootnoteDefinition(_))); - buffer.push_str(&content); - } +impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { + type Item = Event<'a>; - fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - debug!("Rule"); - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::Rule)); - buffer.push_str("
    "); - } - - fn looper<'a>(parser: &'a mut ParserWrapper, buffer: &mut String, next_event: Option>, - toc_builder: &mut Option, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) -> bool { - if let Some(event) = next_event { - match event { - Event::Start(Tag::CodeBlock(lang)) => { - code_block(parser, buffer, &*lang); + fn next(&mut self) -> Option { + loop { + match self.inner.next() { + Some(Event::FootnoteReference(ref reference)) => { + let entry = self.get_entry(&reference); + let reference = format!("
    {0}\ + ", + (*entry).1); + return Some(Event::Html(reference.into())); } - Event::Start(Tag::Header(level)) => { - heading(parser, buffer, toc_builder, shorter, level); + Some(Event::Start(Tag::FootnoteDefinition(def))) => { + let mut content = Vec::new(); + for event in &mut self.inner { + if let Event::End(Tag::FootnoteDefinition(..)) = event { + break; + } + content.push(event); + } + let entry = self.get_entry(&def); + (*entry).0 = content; } - Event::Start(Tag::Code) => { - inline_code(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Paragraph) => { - paragraph(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref(), id); - } - Event::Start(Tag::Image(ref url, ref t)) => { - image(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); - } - Event::Start(Tag::Table(_)) => { - table(parser, buffer, toc_builder, shorter); - } - Event::Start(Tag::BlockQuote) => { - blockquote(parser, buffer, toc_builder, shorter); - } - Event::Start(Tag::List(x)) => { - list(parser, buffer, toc_builder, shorter, x.is_some()); - } - Event::Start(Tag::Emphasis) => { - emphasis(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Strong) => { - strong(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Rule) => { - rule(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::FootnoteDefinition(ref def)) => { - debug!("FootnoteDefinition"); - let mut content = String::new(); - let def = def.as_ref(); - footnote(parser, &mut content, toc_builder, shorter, id); - let entry = parser.get_entry(def); - let cur_id = (*entry).1; - (*entry).0.push_str(&format!("
  • {} β†©

  • ", - cur_id, - if content.ends_with("

    ") { - &content[..content.len() - 4] - } else { - &content - })); - } - Event::FootnoteReference(ref reference) => { - debug!("FootnoteReference"); - let entry = parser.get_entry(reference.as_ref()); - buffer.push_str(&format!("{0}\ - ", - (*entry).1)); - } - Event::HardBreak => { - debug!("HardBreak"); - if shorter.is_fancy() { - buffer.push_str("
    "); - } else if !buffer.is_empty() { - buffer.push(' '); + Some(e) => return Some(e), + None => { + if !self.footnotes.is_empty() { + let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect(); + v.sort_by(|a, b| a.1.cmp(&b.1)); + let mut ret = String::from("

      "); + for (mut content, id) in v { + write!(ret, "
    1. ", id).unwrap(); + let mut is_paragraph = false; + if let Some(&Event::End(Tag::Paragraph)) = content.last() { + content.pop(); + is_paragraph = true; + } + html::push_html(&mut ret, content.into_iter()); + write!(ret, + " β†©", + id).unwrap(); + if is_paragraph { + ret.push_str("

      "); + } + ret.push_str("
    2. "); + } + ret.push_str("
    "); + return Some(Event::Html(ret.into())); + } else { + return None; } } - Event::Html(h) | Event::InlineHtml(h) => { - debug!("Html/InlineHtml"); - buffer.push_str(&*h); - } - _ => {} } - shorter.is_fancy() - } else { - false } } - - let mut toc_builder = if print_toc { - Some(TocBuilder::new()) - } else { - None - }; - let mut buffer = String::new(); - let mut parser = ParserWrapper::new(s); - loop { - let next_event = parser.next(); - if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { - break - } - } - if !parser.footnotes.is_empty() { - let mut v: Vec<_> = parser.footnotes.values().collect(); - v.sort_by(|a, b| a.1.cmp(&b.1)); - buffer.push_str(&format!("

      {}
    ", - v.iter() - .map(|s| s.0.as_str()) - .collect::>() - .join(""))); - } - let mut ret = toc_builder.map_or(Ok(()), |builder| { - write!(w, "", builder.into_toc()) - }); - - if ret.is_ok() { - ret = w.write_str(&buffer); - } - ret } pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { @@ -755,17 +501,45 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md, shorter) = *self; + let Markdown(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, shorter) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + + fmt.write_str(&s) } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let MarkdownWithToc(md) = *self; - render(fmt, md, true, MarkdownOutputStyle::Fancy) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + let mut toc = TocBuilder::new(); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); + + write!(fmt, "", toc.into_toc())?; + + fmt.write_str(&s) } } @@ -774,7 +548,41 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, MarkdownOutputStyle::Fancy) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + // Treat inline HTML as plain text. + let p = p.map(|event| match event { + Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), + _ => event + }); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + + fmt.write_str(&s) + } +} + +impl<'a> fmt::Display for MarkdownSummaryLine<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let MarkdownSummaryLine(md) = *self; + // This is actually common enough to special-case + if md.is_empty() { return Ok(()) } + + let p = Parser::new(md); + + let mut s = String::new(); + + html::push_html(&mut s, SummaryLine::new(p)); + + fmt.write_str(&s) } } @@ -796,14 +604,10 @@ pub fn plain_summary_line(md: &str) -> String { let next_event = next_event.unwrap(); let (ret, is_in) = match next_event { Event::Start(Tag::Paragraph) => (None, 1), - Event::Start(Tag::Link(_, ref t)) if !self.is_first => { - (Some(t.as_ref().to_owned()), 1) - } Event::Start(Tag::Code) => (Some("`".to_owned()), 1), Event::End(Tag::Code) => (Some("`".to_owned()), -1), Event::Start(Tag::Header(_)) => (None, 1), Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1), _ => (None, 0), }; @@ -834,7 +638,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { - use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle}; + use super::{LangString, Markdown, MarkdownHtml}; use super::plain_summary_line; use html::render::reset_ids; @@ -874,14 +678,14 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy)); + format!("{}", Markdown(markdown)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + let output = format!("{}", Markdown(input)); assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -903,7 +707,7 @@ mod tests { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + let output = format!("{}", Markdown(input)); assert_eq!(output, expect, "original: {}", input); } @@ -934,6 +738,7 @@ mod tests { } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); t("code `let x = i32;` ...", "code `let x = i32;` ..."); t("type `Type<'static>` ...", "type `Type<'static>` ..."); t("# top header", "top header"); @@ -947,7 +752,8 @@ mod tests { assert_eq!(output, expect, "original: {}", input); } - t("`Struct<'a, T>`", "

    Struct<'a, T>

    "); - t("Struct<'a, T>", "

    Struct<'a, T>

    "); + t("`Struct<'a, T>`", "

    Struct<'a, T>

    \n"); + t("Struct<'a, T>", "

    Struct<'a, T>

    \n"); + t("Struct
    ", "

    Struct<br>

    \n"); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f0b624105e34..1e1202f04005 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -1651,7 +1651,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin format!("{}", &plain_summary_line(Some(s))) }; write!(w, "
    {}
    ", - Markdown(&markdown, MarkdownOutputStyle::Fancy))?; + Markdown(&markdown))?; } Ok(()) } @@ -1684,8 +1684,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
    {}
    ", - Markdown(&format!("{}{}", md_render_assoc_item(item), s), - MarkdownOutputStyle::Fancy))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; } Ok(()) } @@ -1873,8 +1872,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value, - MarkdownOutputStyle::Compact).to_string())), + docs = MarkdownSummaryLine(doc_value), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2904,7 +2902,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
    {}
    ", Markdown(dox, MarkdownOutputStyle::Fancy))?; + write!(w, "
    {}
    ", Markdown(dox))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 5cc0f03e1f62..5fadda030a4b 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; use html::markdown; -use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code}; +use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -96,7 +96,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let rendered = if include_toc { format!("{}", MarkdownWithToc(text)) } else { - format!("{}", Markdown(text, MarkdownOutputStyle::Fancy)) + format!("{}", Markdown(text)) }; let err = write!( diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs index 5c5e3f8136c7..f048b64d104a 100644 --- a/src/test/rustdoc/check-hard-break.rs +++ b/src/test/rustdoc/check-hard-break.rs @@ -13,7 +13,8 @@ // ignore-tidy-end-whitespace // @has foo/fn.f.html -// @has - '

    hard break:
    after hard break

    ' +// @has - '

    hard break:
    ' +// @has - 'after hard break

    ' /// hard break: /// after hard break pub fn f() {} diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs index 4d3bea20ba89..46542677857f 100644 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -13,16 +13,21 @@ // ignore-tidy-linelength // @has foo/fn.f.html -// @has - '

    markdown test

    this is a link.

    hard break: after hard break


    a footnote1.

    another footnote2.

    Rust


    1. Thing β†©

    2. Another Thing β†©

    ' +// @has - '

    markdown test

    ' +// @has - '

    this is a link.

    ' +// @has - '
    ' +// @has - '

    a footnote1.

    ' +// @has - '

    another footnote2.

    ' +// @has - '

    Rust

    ' +// @has - '

    1. ' +// @has - '

      Thing β†©

    2. ' +// @has - '

      Another Thing β†©

    ' /// markdown test /// /// this is a [link]. /// /// [link]: https://example.com "this is a title" /// -/// hard break: -/// after hard break -/// /// ----------- /// /// a footnote[^footnote]. @@ -36,5 +41,4 @@ /// /// /// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) -#[deprecated(note = "Struct")] pub fn f() {} diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs index 71a826a2bed7..29f157e0425c 100644 --- a/src/test/rustdoc/test-lists.rs +++ b/src/test/rustdoc/test-lists.rs @@ -10,10 +10,11 @@ #![crate_name = "foo"] -// ignore-tidy-linelength - // @has foo/fn.f.html -// @has - "
    pub fn f()
    1. list
      1. fooooo
      2. x
    2. foo
    " +// @has - //ol/li "list" +// @has - //ol/li/ol/li "fooooo" +// @has - //ol/li/ol/li "x" +// @has - //ol/li "foo" /// 1. list /// 1. fooooo /// 2. x @@ -21,7 +22,10 @@ pub fn f() {} // @has foo/fn.foo2.html -// @has - "
    pub fn foo2()
    • normal list
      • sub list

      • new elem still same elem

        and again same elem!

    • new big elem
    " +// @has - //ul/li "normal list" +// @has - //ul/li/ul/li "sub list" +// @has - //ul/li/ul/li "new elem still same elem and again same elem!" +// @has - //ul/li "new big elem" /// * normal list /// * sub list /// * new elem @@ -29,4 +33,4 @@ pub fn f() {} /// /// and again same elem! /// * new big elem -pub fn foo2() {} \ No newline at end of file +pub fn foo2() {} diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 5db2ad83a0a7..efadde992277 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, PLAYGROUND}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?, + Some(ref desc) => write!(output, "{}", Markdown(desc))?, None => write!(output, "

    No description.

    \n")?, } From 7d25e768ea58658a6523f4a0c1579582b298e43d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 08:48:48 -0500 Subject: [PATCH 328/905] add link to issue number, ignore snippet that requires custom linking --- src/doc/unstable-book/src/used.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md index 749c9a8ec288..cdda24acd708 100644 --- a/src/doc/unstable-book/src/used.md +++ b/src/doc/unstable-book/src/used.md @@ -1,6 +1,7 @@ # `used` -The tracking issue for this feature is: 40289. +The tracking issue for this feature +is: [40289](https://github.com/rust-lang/rust/issues/40289). ------------------------ @@ -85,7 +86,7 @@ turned on, to be placed near the start of their FLASH memory to boot properly. This condition can be met using `#[used]` and `#[link_section]` plus a linker script. -``` rust +``` rust,ignore #![feature(lang_items)] #![feature(used)] #![no_main] From 1f93a78cdc388835bb2575c5432950294ad5809c Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Thu, 6 Apr 2017 21:48:56 +0800 Subject: [PATCH 329/905] .gitmodules: use the official Git URL w/o redirect --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 53d178749240..3533f0df5d1c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,4 +25,4 @@ url = https://github.com/rust-lang-nursery/reference.git [submodule "book"] path = src/doc/book - url = https://github.com/rust-lang/book + url = https://github.com/rust-lang/book.git From c47cdc0d93726429ee18b418b1f85fae67b82d41 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 30 Mar 2017 15:27:27 +0200 Subject: [PATCH 330/905] Introduce HashStable trait and base ICH implementations on it. This initial commit provides implementations for HIR, MIR, and everything that also needs to be supported for those two. --- src/librustc/hir/map/definitions.rs | 4 + src/librustc/ich/hcx.rs | 300 +++++ src/librustc/ich/impls_const_math.rs | 71 ++ src/librustc/ich/impls_hir.rs | 1104 ++++++++++++++++ src/librustc/ich/impls_mir.rs | 407 ++++++ src/librustc/ich/impls_syntax.rs | 301 +++++ src/librustc/ich/impls_ty.rs | 415 ++++++ src/librustc/ich/mod.rs | 28 +- src/librustc/lib.rs | 1 + src/librustc/macros.rs | 79 ++ src/librustc/mir/cache.rs | 11 +- src/librustc/mir/mod.rs | 18 + src/librustc/ty/mod.rs | 29 + src/librustc_data_structures/lib.rs | 2 + src/librustc_data_structures/stable_hasher.rs | 192 ++- src/librustc_incremental/calculate_svh/mod.rs | 199 ++- .../calculate_svh/svh_visitor.rs | 1111 ----------------- src/librustc_incremental/lib.rs | 1 - src/librustc_trans/assert_module_sources.rs | 7 +- src/libsyntax/ptr.rs | 12 + src/libsyntax/util/rc_slice.rs | 13 + 21 files changed, 3081 insertions(+), 1224 deletions(-) create mode 100644 src/librustc/ich/hcx.rs create mode 100644 src/librustc/ich/impls_const_math.rs create mode 100644 src/librustc/ich/impls_hir.rs create mode 100644 src/librustc/ich/impls_mir.rs create mode 100644 src/librustc/ich/impls_syntax.rs create mode 100644 src/librustc/ich/impls_ty.rs delete mode 100644 src/librustc_incremental/calculate_svh/svh_visitor.rs diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 809d5db3071d..dca9ebb3397a 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -394,6 +394,10 @@ impl Definitions { } } + pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { + self.node_to_hir_id[node_id] + } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, parent: Option, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs new file mode 100644 index 000000000000..73d81212cd77 --- /dev/null +++ b/src/librustc/ich/hcx.rs @@ -0,0 +1,300 @@ +// 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 hir; +use hir::def_id::DefId; +use ich::{self, CachingCodemapView, DefPathHashes}; +use session::config::DebugInfoLevel::NoDebugInfo; +use ty; + +use std::hash as std_hash; + +use syntax::ast; +use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; +use syntax::symbol::Symbol; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +/// This is the context state available during incr. comp. hashing. It contains +/// enough information to transform DefIds and HirIds into stable DefPaths (i.e. +/// a reference to the TyCtxt) and it holds a few caches for speeding up various +/// things (e.g. each DefId/DefPath is only hashed once). +pub struct StableHashingContext<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + def_path_hashes: DefPathHashes<'a, 'tcx>, + codemap: CachingCodemapView<'tcx>, + hash_spans: bool, + hash_bodies: bool, + overflow_checks_enabled: bool, + node_id_hashing_mode: NodeIdHashingMode, + // A sorted array of symbol keys for fast lookup. + ignored_attr_names: Vec, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum NodeIdHashingMode { + Ignore, + HashDefPath, + HashTraitsInScope, +} + +impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { + + pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self { + let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo; + let check_overflow_initial = tcx.sess.overflow_checks(); + + let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES + .iter() + .map(|&s| Symbol::intern(s)) + .collect(); + + ignored_attr_names.sort(); + + StableHashingContext { + tcx: tcx, + def_path_hashes: DefPathHashes::new(tcx), + codemap: CachingCodemapView::new(tcx), + hash_spans: hash_spans_initial, + hash_bodies: true, + overflow_checks_enabled: check_overflow_initial, + node_id_hashing_mode: NodeIdHashingMode::HashDefPath, + ignored_attr_names: ignored_attr_names, + } + } + + #[inline] + pub fn while_hashing_hir_bodies(&mut self, + hash_bodies: bool, + f: F) { + let prev_hash_bodies = self.hash_bodies; + self.hash_bodies = hash_bodies; + f(self); + self.hash_bodies = prev_hash_bodies; + } + + #[inline] + pub fn while_hashing_spans(&mut self, + hash_spans: bool, + f: F) { + let prev_hash_spans = self.hash_spans; + self.hash_spans = hash_spans; + f(self); + self.hash_spans = prev_hash_spans; + } + + #[inline] + pub fn with_node_id_hashing_mode(&mut self, + mode: NodeIdHashingMode, + f: F) { + let prev = self.node_id_hashing_mode; + self.node_id_hashing_mode = mode; + f(self); + self.node_id_hashing_mode = prev; + } + + #[inline] + pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + #[inline] + pub fn def_path_hash(&mut self, def_id: DefId) -> u64 { + self.def_path_hashes.hash(def_id) + } + + #[inline] + pub fn hash_spans(&self) -> bool { + self.hash_spans + } + + #[inline] + pub fn hash_bodies(&self) -> bool { + self.hash_bodies + } + + #[inline] + pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> { + &mut self.codemap + } + + #[inline] + pub fn is_ignored_attr(&self, name: Symbol) -> bool { + self.ignored_attr_names.binary_search(&name).is_ok() + } + + pub fn hash_hir_item_like(&mut self, + item_attrs: &[ast::Attribute], + f: F) { + let prev_overflow_checks = self.overflow_checks_enabled; + if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { + self.overflow_checks_enabled = true; + } + let prev_hash_node_ids = self.node_id_hashing_mode; + self.node_id_hashing_mode = NodeIdHashingMode::Ignore; + + f(self); + + self.node_id_hashing_mode = prev_hash_node_ids; + self.overflow_checks_enabled = prev_overflow_checks; + } + + #[inline] + pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool + { + match binop { + hir::BiAdd | + hir::BiSub | + hir::BiMul => self.overflow_checks_enabled, + + hir::BiDiv | + hir::BiRem => true, + + hir::BiAnd | + hir::BiOr | + hir::BiBitXor | + hir::BiBitAnd | + hir::BiBitOr | + hir::BiShl | + hir::BiShr | + hir::BiEq | + hir::BiLt | + hir::BiLe | + hir::BiNe | + hir::BiGe | + hir::BiGt => false + } + } + + #[inline] + pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool + { + match unop { + hir::UnDeref | + hir::UnNot => false, + hir::UnNeg => self.overflow_checks_enabled, + } + } +} + + +impl<'a, 'tcx> HashStable> for ast::NodeId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + match hcx.node_id_hashing_mode { + NodeIdHashingMode::Ignore => { + // Most NodeIds in the HIR can be ignored, but if there is a + // corresponding entry in the `trait_map` we need to hash that. + // Make sure we don't ignore too much by checking that there is + // no entry in a debug_assert!(). + debug_assert!(hcx.tcx.trait_map.get(self).is_none()); + } + NodeIdHashingMode::HashDefPath => { + hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher); + } + NodeIdHashingMode::HashTraitsInScope => { + if let Some(traits) = hcx.tcx.trait_map.get(self) { + // The ordering of the candidates is not fixed. So we hash + // the def-ids and then sort them and hash the collection. + let mut candidates: AccumulateVec<[_; 8]> = + traits.iter() + .map(|&hir::TraitCandidate { def_id, import_id: _ }| { + hcx.def_path_hash(def_id) + }) + .collect(); + if traits.len() > 1 { + candidates.sort(); + } + candidates.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for Span { + + // Hash a span in a stable way. We can't directly hash the span's BytePos + // fields (that would be similar to hashing pointers, since those are just + // offsets into the CodeMap). Instead, we hash the (file name, line, column) + // triple, which stays the same even if the containing FileMap has moved + // within the CodeMap. + // Also note that we are hashing byte offsets for the column, not unicode + // codepoint offsets. For the purpose of the hash that's sufficient. + // Also, hashing filenames is expensive so we avoid doing it twice when the + // span starts and ends in the same file, which is almost always the case. + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use syntax_pos::Pos; + + if !hcx.hash_spans { + return + } + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span_hi = if self.hi > self.lo { + // We might end up in the middle of a multibyte character here, + // but that's OK, since we are not trying to decode anything at + // this position. + self.hi - ::syntax_pos::BytePos(1) + } else { + self.hi + }; + + { + let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo); + let loc1 = loc1.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi); + let loc2 = loc2.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + if loc1.0 == loc2.0 { + std_hash::Hash::hash(&0u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + // Do not hash the file name twice + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } else { + std_hash::Hash::hash(&1u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + std_hash::Hash::hash(loc2.0, hasher); + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } + } + + if self.ctxt == SyntaxContext::empty() { + 0u8.hash_stable(hcx, hasher); + } else { + 1u8.hash_stable(hcx, hasher); + self.source_callsite().hash_stable(hcx, hasher); + } + } +} diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs new file mode 100644 index 000000000000..6d11f2a87a41 --- /dev/null +++ b/src/librustc/ich/impls_const_math.rs @@ -0,0 +1,71 @@ +// 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 module contains `HashStable` implementations for various data types +//! from `rustc_const_math` in no particular order. + +impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat { + F32(val), + F64(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstInt { + I8(val), + I16(val), + I32(val), + I64(val), + I128(val), + Isize(val), + U8(val), + U16(val), + U32(val), + U64(val), + U128(val), + Usize(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize { + Is16(i16), + Is32(i32), + Is64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize { + Us16(i16), + Us32(i32), + Us64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { + NotInRange, + CmpBetweenUnequalTypes, + UnequalTypes(op), + Overflow(op), + ShiftNegative, + DivisionByZero, + RemainderByZero, + UnsignedNegation, + ULitOutOfRange(int_ty), + LitOutOfRange(int_ty) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::Op { + Add, + Sub, + Mul, + Div, + Rem, + Shr, + Shl, + Neg, + BitAnd, + BitOr, + BitXor +}); diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs new file mode 100644 index 000000000000..fb18f50027e2 --- /dev/null +++ b/src/librustc/ich/impls_hir.rs @@ -0,0 +1,1104 @@ +// 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 module contains `HashStable` implementations for various HIR data +//! types in no particular order. + +use hir; +use hir::def_id::DefId; +use ich::{StableHashingContext, NodeIdHashingMode}; +use std::mem; + +use syntax::ast; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; + +impl<'a, 'tcx> HashStable> for DefId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.def_path_hash(*self).hash_stable(hcx, hasher); + } +} + + +impl<'a, 'tcx> HashStable> for hir::HirId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::HirId { + owner, + local_id, + } = *self; + + hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher); + local_id.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); + +// The following implementations of HashStable for ItemId, TraitItemId, and +// ImplItemId deserve special attention. Normally we do not hash NodeIds within +// the HIR, since they just signify a HIR nodes own path. But ItemId et al +// are used when another item in the HIR is *referenced* and we certainly +// want to pick up on a reference changing its target, so we hash the NodeIds +// in "DefPath Mode". + +impl<'a, 'tcx> HashStable> for hir::ItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ItemId { + id + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::ImplItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(struct hir::Lifetime { + id, + span, + name +}); + +impl_stable_hash_for!(struct hir::LifetimeDef { + lifetime, + bounds, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Path { + span, + def, + segments +}); + +impl_stable_hash_for!(struct hir::PathSegment { + name, + parameters +}); + +impl_stable_hash_for!(enum hir::PathParameters { + AngleBracketedParameters(data), + ParenthesizedParameters(data) +}); + +impl_stable_hash_for!(struct hir::AngleBracketedParameterData { + lifetimes, + types, + infer_types, + bindings +}); + +impl_stable_hash_for!(struct hir::ParenthesizedParameterData { + span, + inputs, + output +}); + +impl_stable_hash_for!(enum hir::TyParamBound { + TraitTyParamBound(poly_trait_ref, trait_bound_modifier), + RegionTyParamBound(lifetime) +}); + +impl_stable_hash_for!(enum hir::TraitBoundModifier { + None, + Maybe +}); + +impl_stable_hash_for!(struct hir::TyParam { + name, + id, + bounds, + default, + span, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Generics { + lifetimes, + ty_params, + where_clause, + span +}); + +impl_stable_hash_for!(struct hir::WhereClause { + id, + predicates +}); + +impl_stable_hash_for!(enum hir::WherePredicate { + BoundPredicate(pred), + RegionPredicate(pred), + EqPredicate(pred) +}); + +impl_stable_hash_for!(struct hir::WhereBoundPredicate { + span, + bound_lifetimes, + bounded_ty, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereRegionPredicate { + span, + lifetime, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereEqPredicate { + id, + span, + lhs_ty, + rhs_ty +}); + +impl_stable_hash_for!(struct hir::MutTy { + ty, + mutbl +}); + +impl_stable_hash_for!(struct hir::MethodSig { + unsafety, + constness, + abi, + decl, + generics +}); + +impl_stable_hash_for!(struct hir::TypeBinding { + id, + name, + ty, + span +}); + +impl<'a, 'tcx> HashStable> for hir::Ty { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::TySlice(..) | + hir::TyArray(..) | + hir::TyPtr(..) | + hir::TyRptr(..) | + hir::TyBareFn(..) | + hir::TyNever | + hir::TyTup(..) | + hir::TyTraitObject(..) | + hir::TyImplTrait(..) | + hir::TyTypeof(..) | + hir::TyInfer => { + NodeIdHashingMode::Ignore + } + hir::TyPath(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Ty { + id, + ref node, + ref span, + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(enum hir::PrimTy { + TyInt(int_ty), + TyUint(uint_ty), + TyFloat(float_ty), + TyStr, + TyBool, + TyChar +}); + +impl_stable_hash_for!(struct hir::BareFnTy { + unsafety, + abi, + lifetimes, + decl +}); + +impl_stable_hash_for!(enum hir::Ty_ { + TySlice(t), + TyArray(t, body_id), + TyPtr(t), + TyRptr(lifetime, t), + TyBareFn(t), + TyNever, + TyTup(ts), + TyPath(qpath), + TyTraitObject(trait_refs, lifetime), + TyImplTrait(bounds), + TyTypeof(body_id), + TyInfer +}); + +impl_stable_hash_for!(struct hir::FnDecl { + inputs, + output, + variadic, + has_implicit_self +}); + +impl_stable_hash_for!(enum hir::FunctionRetTy { + DefaultReturn(span), + Return(t) +}); + +impl<'a, 'tcx> HashStable> for hir::TraitRef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitRef { + ref path, + ref_id, + } = *self; + + path.hash_stable(hcx, hasher); + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + ref_id.hash_stable(hcx, hasher); + }); + } +} + + +impl_stable_hash_for!(struct hir::PolyTraitRef { + bound_lifetimes, + trait_ref, + span +}); + +impl_stable_hash_for!(enum hir::QPath { + Resolved(t, path), + TypeRelative(t, path_segment) +}); + +impl_stable_hash_for!(struct hir::MacroDef { + name, + attrs, + id, + span, + body +}); + + +impl<'a, 'tcx> HashStable> for hir::Block { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Block { + ref stmts, + ref expr, + id, + rules, + span, + targeted_by_break, + } = *self; + + let non_item_stmts = || stmts.iter().filter(|stmt| { + match stmt.node { + hir::StmtDecl(ref decl, _) => { + match decl.node { + // If this is a declaration of a nested item, we don't + // want to leave any trace of it in the hash value, not + // even that it exists. Otherwise changing the position + // of nested items would invalidate the containing item + // even though that does not constitute a semantic + // change. + hir::DeclItem(_) => false, + hir::DeclLocal(_) => true + } + } + hir::StmtExpr(..) | + hir::StmtSemi(..) => true + } + }); + + let count = non_item_stmts().count(); + + count.hash_stable(hcx, hasher); + + for stmt in non_item_stmts() { + stmt.hash_stable(hcx, hasher); + } + + expr.hash_stable(hcx, hasher); + id.hash_stable(hcx, hasher); + rules.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + targeted_by_break.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::Pat { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::PatKind::Wild | + hir::PatKind::Binding(..) | + hir::PatKind::Tuple(..) | + hir::PatKind::Box(..) | + hir::PatKind::Ref(..) | + hir::PatKind::Lit(..) | + hir::PatKind::Range(..) | + hir::PatKind::Slice(..) => { + NodeIdHashingMode::Ignore + } + hir::PatKind::Path(..) | + hir::PatKind::Struct(..) | + hir::PatKind::TupleStruct(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Pat { + id, + ref node, + ref span + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for_spanned!(hir::FieldPat); +impl_stable_hash_for!(struct hir::FieldPat { + name, + pat, + is_shorthand +}); + +impl_stable_hash_for!(enum hir::BindingMode { + BindByRef(mutability), + BindByValue(mutability) +}); + +impl_stable_hash_for!(enum hir::RangeEnd { + Included, + Excluded +}); + +impl_stable_hash_for!(enum hir::PatKind { + Wild, + Binding(binding_mode, var, name, sub), + Struct(path, field_pats, dotdot), + TupleStruct(path, field_pats, dotdot), + Path(path), + Tuple(field_pats, dotdot), + Box(sub), + Ref(sub, mutability), + Lit(expr), + Range(start, end, end_kind), + Slice(one, two, three) +}); + +impl_stable_hash_for!(enum hir::BinOp_ { + BiAdd, + BiSub, + BiMul, + BiDiv, + BiRem, + BiAnd, + BiOr, + BiBitXor, + BiBitAnd, + BiBitOr, + BiShl, + BiShr, + BiEq, + BiLt, + BiLe, + BiNe, + BiGe, + BiGt +}); + +impl_stable_hash_for_spanned!(hir::BinOp_); + +impl_stable_hash_for!(enum hir::UnOp { + UnDeref, + UnNot, + UnNeg +}); + +impl_stable_hash_for_spanned!(hir::Stmt_); + +impl_stable_hash_for!(struct hir::Local { + pat, + ty, + init, + id, + span, + attrs +}); + +impl_stable_hash_for_spanned!(hir::Decl_); +impl_stable_hash_for!(enum hir::Decl_ { + DeclLocal(local), + DeclItem(item_id) +}); + +impl_stable_hash_for!(struct hir::Arm { + attrs, + pats, + guard, + body +}); + +impl_stable_hash_for!(struct hir::Field { + name, + expr, + span, + is_shorthand +}); + +impl_stable_hash_for_spanned!(ast::Name); + + +impl_stable_hash_for!(enum hir::BlockCheckMode { + DefaultBlock, + UnsafeBlock(src), + PushUnsafeBlock(src), + PopUnsafeBlock(src) +}); + +impl_stable_hash_for!(enum hir::UnsafeSource { + CompilerGenerated, + UserProvided +}); + +impl<'a, 'tcx> HashStable> for hir::Expr { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Expr { + id, + ref span, + ref node, + ref attrs + } = *self; + + let (spans_always_on, node_id_hashing_mode) = match *node { + hir::ExprBox(..) | + hir::ExprArray(..) | + hir::ExprCall(..) | + hir::ExprLit(..) | + hir::ExprCast(..) | + hir::ExprType(..) | + hir::ExprIf(..) | + hir::ExprWhile(..) | + hir::ExprLoop(..) | + hir::ExprMatch(..) | + hir::ExprClosure(..) | + hir::ExprBlock(..) | + hir::ExprAssign(..) | + hir::ExprTupField(..) | + hir::ExprAddrOf(..) | + hir::ExprBreak(..) | + hir::ExprAgain(..) | + hir::ExprRet(..) | + hir::ExprInlineAsm(..) | + hir::ExprRepeat(..) | + hir::ExprTup(..) => { + // For these we only hash the span when debuginfo is on. + (false, NodeIdHashingMode::Ignore) + } + // For the following, spans might be significant because of + // panic messages indicating the source location. + hir::ExprBinary(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprUnary(op, _) => { + (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore) + } + hir::ExprAssignOp(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprIndex(..) => { + (true, NodeIdHashingMode::Ignore) + } + // For these we don't care about the span, but want to hash the + // trait in scope + hir::ExprMethodCall(..) | + hir::ExprPath(..) | + hir::ExprStruct(..) | + hir::ExprField(..) => { + (false, NodeIdHashingMode::HashTraitsInScope) + } + }; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + + if spans_always_on { + hcx.while_hashing_spans(true, |hcx| { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + }); + } else { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + } + }) + } +} + +impl_stable_hash_for!(enum hir::Expr_ { + ExprBox(sub), + ExprArray(subs), + ExprCall(callee, args), + ExprMethodCall(name, ts, args), + ExprTup(fields), + ExprBinary(op, lhs, rhs), + ExprUnary(op, operand), + ExprLit(value), + ExprCast(expr, t), + ExprType(expr, t), + ExprIf(cond, then, els), + ExprWhile(cond, body, label), + ExprLoop(body, label, loop_src), + ExprMatch(matchee, arms, match_src), + ExprClosure(capture_clause, decl, body_id, span), + ExprBlock(blk), + ExprAssign(lhs, rhs), + ExprAssignOp(op, lhs, rhs), + ExprField(owner, field_name), + ExprTupField(owner, idx), + ExprIndex(lhs, rhs), + ExprPath(path), + ExprAddrOf(mutability, sub), + ExprBreak(destination, sub), + ExprAgain(destination), + ExprRet(val), + ExprInlineAsm(asm, inputs, outputs), + ExprStruct(path, fields, base), + ExprRepeat(val, times) +}); + +impl_stable_hash_for!(enum hir::LoopSource { + Loop, + WhileLet, + ForLoop +}); + +impl<'a, 'tcx> HashStable> for hir::MatchSource { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use hir::MatchSource; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + MatchSource::Normal | + MatchSource::WhileLetDesugar | + MatchSource::ForLoopDesugar | + MatchSource::TryDesugar => { + // No fields to hash. + } + MatchSource::IfLetDesugar { contains_else_clause } => { + contains_else_clause.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::CaptureClause { + CaptureByValue, + CaptureByRef +}); + +impl_stable_hash_for_spanned!(usize); + +impl_stable_hash_for!(struct hir::Destination { + ident, + target_id +}); + +impl_stable_hash_for_spanned!(ast::Ident); + +impl_stable_hash_for!(enum hir::LoopIdResult { + Ok(node_id), + Err(loop_id_error) +}); + +impl_stable_hash_for!(enum hir::LoopIdError { + OutsideLoopScope, + UnlabeledCfInWhileCondition, + UnresolvedLabel +}); + +impl_stable_hash_for!(enum hir::ScopeTarget { + Block(node_id), + Loop(loop_id_result) +}); + +impl<'a, 'tcx> HashStable> for ast::Ident { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ast::Ident { + ref name, + ctxt: _ // Ignore this + } = *self; + + name.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItem { + id, + name, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::TraitMethod { + Required(name), + Provided(body) +}); + +impl_stable_hash_for!(enum hir::TraitItemKind { + Const(t, body), + Method(sig, method), + Type(bounds, rhs) +}); + +impl<'a, 'tcx> HashStable> for hir::ImplItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItem { + id, + name, + ref vis, + defaultness, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + defaultness.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::ImplItemKind { + Const(t, body), + Method(sig, body), + Type(t) +}); + +impl<'a, 'tcx> HashStable> for hir::Visibility { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Visibility::Public | + hir::Visibility::Crate | + hir::Visibility::Inherited => { + // No fields to hash. + } + hir::Visibility::Restricted { ref path, id } => { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + id.hash_stable(hcx, hasher); + }); + path.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for hir::Defaultness { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Defaultness::Final => { + // No fields to hash. + } + hir::Defaultness::Default { has_value } => { + has_value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::ImplPolarity { + Positive, + Negative +}); + +impl<'a, 'tcx> HashStable> for hir::Mod { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Mod { + inner, + // We are not hashing the IDs of the items contained in the module. + // This is harmless and matches the current behavior but it's not + // actually correct. See issue #40876. + item_ids: _, + } = *self; + + inner.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::ForeignMod { + abi, + items +}); + +impl_stable_hash_for!(struct hir::EnumDef { + variants +}); + +impl_stable_hash_for!(struct hir::Variant_ { + name, + attrs, + data, + disr_expr +}); + +impl_stable_hash_for_spanned!(hir::Variant_); + +impl_stable_hash_for!(enum hir::UseKind { + Single, + Glob, + ListStem +}); + +impl_stable_hash_for!(struct hir::StructField { + span, + name, + vis, + id, + ty, + attrs +}); + +impl_stable_hash_for!(enum hir::VariantData { + Struct(fields, id), + Tuple(fields, id), + Unit(id) +}); + +impl<'a, 'tcx> HashStable> for hir::Item { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::ItemExternCrate(..) | + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemMod(..) | + hir::ItemForeignMod(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemTrait(..) | + hir::ItemDefaultImpl(..) | + hir::ItemImpl(..) => { + NodeIdHashingMode::Ignore + } + hir::ItemUse(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Item { + name, + ref attrs, + id, + ref node, + ref vis, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::Item_ { + ItemExternCrate(name), + ItemUse(path, use_kind), + ItemStatic(ty, mutability, body_id), + ItemConst(ty, body_id), + ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), + ItemMod(module), + ItemForeignMod(foreign_mod), + ItemTy(ty, generics), + ItemEnum(enum_def, generics), + ItemStruct(variant_data, generics), + ItemUnion(variant_data, generics), + ItemTrait(unsafety, generics, bounds, item_refs), + ItemDefaultImpl(unsafety, trait_ref), + ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) +}); + +impl_stable_hash_for!(struct hir::TraitItemRef { + id, + name, + kind, + span, + defaultness +}); + +impl_stable_hash_for!(struct hir::ImplItemRef { + id, + name, + kind, + span, + vis, + defaultness +}); + +impl<'a, 'tcx> HashStable> for hir::AssociatedItemKind { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::AssociatedItemKind::Const | + hir::AssociatedItemKind::Type => { + // No fields to hash. + } + hir::AssociatedItemKind::Method { has_self } => { + has_self.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct hir::ForeignItem { + name, + attrs, + node, + id, + span, + vis +}); + +impl_stable_hash_for!(enum hir::ForeignItem_ { + ForeignItemFn(fn_decl, arg_names, generics), + ForeignItemStatic(ty, is_mutbl) +}); + +impl_stable_hash_for!(enum hir::Stmt_ { + StmtDecl(decl, id), + StmtExpr(expr, id), + StmtSemi(expr, id) +}); + +impl_stable_hash_for!(struct hir::Arg { + pat, + id +}); + +impl_stable_hash_for!(struct hir::Body { + arguments, + value +}); + +impl<'a, 'tcx> HashStable> for hir::BodyId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + if hcx.hash_bodies() { + hcx.tcx().hir.body(*self).hash_stable(hcx, hasher); + } + } +} + +impl_stable_hash_for!(struct hir::InlineAsmOutput { + constraint, + is_rw, + is_indirect +}); + +impl<'a, 'tcx> HashStable> for hir::InlineAsm { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::InlineAsm { + asm, + asm_str_style, + ref outputs, + ref inputs, + ref clobbers, + volatile, + alignstack, + dialect, + ctxt: _, // This is used for error reporting + } = *self; + + asm.hash_stable(hcx, hasher); + asm_str_style.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + clobbers.hash_stable(hcx, hasher); + volatile.hash_stable(hcx, hasher); + alignstack.hash_stable(hcx, hasher); + dialect.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum hir::def::CtorKind { + Fn, + Const, + Fictive +}); + +impl_stable_hash_for!(enum hir::def::Def { + Mod(def_id), + Struct(def_id), + Union(def_id), + Enum(def_id), + Variant(def_id), + Trait(def_id), + TyAlias(def_id), + AssociatedTy(def_id), + PrimTy(prim_ty), + TyParam(def_id), + SelfTy(trait_def_id, impl_def_id), + Fn(def_id), + Const(def_id), + Static(def_id, is_mutbl), + StructCtor(def_id, ctor_kind), + VariantCtor(def_id, ctor_kind), + Method(def_id), + AssociatedConst(def_id), + Local(def_id), + Upvar(def_id, index, expr_id), + Label(node_id), + Macro(def_id, macro_kind), + Err +}); + +impl_stable_hash_for!(enum hir::Mutability { + MutMutable, + MutImmutable +}); + + +impl_stable_hash_for!(enum hir::Unsafety { + Unsafe, + Normal +}); + + +impl_stable_hash_for!(enum hir::Constness { + Const, + NotConst +}); + +impl<'a, 'tcx> HashStable> for hir::def_id::DefIndex { + + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + DefId::local(*self).hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::def::Export { + name, + def, + span +}); diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs new file mode 100644 index 000000000000..401f7e1921ab --- /dev/null +++ b/src/librustc/ich/impls_mir.rs @@ -0,0 +1,407 @@ +// 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 module contains `HashStable` implementations for various MIR data +//! types in no particular order. + +use ich::StableHashingContext; +use mir; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::mem; + + +impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); +impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); +impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); +impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info }); +impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); +impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); +impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::Local { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::BasicBlock { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Field { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::VisibilityScope { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Promoted { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::TerminatorKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::TerminatorKind::Goto { ref target } => { + target.hash_stable(hcx, hasher); + } + mir::TerminatorKind::SwitchInt { ref discr, + switch_ty, + ref values, + ref targets } => { + discr.hash_stable(hcx, hasher); + switch_ty.hash_stable(hcx, hasher); + values.hash_stable(hcx, hasher); + targets.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::Unreachable => {} + mir::TerminatorKind::Drop { ref location, target, unwind } => { + location.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::DropAndReplace { ref location, + ref value, + target, + unwind, } => { + location.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Call { ref func, + ref args, + ref destination, + cleanup } => { + func.hash_stable(hcx, hasher); + args.hash_stable(hcx, hasher); + destination.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Assert { ref cond, + expected, + ref msg, + target, + cleanup } => { + cond.hash_stable(hcx, hasher); + expected.hash_stable(hcx, hasher); + msg.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::AssertMessage<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::AssertMessage::BoundsCheck { ref len, ref index } => { + len.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + } + mir::AssertMessage::Math(ref const_math_err) => { + const_math_err.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::StatementKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::StatementKind::Assign(ref lvalue, ref rvalue) => { + lvalue.hash_stable(hcx, hasher); + rvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => { + lvalue.hash_stable(hcx, hasher); + variant_index.hash_stable(hcx, hasher); + } + mir::StatementKind::StorageLive(ref lvalue) | + mir::StatementKind::StorageDead(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::Nop => {} + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + asm.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Lvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Lvalue::Local(ref local) => { + local.hash_stable(hcx, hasher); + } + mir::Lvalue::Static(ref statik) => { + statik.hash_stable(hcx, hasher); + } + mir::Lvalue::Projection(ref lvalue_projection) => { + lvalue_projection.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx, B, V> HashStable> for mir::Projection<'tcx, B, V> + where B: HashStable>, + V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let mir::Projection { + ref base, + ref elem, + } = *self; + + base.hash_stable(hcx, hasher); + elem.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx, V> HashStable> for mir::ProjectionElem<'tcx, V> + where V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::ProjectionElem::Deref => {} + mir::ProjectionElem::Field(field, ty) => { + field.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Index(ref value) => { + value.hash_stable(hcx, hasher); + } + mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + offset.hash_stable(hcx, hasher); + min_length.hash_stable(hcx, hasher); + from_end.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Subslice { from, to } => { + from.hash_stable(hcx, hasher); + to.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Downcast(adt_def, variant) => { + adt_def.hash_stable(hcx, hasher); + variant.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope }); + +impl<'a, 'tcx> HashStable> for mir::Operand<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Operand::Consume(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Operand::Constant(ref constant) => { + constant.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Rvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Rvalue::Use(ref operand) => { + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Repeat(ref operand, ref val) => { + operand.hash_stable(hcx, hasher); + val.hash_stable(hcx, hasher); + } + mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => { + region.hash_stable(hcx, hasher); + borrow_kind.hash_stable(hcx, hasher); + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Len(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Cast(cast_kind, ref operand, ty) => { + cast_kind.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) | + mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => { + op.hash_stable(hcx, hasher); + operand1.hash_stable(hcx, hasher); + operand2.hash_stable(hcx, hasher); + } + mir::Rvalue::UnaryOp(op, ref operand) => { + op.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Discriminant(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Box(ty) => { + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::Aggregate(ref kind, ref operands) => { + kind.hash_stable(hcx, hasher); + operands.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::CastKind { + Misc, + ReifyFnPointer, + ClosureFnPointer, + UnsafeFnPointer, + Unsize +}); + +impl<'a, 'tcx> HashStable> for mir::AggregateKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::AggregateKind::Tuple => {} + mir::AggregateKind::Array(t) => { + t.hash_stable(hcx, hasher); + } + mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => { + adt_def.hash_stable(hcx, hasher); + idx.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + active_field.hash_stable(hcx, hasher); + } + mir::AggregateKind::Closure(def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::BinOp { + Add, + Sub, + Mul, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + Shl, + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt +}); + +impl_stable_hash_for!(enum mir::UnOp { + Not, + Neg +}); + + +impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); + +impl<'a, 'tcx> HashStable> for mir::Literal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Literal::Item { def_id, substs } => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + mir::Literal::Value { ref value } => { + value.hash_stable(hcx, hasher); + } + mir::Literal::Promoted { index } => { + index.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Location { block, statement_index }); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs new file mode 100644 index 000000000000..26734500001f --- /dev/null +++ b/src/librustc/ich/impls_syntax.rs @@ -0,0 +1,301 @@ +// 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 module contains `HashStable` implementations for various data types +//! from libsyntax in no particular order. + +use ich::StableHashingContext; + +use std::hash as std_hash; +use std::mem; + +use syntax::ast; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +impl<'a, 'tcx> HashStable> for ::syntax::symbol::InternedString { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let s: &str = &**self; + s.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ast::Name { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_str().hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ::syntax::ast::AsmDialect { + Att, + Intel +}); + +impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { + Bang, + Attr, + Derive +}); + + +impl_stable_hash_for!(enum ::syntax::abi::Abi { + Cdecl, + Stdcall, + Fastcall, + Vectorcall, + Aapcs, + Win64, + SysV64, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + Rust, + C, + System, + RustIntrinsic, + RustCall, + PlatformIntrinsic, + Unadjusted +}); + +impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note }); +impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr }); + +impl<'a, 'tcx> HashStable> for ::syntax::attr::StabilityLevel { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { + reason.hash_stable(hcx, hasher); + issue.hash_stable(hcx, hasher); + } + ::syntax::attr::StabilityLevel::Stable { ref since } => { + since.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason }); + + +impl_stable_hash_for!(enum ::syntax::attr::IntType { + SignedInt(int_ty), + UnsignedInt(uint_ty) +}); + +impl_stable_hash_for!(enum ::syntax::ast::LitIntType { + Signed(int_ty), + Unsigned(int_ty), + Unsuffixed +}); + +impl_stable_hash_for_spanned!(::syntax::ast::LitKind); +impl_stable_hash_for!(enum ::syntax::ast::LitKind { + Str(value, style), + ByteStr(value), + Byte(value), + Char(value), + Int(value, lit_int_type), + Float(value, float_ty), + FloatUnsuffixed(value), + Bool(value) +}); + +impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 }); +impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 }); +impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); +impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal }); +impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst }); +impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final }); +impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name }); +impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); +impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); + +impl<'a, 'tcx> HashStable> for [ast::Attribute] { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Some attributes are always ignored during hashing. + let filtered: AccumulateVec<[&ast::Attribute; 8]> = self + .iter() + .filter(|attr| { + !attr.is_sugared_doc && + attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true) + }) + .collect(); + + filtered.len().hash_stable(hcx, hasher); + for attr in filtered { + attr.hash_stable(hcx, hasher); + } + } +} + +impl<'a, 'tcx> HashStable> for ast::Attribute { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Make sure that these have been filtered out. + debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); + debug_assert!(!self.is_sugared_doc); + + let ast::Attribute { + id: _, + style, + ref path, + ref tokens, + is_sugared_doc: _, + span, + } = *self; + + style.hash_stable(hcx, hasher); + path.segments.len().hash_stable(hcx, hasher); + for segment in &path.segments { + segment.identifier.name.hash_stable(hcx, hasher); + } + for tt in tokens.trees() { + tt.hash_stable(hcx, hasher); + } + span.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenTree { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + tokenstream::TokenTree::Token(span, ref token) => { + span.hash_stable(hcx, hasher); + hash_token(token, hcx, hasher, span); + } + tokenstream::TokenTree::Delimited(span, ref delimited) => { + span.hash_stable(hcx, hasher); + std_hash::Hash::hash(&delimited.delim, hasher); + for sub_tt in delimited.stream().trees() { + sub_tt.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenStream { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + for sub_tt in self.trees() { + sub_tt.hash_stable(hcx, hasher); + } + } +} + +fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + error_reporting_span: Span) { + mem::discriminant(token).hash_stable(hcx, hasher); + match *token { + token::Token::Eq | + token::Token::Lt | + token::Token::Le | + token::Token::EqEq | + token::Token::Ne | + token::Token::Ge | + token::Token::Gt | + token::Token::AndAnd | + token::Token::OrOr | + token::Token::Not | + token::Token::Tilde | + token::Token::At | + token::Token::Dot | + token::Token::DotDot | + token::Token::DotDotDot | + token::Token::Comma | + token::Token::Semi | + token::Token::Colon | + token::Token::ModSep | + token::Token::RArrow | + token::Token::LArrow | + token::Token::FatArrow | + token::Token::Pound | + token::Token::Dollar | + token::Token::Question | + token::Token::Underscore | + token::Token::Whitespace | + token::Token::Comment | + token::Token::Eof => {} + + token::Token::BinOp(bin_op_token) | + token::Token::BinOpEq(bin_op_token) => { + std_hash::Hash::hash(&bin_op_token, hasher); + } + + token::Token::OpenDelim(delim_token) | + token::Token::CloseDelim(delim_token) => { + std_hash::Hash::hash(&delim_token, hasher); + } + token::Token::Literal(ref lit, ref opt_name) => { + mem::discriminant(lit).hash_stable(hcx, hasher); + match *lit { + token::Lit::Byte(val) | + token::Lit::Char(val) | + token::Lit::Integer(val) | + token::Lit::Float(val) | + token::Lit::Str_(val) | + token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher), + token::Lit::StrRaw(val, n) | + token::Lit::ByteStrRaw(val, n) => { + val.hash_stable(hcx, hasher); + n.hash_stable(hcx, hasher); + } + }; + opt_name.hash_stable(hcx, hasher); + } + + token::Token::Ident(ident) | + token::Token::Lifetime(ident) | + token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher), + + token::Token::Interpolated(ref non_terminal) => { + // FIXME(mw): This could be implemented properly. It's just a + // lot of work, since we would need to hash the AST + // in a stable way, in addition to the HIR. + // Since this is hardly used anywhere, just emit a + // warning for now. + if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() { + let msg = format!("Quasi-quoting might make incremental \ + compilation very inefficient: {:?}", + non_terminal); + hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]); + } + + std_hash::Hash::hash(non_terminal, hasher); + } + + token::Token::DocComment(val) | + token::Token::Shebang(val) => val.hash_stable(hcx, hasher), + } +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs new file mode 100644 index 000000000000..7b6f3af2a11e --- /dev/null +++ b/src/librustc/ich/impls_ty.rs @@ -0,0 +1,415 @@ +// 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 module contains `HashStable` implementations for various data types +//! from rustc::ty in no particular order. + +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::hash as std_hash; +use std::mem; +use ty; + + +impl<'a, 'tcx> HashStable> for ty::Ty<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let type_hash = hcx.tcx().type_id_hash(*self); + type_hash.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); + +impl<'a, 'tcx, T> HashStable> for ty::Slice + where T: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + (&**self).hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::subst::Kind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_type().hash_stable(hcx, hasher); + self.as_region().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::Region { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ReErased | + ty::ReStatic | + ty::ReEmpty => { + // No variant fields to hash for these ... + } + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.depth.hash_stable(hcx, hasher); + i.hash_stable(hcx, hasher); + } + ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { + index.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + } + ty::ReLateBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + bug!("TypeIdHasher: unexpected region {:?}", *self) + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::AutoBorrow<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::AutoBorrow::Ref(ref region, mutability) => { + region.hash_stable(hcx, hasher); + mutability.hash_stable(hcx, hasher); + } + ty::adjustment::AutoBorrow::RawPtr(mutability) => { + mutability.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::Adjust<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer => {} + ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { + autoderefs.hash_stable(hcx, hasher); + autoref.hash_stable(hcx, hasher); + unsize.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); +impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef }); +impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); +impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); + +impl_stable_hash_for!(enum ty::BorrowKind { + ImmBorrow, + UniqueImmBorrow, + MutBorrow +}); + + +impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(ref up_var_borrow) => { + up_var_borrow.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::FnSig<'tcx> { + inputs_and_output, + variadic, + unsafety, + abi +}); + +impl<'a, 'tcx, T> HashStable> for ty::Binder + where T: HashStable> + ty::fold::TypeFoldable<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce }); + +impl_stable_hash_for!(enum ty::Visibility { + Public, + Restricted(def_id), + Invisible +}); + +impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); +impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); +impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); + +impl<'a, 'tcx, A, B> HashStable> for ty::OutlivesPredicate + where A: HashStable>, + B: HashStable>, +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::OutlivesPredicate(ref a, ref b) = *self; + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }); +impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name }); + + +impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::Predicate::Trait(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Equate(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::RegionOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::TypeOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Projection(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::WellFormed(ty) => { + ty.hash_stable(hcx, hasher); + } + ty::Predicate::ObjectSafe(def_id) => { + def_id.hash_stable(hcx, hasher); + } + ty::Predicate::ClosureKind(def_id, closure_kind) => { + def_id.hash_stable(hcx, hasher); + closure_kind.hash_stable(hcx, hasher); + } + } + } +} + + +impl<'a, 'tcx> HashStable> for ty::AdtFlags { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + std_hash::Hash::hash(self, hasher); + } +} + +impl_stable_hash_for!(struct ty::VariantDef { + did, + name, + discr, + fields, + ctor_kind +}); + +impl_stable_hash_for!(enum ty::VariantDiscr { + Explicit(def_id), + Relative(distance) +}); + +impl_stable_hash_for!(struct ty::FieldDef { + did, + name, + vis +}); + +impl<'a, 'tcx> HashStable> +for ::middle::const_val::ConstVal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::const_val::ConstVal; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + ConstVal::Float(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Integral(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Str(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::ByteStr(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Bool(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Function(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + ConstVal::Struct(ref _name_value_map) => { + // BTreeMap>), + panic!("Ordering still unstable") + } + ConstVal::Tuple(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Array(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Repeat(ref value, times) => { + value.hash_stable(hcx, hasher); + times.hash_stable(hcx, hasher); + } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); + + +impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { + parent, + predicates +}); + +impl_stable_hash_for!(enum ty::Variance { + Covariant, + Invariant, + Contravariant, + Bivariant +}); + +impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { + Struct(index) +}); + +impl<'a, 'tcx> HashStable> for ty::Generics { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::Generics { + parent, + parent_regions, + parent_types, + ref regions, + ref types, + + // Reverse map to each `TypeParameterDef`'s `index` field, from + // `def_id.index` (`def_id.krate` is the same as the item's). + type_param_to_index: _, // Don't hash this + has_self, + } = *self; + + parent.hash_stable(hcx, hasher); + parent_regions.hash_stable(hcx, hasher); + parent_types.hash_stable(hcx, hasher); + regions.hash_stable(hcx, hasher); + types.hash_stable(hcx, hasher); + has_self.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::RegionParameterDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::RegionParameterDef { + name, + def_id, + index, + issue_32330: _, + pure_wrt_drop + } = *self; + + name.hash_stable(hcx, hasher); + def_id.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + pure_wrt_drop.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::TypeParameterDef { + name, + def_id, + index, + has_default, + object_lifetime_default, + pure_wrt_drop +}); + + +impl<'a, 'tcx, T> HashStable> +for ::middle::resolve_lifetime::Set1 + where T: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::resolve_lifetime::Set1; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Set1::Empty | + Set1::Many => { + // Nothing to do. + } + Set1::One(ref value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region { + Static, + EarlyBound(index, decl), + LateBound(db_index, decl), + LateBoundAnon(db_index, anon_index), + Free(call_site_scope_data, decl) +}); + +impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { + fn_id, + body_id +}); + +impl_stable_hash_for!(struct ty::DebruijnIndex { + depth +}); diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 209953f3c686..f0601a0efabf 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -8,13 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! ICH - Incremental Compilation Hash + pub use self::fingerprint::Fingerprint; pub use self::def_path_hash::DefPathHashes; pub use self::caching_codemap_view::CachingCodemapView; +pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; mod fingerprint; mod def_path_hash; mod caching_codemap_view; +mod hcx; + +mod impls_const_math; +mod impls_hir; +mod impls_mir; +mod impls_ty; +mod impls_syntax; pub const ATTR_DIRTY: &'static str = "rustc_dirty"; pub const ATTR_CLEAN: &'static str = "rustc_clean"; @@ -22,6 +32,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_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 DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ + ATTR_IF_THIS_CHANGED, + ATTR_THEN_THIS_WOULD_NEED, + ATTR_DIRTY, + ATTR_CLEAN, + ATTR_DIRTY_METADATA, + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, +]; pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ "cfg", @@ -30,5 +54,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, - ATTR_CLEAN_METADATA + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, ]; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 294f80d7d230..3b002fd4dfc1 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -41,6 +41,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] +#![feature(discriminant_value)] extern crate arena; extern crate core; diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 76dca1bb5b64..c18e585f7955 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + macro_rules! enum_from_u32 { ($(#[$attr:meta])* pub enum $name:ident { $($variant:ident = $e:expr,)* @@ -59,3 +61,80 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } + +#[macro_export] +macro_rules! __impl_stable_hash_field { + (DECL IGNORED) => (_); + (DECL $name:ident) => (ref $name); + (USE IGNORED $ctx:expr, $hasher:expr) => ({}); + (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher)); +} + +#[macro_export] +macro_rules! impl_stable_hash_for { + (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + use $enum_name::*; + ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); + + match *self { + $( + $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => { + $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)* + } + )* + } + } + } + }; + (struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name { + $(ref $field),* + } = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; + (tuple_struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name ( + $(ref $field),* + ) = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; +} + +#[macro_export] +macro_rules! impl_stable_hash_for_spanned { + ($T:path) => ( + + impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> + { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.node.hash_stable(hcx, hasher); + self.span.hash_stable(hcx, hasher); + } + } + ); +} + diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index bc9bbebb1796..799686ceca4a 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -10,7 +10,9 @@ use std::cell::{Ref, RefCell}; use rustc_data_structures::indexed_vec::IndexVec; - +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use ich::StableHashingContext; use mir::{Mir, BasicBlock}; use rustc_serialize as serialize; @@ -33,6 +35,13 @@ impl serialize::Decodable for Cache { } } +impl<'a, 'tcx> HashStable> for Cache { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHasher) { + // do nothing + } +} impl Cache { pub fn new() -> Self { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 01dc7f51e29d..aea4684e526c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -243,6 +243,19 @@ impl<'tcx> Mir<'tcx> { } } +impl_stable_hash_for!(struct Mir<'tcx> { + basic_blocks, + visibility_scopes, + promoted, + return_ty, + local_decls, + arg_count, + upvar_decls, + spread_arg, + span, + cache +}); + impl<'tcx> Index for Mir<'tcx> { type Output = BasicBlockData<'tcx>; @@ -830,6 +843,11 @@ pub struct Static<'tcx> { pub ty: Ty<'tcx>, } +impl_stable_hash_for!(struct Static<'tcx> { + def_id, + ty +}); + /// The `Projection` data structure defines things of the form `B.x` /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Lvalue`. See the aliases diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6a4e7db21dd1..3c529a698204 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -19,6 +19,7 @@ use dep_graph::{self, DepNode}; use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use ich::StableHashingContext; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; @@ -50,6 +51,8 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use hir; use hir::itemlikevisit::ItemLikeVisitor; @@ -1379,6 +1382,25 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} + +impl<'a, 'tcx> HashStable> for AdtDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::AdtDef { + did, + ref variants, + ref flags, + ref repr, + } = *self; + + did.hash_stable(hcx, hasher); + variants.hash_stable(hcx, hasher); + flags.hash_stable(hcx, hasher); + repr.hash_stable(hcx, hasher); + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } @@ -1391,6 +1413,13 @@ pub struct ReprOptions { pub int: Option, } +impl_stable_hash_for!(struct ReprOptions { + c, + packed, + simd, + int +}); + impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { let mut ret = ReprOptions::default(); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 9ccd95dd8d80..c1735b4a4ec9 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -37,6 +37,8 @@ #![feature(unsize)] #![feature(i128_type)] #![feature(conservative_impl_trait)] +#![feature(discriminant_value)] +#![feature(specialization)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 231c01c9ab78..dc412a0763ef 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::Hasher; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; use blake2b::Blake2bHasher; @@ -174,3 +174,193 @@ impl Hasher for StableHasher { self.write_ileb128(i as i64); } } + + +/// Something that implements `HashStable` can be hashed in a way that is +/// stable across multiple compiliation sessions. +pub trait HashStable { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher); +} + +// Implement HashStable by just calling `Hash::hash()`. This works fine for +// self-contained values that don't depend on the hashing context `CTX`. +macro_rules! impl_stable_hash_via_hash { + ($t:ty) => ( + impl HashStable for $t { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } + } + ); +} + +impl_stable_hash_via_hash!(i8); +impl_stable_hash_via_hash!(i16); +impl_stable_hash_via_hash!(i32); +impl_stable_hash_via_hash!(i64); +impl_stable_hash_via_hash!(isize); + +impl_stable_hash_via_hash!(u8); +impl_stable_hash_via_hash!(u16); +impl_stable_hash_via_hash!(u32); +impl_stable_hash_via_hash!(u64); +impl_stable_hash_via_hash!(usize); + +impl_stable_hash_via_hash!(u128); +impl_stable_hash_via_hash!(i128); + +impl_stable_hash_via_hash!(char); +impl_stable_hash_via_hash!(()); + +impl HashStable for f32 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u32 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl HashStable for f64 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u64 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl, T2: HashStable, CTX> HashStable for (T1, T2) { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.0.hash_stable(ctx, hasher); + self.1.hash_stable(ctx, hasher); + } +} + +impl, CTX> HashStable for [T] { + default fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for item in self { + item.hash_stable(ctx, hasher); + } + } +} + +impl, CTX> HashStable for Vec { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (&self[..]).hash_stable(ctx, hasher); + } +} + +impl HashStable for str { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash(hasher); + self.as_bytes().hash(hasher); + } +} + +impl HashStable for bool { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); + } +} + + +impl HashStable for Option + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + if let Some(ref value) = *self { + 1u8.hash_stable(ctx, hasher); + value.hash_stable(ctx, hasher); + } else { + 0u8.hash_stable(ctx, hasher); + } + } +} + +impl<'a, T, CTX> HashStable for &'a T + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(ctx, hasher); + } +} + +impl HashStable for ::std::mem::Discriminant { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } +} + +impl HashStable for ::std::collections::BTreeMap + where K: Ord + HashStable, + V: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for (k, v) in self { + k.hash_stable(ctx, hasher); + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::std::collections::BTreeSet + where T: Ord + HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in self { + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::indexed_vec::IndexVec + where T: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in &self.raw { + v.hash_stable(ctx, hasher); + } + } +} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c9496a4deb8e..c80a5a162779 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -27,24 +27,17 @@ //! at the end of compilation would be different from those computed //! at the beginning. -use syntax::ast; use std::cell::RefCell; use std::hash::Hash; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::intravisit as visit; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ich::{Fingerprint, StableHashingContext}; use rustc::ty::TyCtxt; -use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; -use rustc::session::config::DebugInfoLevel::NoDebugInfo; - -use self::svh_visitor::StrictVersionHashVisitor; - -mod svh_visitor; pub type IchHasher = StableHasher; @@ -94,91 +87,42 @@ impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { } } - -pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> IncrementalHashesMap { - let _ignore = tcx.dep_graph.in_ignore(); - let krate = tcx.hir.krate(); - let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo; - let mut visitor = HashItemsVisitor { - tcx: tcx, - hashes: IncrementalHashesMap::new(), - def_path_hashes: DefPathHashes::new(tcx), - codemap: CachingCodemapView::new(tcx), - hash_spans: hash_spans, - }; - record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { - visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| { - v.hash_crate_root_module(krate); - }); - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); - - for macro_def in krate.exported_macros.iter() { - visitor.calculate_node_id(macro_def.id, - |v| v.visit_macro_def(macro_def)); - } - }); - - tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); - - record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); - visitor.hashes -} - -struct HashItemsVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: DefPathHashes<'a, 'tcx>, - codemap: CachingCodemapView<'tcx>, +struct ComputeItemHashesVisitor<'a, 'tcx: 'a> { + hcx: StableHashingContext<'a, 'tcx>, hashes: IncrementalHashesMap, - hash_spans: bool, } -impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { - fn calculate_node_id(&mut self, id: ast::NodeId, walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) +impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { + fn compute_and_store_ich_for_item_like(&mut self, + dep_node: DepNode, + hash_bodies: bool, + item_like: T) + where T: HashStable> { - let def_id = self.tcx.hir.local_def_id(id); - self.calculate_def_id(def_id, walk_op) - } + let mut hasher = IchHasher::new(); + self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| { + item_like.hash_stable(hcx, &mut hasher); + }); - fn calculate_def_id(&mut self, def_id: DefId, mut walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - assert!(def_id.is_local()); - debug!("HashItemsVisitor::calculate(def_id={:?})", def_id); - self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op); - self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op); - } - - fn calculate_def_hash(&mut self, - dep_node: DepNode, - hash_bodies: bool, - walk_op: &mut W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - let mut state = IchHasher::new(); - walk_op(&mut StrictVersionHashVisitor::new(&mut state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - hash_bodies)); - let bytes_hashed = state.bytes_hashed(); - let item_hash = state.finish(); + let bytes_hashed = hasher.bytes_hashed(); + let item_hash = hasher.finish(); debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash); self.hashes.insert(dep_node, item_hash); - let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + + let tcx = self.hcx.tcx(); + let bytes_hashed = + tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + bytes_hashed; - self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); + tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); } fn compute_crate_hash(&mut self) { - let krate = self.tcx.hir.krate(); + let tcx = self.hcx.tcx(); + let krate = tcx.hir.krate(); let mut crate_state = IchHasher::new(); - let crate_disambiguator = self.tcx.sess.local_crate_disambiguator(); + let crate_disambiguator = tcx.sess.local_crate_disambiguator(); "crate_disambiguator".hash(&mut crate_state); crate_disambiguator.as_str().len().hash(&mut crate_state); crate_disambiguator.as_str().hash(&mut crate_state); @@ -186,7 +130,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // add each item (in some deterministic order) to the overall // crate hash. { - let def_path_hashes = &mut self.def_path_hashes; + let hcx = &mut self.hcx; let mut item_hashes: Vec<_> = self.hashes.iter() .map(|(item_dep_node, &item_hash)| { @@ -194,7 +138,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // DepNode where the u64 is the // hash of the def-id's def-path: let item_dep_node = - item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did))) + item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did))) .unwrap(); (item_dep_node, item_hash) }) @@ -203,40 +147,85 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { item_hashes.hash(&mut crate_state); } - { - let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - false); - visitor.hash_attributes(&krate.attrs); - } + krate.attrs.hash_stable(&mut self.hcx, &mut crate_state); let crate_hash = crate_state.finish(); self.hashes.insert(DepNode::Krate, crate_hash); debug!("calculate_crate_hash: crate_hash={:?}", crate_hash); } + + fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) { + let hir::Crate { + ref module, + // Crate attributes are not copied over to the root `Mod`, so hash + // them explicitly here. + ref attrs, + span, + + // These fields are handled separately: + exported_macros: _, + items: _, + trait_items: _, + impl_items: _, + bodies: _, + trait_impls: _, + trait_default_impl: _, + body_ids: _, + } = *krate; + + let def_id = DefId::local(CRATE_DEF_INDEX); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), + false, + (module, (span, attrs))); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), + true, + (module, (span, attrs))); + } } - -impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - +impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - self.calculate_node_id(item.id, |v| v.visit_item(item)); - visit::walk_item(self, item); + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item)); - visit::walk_trait_item(self, trait_item); + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item)); - visit::walk_impl_item(self, impl_item); + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } } + +pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> IncrementalHashesMap { + let _ignore = tcx.dep_graph.in_ignore(); + let krate = tcx.hir.krate(); + + let mut visitor = ComputeItemHashesVisitor { + hcx: StableHashingContext::new(tcx), + hashes: IncrementalHashesMap::new(), + }; + + record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { + visitor.hash_crate_root_module(krate); + krate.visit_all_item_likes(&mut visitor); + + for macro_def in krate.exported_macros.iter() { + let def_id = tcx.hir.local_def_id(macro_def.id); + visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def); + visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def); + } + }); + + tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); + + record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); + visitor.hashes +} diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs deleted file mode 100644 index 5401b371888e..000000000000 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ /dev/null @@ -1,1111 +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 self::SawExprComponent::*; -use self::SawAbiComponent::*; -use self::SawItemComponent::*; -use self::SawPatComponent::*; -use self::SawTyComponent::*; -use self::SawTraitOrImplItemComponent::*; -use syntax::abi::Abi; -use syntax::ast::{self, Name, NodeId}; -use syntax::attr; -use syntax::ext::hygiene::SyntaxContext; -use syntax::parse::token; -use syntax::symbol::InternedString; -use syntax_pos::{Span, BytePos}; -use syntax::tokenstream; -use rustc::hir; -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{self as visit, Visitor}; -use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES}; -use rustc::ty::TyCtxt; -use std::hash::{Hash, Hasher}; - -use super::IchHasher; - -pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { - pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, - pub st: &'a mut IchHasher, - // collect a deterministic hash of def-ids that we have seen - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - hash_spans: bool, - codemap: &'a mut CachingCodemapView<'tcx>, - overflow_checks_enabled: bool, - hash_bodies: bool, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - pub fn new(st: &'a mut IchHasher, - tcx: TyCtxt<'hash, 'tcx, 'tcx>, - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - codemap: &'a mut CachingCodemapView<'tcx>, - hash_spans: bool, - hash_bodies: bool) - -> Self { - let check_overflow = tcx.sess.overflow_checks(); - - StrictVersionHashVisitor { - st: st, - tcx: tcx, - def_path_hashes: def_path_hashes, - hash_spans: hash_spans, - codemap: codemap, - overflow_checks_enabled: check_overflow, - hash_bodies: hash_bodies, - } - } - - fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { - self.def_path_hashes.hash(def_id) - } - - // Hash a span in a stable way. We can't directly hash the span's BytePos - // fields (that would be similar to hashing pointers, since those are just - // offsets into the CodeMap). Instead, we hash the (file name, line, column) - // triple, which stays the same even if the containing FileMap has moved - // within the CodeMap. - // Also note that we are hashing byte offsets for the column, not unicode - // codepoint offsets. For the purpose of the hash that's sufficient. - // Also, hashing filenames is expensive so we avoid doing it twice when the - // span starts and ends in the same file, which is almost always the case. - fn hash_span(&mut self, span: Span) { - debug!("hash_span: st={:?}", self.st); - - // If this is not an empty or invalid span, we want to hash the last - // position that belongs to it, as opposed to hashing the first - // position past it. - let span_hi = if span.hi > span.lo { - // We might end up in the middle of a multibyte character here, - // but that's OK, since we are not trying to decode anything at - // this position. - span.hi - BytePos(1) - } else { - span.hi - }; - - let expn_kind = if span.ctxt == SyntaxContext::empty() { - SawSpanExpnKind::NoExpansion - } else { - SawSpanExpnKind::SomeExpansion - }; - - let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); - let loc1 = loc1.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) - .unwrap_or(("???", 0, BytePos(0))); - - let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); - let loc2 = loc2.as_ref() - .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) - .unwrap_or(("???", 0, BytePos(0))); - - let saw = if loc1.0 == loc2.0 { - SawSpan(loc1.0, - loc1.1, loc1.2, - loc2.1, loc2.2, - expn_kind) - } else { - SawSpanTwoFiles(loc1.0, loc1.1, loc1.2, - loc2.0, loc2.1, loc2.2, - expn_kind) - }; - saw.hash(self.st); - - if expn_kind == SawSpanExpnKind::SomeExpansion { - self.hash_span(span.source_callsite()); - } - } - - fn hash_discriminant(&mut self, v: &T) { - unsafe { - let disr = ::std::intrinsics::discriminant_value(v); - debug!("hash_discriminant: disr={}, st={:?}", disr, self.st); - disr.hash(self.st); - } - } -} - -// To off-load the bulk of the hash-computation on #[derive(Hash)], -// we define a set of enums corresponding to the content that our -// crate visitor will encounter as it traverses the ast. -// -// The important invariant is that all of the Saw*Component enums -// do not carry any Spans, Names, or Idents. -// -// Not carrying any Names/Idents is the important fix for problem -// noted on PR #13948: using the ident.name as the basis for a -// hash leads to unstable SVH, because ident.name is just an index -// into intern table (i.e. essentially a random address), not -// computed from the name content. -// -// With the below enums, the SVH computation is not sensitive to -// artifacts of how rustc was invoked nor of how the source code -// was laid out. (Or at least it is *less* sensitive.) - -// This enum represents the different potential bits of code the -// visitor could encounter that could affect the ABI for the crate, -// and assigns each a distinct tag to feed into the hash computation. -#[derive(Hash)] -enum SawAbiComponent<'a> { - - // FIXME (#14132): should we include (some function of) - // ident.ctxt as well? - SawIdent(InternedString), - SawStructDef(InternedString), - - SawLifetime, - SawLifetimeDef(usize), - - SawMod, - SawForeignItem(SawForeignItemComponent), - SawItem(SawItemComponent), - SawTy(SawTyComponent), - SawFnDecl(bool), - SawGenerics, - SawTraitItem(SawTraitOrImplItemComponent), - SawImplItem(SawTraitOrImplItemComponent), - SawStructField, - SawVariant(bool), - SawQPath, - SawPathSegment, - SawPathParameters, - SawBlock, - SawPat(SawPatComponent), - SawLocal, - SawArm, - SawExpr(SawExprComponent<'a>), - SawStmt, - SawVis, - SawAssociatedItemKind(hir::AssociatedItemKind), - SawDefaultness(hir::Defaultness), - SawWherePredicate, - SawTyParamBound, - SawPolyTraitRef, - SawAssocTypeBinding, - SawAttribute(ast::AttrStyle), - SawMacroDef, - SawSpan(&'a str, - usize, BytePos, - usize, BytePos, - SawSpanExpnKind), - SawSpanTwoFiles(&'a str, usize, BytePos, - &'a str, usize, BytePos, - SawSpanExpnKind), -} - -/// SawExprComponent carries all of the information that we want -/// to include in the hash that *won't* be covered by the -/// subsequent recursive traversal of the expression's -/// substructure by the visitor. -/// -/// We know every Expr_ variant is covered by a variant because -/// `fn saw_expr` maps each to some case below. Ensuring that -/// each variant carries an appropriate payload has to be verified -/// by hand. -/// -/// (However, getting that *exactly* right is not so important -/// because the SVH is just a developer convenience; there is no -/// guarantee of collision-freedom, hash collisions are just -/// (hopefully) unlikely.) -/// -/// The xxxComponent enums and saw_xxx functions for Item, Pat, -/// Ty, TraitItem and ImplItem follow the same methodology. -#[derive(Hash)] -enum SawExprComponent<'a> { - - SawExprLoop(Option), - SawExprField(InternedString), - SawExprTupField(usize), - SawExprBreak(Option), - SawExprAgain(Option), - - SawExprBox, - SawExprArray, - SawExprCall, - SawExprMethodCall, - SawExprTup, - SawExprBinary(hir::BinOp_), - SawExprUnary(hir::UnOp), - SawExprLit(ast::LitKind), - SawExprLitStr(InternedString, ast::StrStyle), - SawExprLitFloat(InternedString, Option), - SawExprCast, - SawExprType, - SawExprIf, - SawExprWhile, - SawExprMatch, - SawExprClosure(CaptureClause), - SawExprBlock, - SawExprAssign, - SawExprAssignOp(hir::BinOp_), - SawExprIndex, - SawExprPath, - SawExprAddrOf(hir::Mutability), - SawExprRet, - SawExprInlineAsm(StableInlineAsm<'a>), - SawExprStruct, - SawExprRepeat, -} - -// The boolean returned indicates whether the span of this expression is always -// significant, regardless of debuginfo. -fn saw_expr<'a>(node: &'a Expr_, - overflow_checks_enabled: bool) - -> (SawExprComponent<'a>, bool) { - let binop_can_panic_at_runtime = |binop| { - match binop { - BiAdd | - BiSub | - BiMul => overflow_checks_enabled, - - BiDiv | - BiRem => true, - - BiAnd | - BiOr | - BiBitXor | - BiBitAnd | - BiBitOr | - BiShl | - BiShr | - BiEq | - BiLt | - BiLe | - BiNe | - BiGe | - BiGt => false - } - }; - - let unop_can_panic_at_runtime = |unop| { - match unop { - UnDeref | - UnNot => false, - UnNeg => overflow_checks_enabled, - } - }; - - match *node { - ExprBox(..) => (SawExprBox, false), - ExprArray(..) => (SawExprArray, false), - ExprCall(..) => (SawExprCall, false), - ExprMethodCall(..) => (SawExprMethodCall, false), - ExprTup(..) => (SawExprTup, false), - ExprBinary(op, ..) => { - (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprUnary(op, _) => { - (SawExprUnary(op), unop_can_panic_at_runtime(op)) - } - ExprLit(ref lit) => (saw_lit(lit), false), - ExprCast(..) => (SawExprCast, false), - ExprType(..) => (SawExprType, false), - ExprIf(..) => (SawExprIf, false), - ExprWhile(..) => (SawExprWhile, false), - ExprLoop(_, id, _) => (SawExprLoop(id.map(|id| id.node.as_str())), false), - ExprMatch(..) => (SawExprMatch, false), - ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false), - ExprBlock(..) => (SawExprBlock, false), - ExprAssign(..) => (SawExprAssign, false), - ExprAssignOp(op, ..) => { - (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprField(_, name) => (SawExprField(name.node.as_str()), false), - ExprTupField(_, id) => (SawExprTupField(id.node), false), - ExprIndex(..) => (SawExprIndex, true), - ExprPath(_) => (SawExprPath, false), - ExprAddrOf(m, _) => (SawExprAddrOf(m), false), - ExprBreak(label, _) => (SawExprBreak(label.ident.map(|i| - i.node.name.as_str())), false), - ExprAgain(label) => (SawExprAgain(label.ident.map(|i| - i.node.name.as_str())), false), - ExprRet(..) => (SawExprRet, false), - ExprInlineAsm(ref a,..) => (SawExprInlineAsm(StableInlineAsm(a)), false), - ExprStruct(..) => (SawExprStruct, false), - ExprRepeat(..) => (SawExprRepeat, false), - } -} - -fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> { - match lit.node { - ast::LitKind::Str(s, style) => SawExprLitStr(s.as_str(), style), - ast::LitKind::Float(s, ty) => SawExprLitFloat(s.as_str(), Some(ty)), - ast::LitKind::FloatUnsuffixed(s) => SawExprLitFloat(s.as_str(), None), - ref node @ _ => SawExprLit(node.clone()), - } -} - -#[derive(Hash)] -enum SawItemComponent { - SawItemExternCrate, - SawItemUse(UseKind), - SawItemStatic(Mutability), - SawItemConst, - SawItemFn(Unsafety, Constness, Abi), - SawItemMod, - SawItemForeignMod(Abi), - SawItemTy, - SawItemEnum, - SawItemStruct, - SawItemUnion, - SawItemTrait(Unsafety), - SawItemDefaultImpl(Unsafety), - SawItemImpl(Unsafety, ImplPolarity) -} - -fn saw_item(node: &Item_) -> SawItemComponent { - match *node { - ItemExternCrate(..) => SawItemExternCrate, - ItemUse(_, kind) => SawItemUse(kind), - ItemStatic(_, mutability, _) => SawItemStatic(mutability), - ItemConst(..) =>SawItemConst, - ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), - ItemMod(..) => SawItemMod, - ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi), - ItemTy(..) => SawItemTy, - ItemEnum(..) => SawItemEnum, - ItemStruct(..) => SawItemStruct, - ItemUnion(..) => SawItemUnion, - ItemTrait(unsafety, ..) => SawItemTrait(unsafety), - ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety), - ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity) - } -} - -#[derive(Hash)] -enum SawForeignItemComponent { - Static { mutable: bool }, - Fn, -} - -#[derive(Hash)] -enum SawPatComponent { - SawPatWild, - SawPatBinding(BindingMode), - SawPatStruct, - SawPatTupleStruct, - SawPatPath, - SawPatTuple, - SawPatBox, - SawPatRef(Mutability), - SawPatLit, - SawPatRange, - SawPatSlice -} - -fn saw_pat(node: &PatKind) -> SawPatComponent { - match *node { - PatKind::Wild => SawPatWild, - PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode), - PatKind::Struct(..) => SawPatStruct, - PatKind::TupleStruct(..) => SawPatTupleStruct, - PatKind::Path(_) => SawPatPath, - PatKind::Tuple(..) => SawPatTuple, - PatKind::Box(..) => SawPatBox, - PatKind::Ref(_, mutability) => SawPatRef(mutability), - PatKind::Lit(..) => SawPatLit, - PatKind::Range(..) => SawPatRange, - PatKind::Slice(..) => SawPatSlice - } -} - -#[derive(Hash)] -enum SawTyComponent { - SawTySlice, - SawTyArray, - SawTyPtr(Mutability), - SawTyRptr(Mutability), - SawTyBareFn(Unsafety, Abi), - SawTyNever, - SawTyTup, - SawTyPath, - SawTyObjectSum, - SawTyImplTrait, - SawTyTypeof, - SawTyInfer -} - -fn saw_ty(node: &Ty_) -> SawTyComponent { - match *node { - TySlice(..) => SawTySlice, - TyArray(..) => SawTyArray, - TyPtr(ref mty) => SawTyPtr(mty.mutbl), - TyRptr(_, ref mty) => SawTyRptr(mty.mutbl), - TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi), - TyNever => SawTyNever, - TyTup(..) => SawTyTup, - TyPath(_) => SawTyPath, - TyTraitObject(..) => SawTyObjectSum, - TyImplTrait(..) => SawTyImplTrait, - TyTypeof(..) => SawTyTypeof, - TyInfer => SawTyInfer - } -} - -#[derive(Hash)] -enum SawTraitOrImplItemComponent { - SawTraitOrImplItemConst, - // The boolean signifies whether a body is present - SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool), - SawTraitOrImplItemType -} - -fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent { - match *ti { - TraitItemKind::Const(..) => SawTraitOrImplItemConst, - TraitItemKind::Method(ref sig, TraitMethod::Required(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false), - TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - TraitItemKind::Type(..) => SawTraitOrImplItemType - } -} - -fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { - match *ii { - ImplItemKind::Const(..) => SawTraitOrImplItemConst, - ImplItemKind::Method(ref sig, _) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - ImplItemKind::Type(..) => SawTraitOrImplItemType - } -} - -#[derive(Clone, Copy, Hash, Eq, PartialEq)] -enum SawSpanExpnKind { - NoExpansion, - SomeExpansion, -} - -/// A wrapper that provides a stable Hash implementation. -struct StableInlineAsm<'a>(&'a InlineAsm); - -impl<'a> Hash for StableInlineAsm<'a> { - fn hash(&self, state: &mut H) { - let InlineAsm { - asm, - asm_str_style, - ref outputs, - ref inputs, - ref clobbers, - volatile, - alignstack, - dialect, - ctxt: _, // This is used for error reporting - } = *self.0; - - asm.as_str().hash(state); - asm_str_style.hash(state); - outputs.len().hash(state); - for output in outputs { - let InlineAsmOutput { constraint, is_rw, is_indirect } = *output; - constraint.as_str().hash(state); - is_rw.hash(state); - is_indirect.hash(state); - } - inputs.len().hash(state); - for input in inputs { - input.as_str().hash(state); - } - clobbers.len().hash(state); - for clobber in clobbers { - clobber.as_str().hash(state); - } - volatile.hash(state); - alignstack.hash(state); - dialect.hash(state); - } -} - -macro_rules! hash_attrs { - ($visitor:expr, $attrs:expr) => ({ - let attrs = $attrs; - if attrs.len() > 0 { - $visitor.hash_attributes(attrs); - } - }) -} - -macro_rules! hash_span { - ($visitor:expr, $span:expr) => ({ - hash_span!($visitor, $span, false) - }); - ($visitor:expr, $span:expr, $force:expr) => ({ - if $force || $visitor.hash_spans { - $visitor.hash_span($span); - } - }); -} - -impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> { - if self.hash_bodies { - visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } else { - visit::NestedVisitorMap::None - } - } - - fn visit_variant_data(&mut self, - s: &'tcx VariantData, - name: Name, - _: &'tcx Generics, - _: NodeId, - span: Span) { - debug!("visit_variant_data: st={:?}", self.st); - SawStructDef(name.as_str()).hash(self.st); - hash_span!(self, span); - visit::walk_struct_def(self, s); - } - - fn visit_variant(&mut self, - v: &'tcx Variant, - g: &'tcx Generics, - item_id: NodeId) { - debug!("visit_variant: st={:?}", self.st); - SawVariant(v.node.disr_expr.is_some()).hash(self.st); - hash_attrs!(self, &v.node.attrs); - visit::walk_variant(self, v, g, item_id) - } - - fn visit_name(&mut self, span: Span, name: Name) { - debug!("visit_name: st={:?}", self.st); - SawIdent(name.as_str()).hash(self.st); - hash_span!(self, span); - } - - fn visit_lifetime(&mut self, l: &'tcx Lifetime) { - debug!("visit_lifetime: st={:?}", self.st); - SawLifetime.hash(self.st); - visit::walk_lifetime(self, l); - } - - fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) { - debug!("visit_lifetime_def: st={:?}", self.st); - SawLifetimeDef(l.bounds.len()).hash(self.st); - visit::walk_lifetime_def(self, l); - } - - fn visit_expr(&mut self, ex: &'tcx Expr) { - debug!("visit_expr: st={:?}", self.st); - let (saw_expr, force_span) = saw_expr(&ex.node, - self.overflow_checks_enabled); - SawExpr(saw_expr).hash(self.st); - // No need to explicitly hash the discriminant here, since we are - // implicitly hashing the discriminant of SawExprComponent. - hash_span!(self, ex.span, force_span); - hash_attrs!(self, &ex.attrs); - - // Always hash nested constant bodies (e.g. n in `[x; n]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_expr(self, ex); - self.hash_bodies = hash_bodies; - } - - fn visit_stmt(&mut self, s: &'tcx Stmt) { - debug!("visit_stmt: st={:?}", self.st); - - // We don't want to modify the hash for decls, because - // they might be item decls (if they are local decls, - // we'll hash that fact in visit_local); but we do want to - // remember if this was a StmtExpr or StmtSemi (the later - // had an explicit semi-colon; this affects the typing - // rules). - match s.node { - StmtDecl(..) => (), - StmtExpr(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - StmtSemi(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - } - - visit::walk_stmt(self, s) - } - - fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { - debug!("visit_foreign_item: st={:?}", self.st); - - match i.node { - ForeignItemFn(..) => { - SawForeignItem(SawForeignItemComponent::Fn) - } - ForeignItemStatic(_, mutable) => { - SawForeignItem(SawForeignItemComponent::Static { - mutable: mutable - }) - } - }.hash(self.st); - - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_foreign_item(self, i) - } - - fn visit_item(&mut self, i: &'tcx Item) { - debug!("visit_item: {:?} st={:?}", i, self.st); - - self.maybe_enable_overflow_checks(&i.attrs); - - SawItem(saw_item(&i.node)).hash(self.st); - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_item(self, i) - } - - fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) { - debug!("visit_mod: st={:?}", self.st); - SawMod.hash(self.st); - hash_span!(self, span); - visit::walk_mod(self, m, n) - } - - fn visit_ty(&mut self, t: &'tcx Ty) { - debug!("visit_ty: st={:?}", self.st); - SawTy(saw_ty(&t.node)).hash(self.st); - hash_span!(self, t.span); - - // Always hash nested constant bodies (e.g. N in `[T; N]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_ty(self, t); - self.hash_bodies = hash_bodies; - } - - fn visit_generics(&mut self, g: &'tcx Generics) { - debug!("visit_generics: st={:?}", self.st); - SawGenerics.hash(self.st); - visit::walk_generics(self, g) - } - - fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) { - debug!("visit_fn_decl: st={:?}", self.st); - SawFnDecl(fd.variadic).hash(self.st); - visit::walk_fn_decl(self, fd) - } - - fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { - debug!("visit_trait_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ti.attrs); - - SawTraitItem(saw_trait_item(&ti.node)).hash(self.st); - hash_span!(self, ti.span); - hash_attrs!(self, &ti.attrs); - visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { - debug!("visit_impl_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ii.attrs); - - SawImplItem(saw_impl_item(&ii.node)).hash(self.st); - hash_span!(self, ii.span); - hash_attrs!(self, &ii.attrs); - visit::walk_impl_item(self, ii) - } - - fn visit_struct_field(&mut self, s: &'tcx StructField) { - debug!("visit_struct_field: st={:?}", self.st); - SawStructField.hash(self.st); - hash_span!(self, s.span); - hash_attrs!(self, &s.attrs); - visit::walk_struct_field(self, s) - } - - fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) { - debug!("visit_qpath: st={:?}", self.st); - SawQPath.hash(self.st); - self.hash_discriminant(qpath); - visit::walk_qpath(self, qpath, id, span) - } - - fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { - debug!("visit_path: st={:?}", self.st); - hash_span!(self, path.span); - visit::walk_path(self, path) - } - - fn visit_def_mention(&mut self, def: Def) { - self.hash_def(def); - } - - fn visit_block(&mut self, b: &'tcx Block) { - debug!("visit_block: st={:?}", self.st); - SawBlock.hash(self.st); - hash_span!(self, b.span); - visit::walk_block(self, b) - } - - fn visit_pat(&mut self, p: &'tcx Pat) { - debug!("visit_pat: st={:?}", self.st); - SawPat(saw_pat(&p.node)).hash(self.st); - hash_span!(self, p.span); - visit::walk_pat(self, p) - } - - fn visit_local(&mut self, l: &'tcx Local) { - debug!("visit_local: st={:?}", self.st); - SawLocal.hash(self.st); - hash_attrs!(self, &l.attrs); - visit::walk_local(self, l) - // No need to hash span, we are hashing all component spans - } - - fn visit_arm(&mut self, a: &'tcx Arm) { - debug!("visit_arm: st={:?}", self.st); - SawArm.hash(self.st); - hash_attrs!(self, &a.attrs); - visit::walk_arm(self, a) - } - - fn visit_id(&mut self, id: NodeId) { - debug!("visit_id: id={} st={:?}", id, self.st); - self.hash_resolve(id) - } - - fn visit_vis(&mut self, v: &'tcx Visibility) { - debug!("visit_vis: st={:?}", self.st); - SawVis.hash(self.st); - self.hash_discriminant(v); - visit::walk_vis(self, v) - } - - fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawAssociatedItemKind(*kind).hash(self.st); - visit::walk_associated_item_kind(self, kind); - } - - fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawDefaultness(*defaultness).hash(self.st); - visit::walk_defaultness(self, defaultness); - } - - fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { - debug!("visit_where_predicate: st={:?}", self.st); - SawWherePredicate.hash(self.st); - self.hash_discriminant(predicate); - // Ignoring span. Any important nested components should be visited. - visit::walk_where_predicate(self, predicate) - } - - fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) { - debug!("visit_ty_param_bound: st={:?}", self.st); - SawTyParamBound.hash(self.st); - self.hash_discriminant(bounds); - // The TraitBoundModifier in TraitTyParamBound will be hash in - // visit_poly_trait_ref() - visit::walk_ty_param_bound(self, bounds) - } - - fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) { - debug!("visit_poly_trait_ref: st={:?}", self.st); - SawPolyTraitRef.hash(self.st); - m.hash(self.st); - visit::walk_poly_trait_ref(self, t, m) - } - - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) { - debug!("visit_path_segment: st={:?}", self.st); - SawPathSegment.hash(self.st); - visit::walk_path_segment(self, path_span, path_segment) - } - - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) { - debug!("visit_path_parameters: st={:?}", self.st); - SawPathParameters.hash(self.st); - self.hash_discriminant(path_parameters); - visit::walk_path_parameters(self, path_span, path_parameters) - } - - fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { - debug!("visit_assoc_type_binding: st={:?}", self.st); - SawAssocTypeBinding.hash(self.st); - hash_span!(self, type_binding.span); - visit::walk_assoc_type_binding(self, type_binding) - } - - fn visit_attribute(&mut self, _: &ast::Attribute) { - // We explicitly do not use this method, since doing that would - // implicitly impose an order on the attributes being hashed, while we - // explicitly don't want their order to matter - } - - fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) { - debug!("visit_macro_def: st={:?}", self.st); - SawMacroDef.hash(self.st); - hash_attrs!(self, ¯o_def.attrs); - for tt in macro_def.body.trees() { - self.hash_token_tree(&tt); - } - visit::walk_macro_def(self, macro_def) - } -} - -#[derive(Hash)] -pub enum DefHash { - SawDefId, - SawLabel, - SawPrimTy, - SawSelfTy, - SawErr, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn hash_resolve(&mut self, id: ast::NodeId) { - // Because whether or not a given id has an entry is dependent - // solely on expr variant etc, we don't need to hash whether - // or not an entry was present (we are already hashing what - // variant it is above when we visit the HIR). - - if let Some(traits) = self.tcx.trait_map.get(&id) { - debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st); - traits.len().hash(self.st); - - // The ordering of the candidates is not fixed. So we hash - // the def-ids and then sort them and hash the collection. - let mut candidates: Vec<_> = - traits.iter() - .map(|&TraitCandidate { def_id, import_id: _ }| { - self.compute_def_id_hash(def_id) - }) - .collect(); - candidates.sort(); - candidates.hash(self.st); - } - } - - fn hash_def_id(&mut self, def_id: DefId) { - self.compute_def_id_hash(def_id).hash(self.st); - } - - fn hash_def(&mut self, def: Def) { - match def { - // Crucial point: for all of these variants, the variant + - // add'l data that is added is always the same if the - // def-id is the same, so it suffices to hash the def-id - Def::Fn(..) | - Def::Mod(..) | - Def::Static(..) | - Def::Variant(..) | - Def::VariantCtor(..) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::TyParam(..) | - Def::Struct(..) | - Def::StructCtor(..) | - Def::Union(..) | - Def::Trait(..) | - Def::Method(..) | - Def::Const(..) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Upvar(..) | - Def::Macro(..) => { - DefHash::SawDefId.hash(self.st); - self.hash_def_id(def.def_id()); - } - - Def::Label(..) => { - DefHash::SawLabel.hash(self.st); - // we don't encode the `id` because it always refers to something - // within this item, so if it changed, there would have to be other - // changes too - } - Def::PrimTy(ref prim_ty) => { - DefHash::SawPrimTy.hash(self.st); - prim_ty.hash(self.st); - } - Def::SelfTy(..) => { - DefHash::SawSelfTy.hash(self.st); - // the meaning of Self is always the same within a - // given context, so we don't need to hash the other - // fields - } - Def::Err => { - DefHash::SawErr.hash(self.st); - } - } - } - - pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { - debug!("hash_attributes: st={:?}", self.st); - let indices = self.indices_sorted_by(attributes, |attr| attr.name()); - - for i in indices { - let attr = &attributes[i]; - match attr.name() { - Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue, - _ => {} - }; - if !attr.is_sugared_doc { - SawAttribute(attr.style).hash(self.st); - for segment in &attr.path.segments { - SawIdent(segment.identifier.name.as_str()).hash(self.st); - } - for tt in attr.tokens.trees() { - self.hash_token_tree(&tt); - } - } - } - } - - fn indices_sorted_by(&mut self, items: &[T], get_key: F) -> Vec - where K: Ord, - F: Fn(&T) -> K - { - let mut indices = Vec::with_capacity(items.len()); - indices.extend(0 .. items.len()); - indices.sort_by_key(|index| get_key(&items[*index])); - indices - } - - fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) { - if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { - self.overflow_checks_enabled = true; - } - } - - fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) { - self.hash_discriminant(tt); - match *tt { - tokenstream::TokenTree::Token(span, ref token) => { - hash_span!(self, span); - self.hash_token(token, span); - } - tokenstream::TokenTree::Delimited(span, ref delimited) => { - hash_span!(self, span); - delimited.delim.hash(self.st); - for sub_tt in delimited.stream().trees() { - self.hash_token_tree(&sub_tt); - } - } - } - } - - fn hash_token(&mut self, - token: &token::Token, - error_reporting_span: Span) { - self.hash_discriminant(token); - match *token { - token::Token::Eq | - token::Token::Lt | - token::Token::Le | - token::Token::EqEq | - token::Token::Ne | - token::Token::Ge | - token::Token::Gt | - token::Token::AndAnd | - token::Token::OrOr | - token::Token::Not | - token::Token::Tilde | - token::Token::At | - token::Token::Dot | - token::Token::DotDot | - token::Token::DotDotDot | - token::Token::Comma | - token::Token::Semi | - token::Token::Colon | - token::Token::ModSep | - token::Token::RArrow | - token::Token::LArrow | - token::Token::FatArrow | - token::Token::Pound | - token::Token::Dollar | - token::Token::Question | - token::Token::Underscore | - token::Token::Whitespace | - token::Token::Comment | - token::Token::Eof => {} - - token::Token::BinOp(bin_op_token) | - token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st), - - token::Token::OpenDelim(delim_token) | - token::Token::CloseDelim(delim_token) => delim_token.hash(self.st), - - token::Token::Literal(ref lit, ref opt_name) => { - self.hash_discriminant(lit); - match *lit { - token::Lit::Byte(val) | - token::Lit::Char(val) | - token::Lit::Integer(val) | - token::Lit::Float(val) | - token::Lit::Str_(val) | - token::Lit::ByteStr(val) => val.as_str().hash(self.st), - token::Lit::StrRaw(val, n) | - token::Lit::ByteStrRaw(val, n) => { - val.as_str().hash(self.st); - n.hash(self.st); - } - }; - opt_name.map(ast::Name::as_str).hash(self.st); - } - - token::Token::Ident(ident) | - token::Token::Lifetime(ident) | - token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st), - - token::Token::Interpolated(ref non_terminal) => { - // FIXME(mw): This could be implemented properly. It's just a - // lot of work, since we would need to hash the AST - // in a stable way, in addition to the HIR. - // Since this is hardly used anywhere, just emit a - // warning for now. - if self.tcx.sess.opts.debugging_opts.incremental.is_some() { - let msg = format!("Quasi-quoting might make incremental \ - compilation very inefficient: {:?}", - non_terminal); - self.tcx.sess.span_warn(error_reporting_span, &msg[..]); - } - - non_terminal.hash(self.st); - } - - token::Token::DocComment(val) | - token::Token::Shebang(val) => val.as_str().hash(self.st), - } - } - - pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) { - let hir::Crate { - ref module, - ref attrs, - span, - - // These fields are handled separately: - exported_macros: _, - items: _, - trait_items: _, - impl_items: _, - bodies: _, - trait_impls: _, - trait_default_impl: _, - body_ids: _, - } = *krate; - - visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); - // Crate attributes are not copied over to the root `Mod`, so hash them - // explicitly here. - hash_attrs!(self, attrs); - } -} diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 477777c975db..d10df17f8583 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -22,7 +22,6 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] -#![feature(core_intrinsics)] #![feature(conservative_impl_trait)] #![cfg_attr(stage0, feature(pub_restricted))] diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 8528482c7856..63cfe591ce36 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -32,8 +32,7 @@ use syntax::ast; use {ModuleSource, ModuleTranslation}; -const PARTITION_REUSED: &'static str = "rustc_partition_reused"; -const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; +use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED}; const MODULE: &'static str = "module"; const CFG: &'static str = "cfg"; @@ -62,9 +61,9 @@ struct AssertModuleSource<'a, 'tcx: 'a> { impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { fn check_attr(&self, attr: &ast::Attribute) { - let disposition = if attr.check_name(PARTITION_REUSED) { + let disposition = if attr.check_name(ATTR_PARTITION_REUSED) { Disposition::Reused - } else if attr.check_name(PARTITION_TRANSLATED) { + } else if attr.check_name(ATTR_PARTITION_TRANSLATED) { Disposition::Translated } else { return; diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 587501589314..15111bbba0a9 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -43,6 +43,8 @@ use std::{mem, ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; /// An owned smart pointer. #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct P { @@ -215,3 +217,13 @@ impl Decodable for P<[T]> { })) } } + +impl HashStable for P + where T: ?Sized + HashStable +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(hcx, hasher); + } +} diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs index 195fb23f9d8c..2d9fd7aa8755 100644 --- a/src/libsyntax/util/rc_slice.rs +++ b/src/libsyntax/util/rc_slice.rs @@ -12,6 +12,9 @@ use std::fmt; use std::ops::Deref; use std::rc::Rc; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; + #[derive(Clone)] pub struct RcSlice { data: Rc>, @@ -41,3 +44,13 @@ impl fmt::Debug for RcSlice { fmt::Debug::fmt(self.deref(), f) } } + +impl HashStable for RcSlice + where T: HashStable +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(hcx, hasher); + } +} From edc7f9abec051b3c388f3199c052a0f617a99423 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 27 Mar 2017 21:52:51 +0300 Subject: [PATCH 331/905] Avoid type-checking addition and indexing twice. --- src/librustc_typeck/check/mod.rs | 1 - src/librustc_typeck/check/op.rs | 21 +++++++++++---------- src/test/compile-fail/issue-40610.rs | 16 ++++++++++++++++ src/test/compile-fail/issue-40861.rs | 16 ++++++++++++++++ 4 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/issue-40610.rs create mode 100644 src/test/compile-fail/issue-40861.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aaa3cf0f29e7..c995b7e92843 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3884,7 +3884,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { element_ty } None => { - self.check_expr_has_type(&idx, self.tcx.types.err); let mut err = self.type_error_struct( expr.span, |actual| { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index f492ab12e3f9..cc33bd8754d9 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -184,9 +184,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); - let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], - Symbol::intern(name), trait_def_id, - lhs_expr) { + let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], + Symbol::intern(name), trait_def_id, + lhs_expr); + + // see `NB` above + let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); + + let return_ty = match return_ty { Ok(return_ty) => return_ty, Err(()) => { // error types are considered "builtin" @@ -209,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], + self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty], Symbol::intern(name), trait_def_id, lhs_expr).is_ok() { err.note( @@ -240,7 +245,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(missing_trait) = missing_trait { if missing_trait == "std::ops::Add" && self.check_str_addition(expr, lhs_expr, lhs_ty, - rhs_expr, rhs_ty_var, &mut err) { + rhs_expr, rhs_ty, &mut err) { // This has nothing here because it means we did string // concatenation (e.g. "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted @@ -257,9 +262,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - // see `NB` above - self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - (rhs_ty_var, return_ty) } @@ -268,12 +270,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_expr: &'gcx hir::Expr, - rhs_ty_var: Ty<'tcx>, + rhs_ty: Ty<'tcx>, mut err: &mut errors::DiagnosticBuilder) -> bool { // If this function returns true it means a note was printed, so we don't need // to print the normal "implementation of `std::ops::Add` might be missing" note let mut is_string_addition = false; - let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); if let TyRef(_, l_ty) = lhs_ty.sty { if let TyRef(_, r_ty) = rhs_ty.sty { if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { diff --git a/src/test/compile-fail/issue-40610.rs b/src/test/compile-fail/issue-40610.rs new file mode 100644 index 000000000000..aec20b4ad87b --- /dev/null +++ b/src/test/compile-fail/issue-40610.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 f(_: &[f32]) {} + +fn main() { + () + f(&[1.0]); + //~^ ERROR binary operation `+` cannot be applied to type `()` +} diff --git a/src/test/compile-fail/issue-40861.rs b/src/test/compile-fail/issue-40861.rs new file mode 100644 index 000000000000..e525b3954f5e --- /dev/null +++ b/src/test/compile-fail/issue-40861.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 f(_: &[f32]) {} + +fn main() { + ()[f(&[1.0])]; + //~^ ERROR cannot index a value of type `()` +} From ae0e45c02808551ec27ed940fad9a05cd9bcbaed Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 6 Apr 2017 14:19:45 -0500 Subject: [PATCH 332/905] rustdoc: where clause adjustment to fix tests - add spaces to output so stripping lines and breaking spaces renders the same - add commas to where clauses in rustdoc tests to match the new output --- src/librustdoc/html/format.rs | 11 +++++++---- src/librustdoc/html/render.rs | 4 ++-- src/test/rustdoc/impl-parts.rs | 4 ++-- src/test/rustdoc/issue-20727-4.rs | 4 ++-- src/test/rustdoc/where.rs | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7c1139d7135c..13a31c557021 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -192,9 +192,9 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push_str(" where"); } else { if end_newline { - clause.push_str("where"); + clause.push_str(" where"); } else { - clause.push_str("where"); + clause.push_str(" where"); } } for (i, pred) in gens.where_predicates.iter().enumerate() { @@ -241,8 +241,11 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push_str(""); let padding = repeat(" ").take(indent + 4).collect::(); clause = clause.replace("
    ", &format!("
    {}", padding)); - clause.insert_str(0, &repeat(" ").take(indent).collect::()); - if !end_newline { + clause.insert_str(0, &repeat(" ").take(indent.saturating_sub(1)) + .collect::()); + if end_newline { + clause.push(' '); + } else { clause.insert_str(0, "
    "); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index b1ac6a5127f2..af2beacf58ac 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2710,14 +2710,14 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } write!(w, ")")?; if let Some(g) = g { - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })? + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })? } write!(w, ";")?; } doctree::Unit => { // Needed for PhantomData. if let Some(g) = g { - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })? + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })? } write!(w, ";")?; } diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index 89c5e60e3431..48ef4b6be66d 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -17,7 +17,7 @@ impl AnOibit for .. {} pub struct Foo { field: T } // @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \ -// "impl !AnOibit for Foo where T: Sync" +// "impl !AnOibit for Foo where T: Sync," // @has impl_parts/trait.AnOibit.html '//*[@class="item-list"]//code' \ -// "impl !AnOibit for Foo where T: Sync" +// "impl !AnOibit for Foo where T: Sync," impl !AnOibit for Foo where T: Sync {} diff --git a/src/test/rustdoc/issue-20727-4.rs b/src/test/rustdoc/issue-20727-4.rs index 9ebd1c448eeb..960e40b07098 100644 --- a/src/test/rustdoc/issue-20727-4.rs +++ b/src/test/rustdoc/issue-20727-4.rs @@ -35,7 +35,7 @@ pub trait IndexMut: Index { pub mod reexport { // @has issue_20727_4/reexport/trait.Index.html - // @has - '//*[@class="rust trait"]' 'trait Index where Idx: ?Sized {' + // @has - '//*[@class="rust trait"]' 'trait Index where Idx: ?Sized, {' // @has - '//*[@class="rust trait"]' 'type Output: ?Sized' // @has - '//*[@class="rust trait"]' \ // 'fn index(&self, index: Idx) -> &Self::Output' @@ -43,7 +43,7 @@ pub mod reexport { // @has issue_20727_4/reexport/trait.IndexMut.html // @has - '//*[@class="rust trait"]' \ - // 'trait IndexMut: Index where Idx: ?Sized {' + // 'trait IndexMut: Index where Idx: ?Sized, {' // @has - '//*[@class="rust trait"]' \ // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;' pub use issue_20727::IndexMut; diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index d8dc115abf91..e691f7c5bea0 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -44,5 +44,5 @@ pub enum Foxtrot { Foxtrot1(F) } impl MyTrait for Foxtrot where F: MyTrait {} // @has foo/type.Golf.html '//pre[@class="rust typedef"]' \ -// "type Golf where T: Clone = (T, T)" +// "type Golf where T: Clone, = (T, T)" pub type Golf where T: Clone = (T, T); From c199d253867085dae44f6946d7085a991abe17c8 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 6 Apr 2017 21:59:08 +0200 Subject: [PATCH 333/905] rephrased std::hash::BuildHasherDefault docs Part of #29357. * split summary and explanation more clearly * added link to nomicon for "zero-sized" * "does not need construction" -> say how it can be created, and that it doesn't need to be done with `HashMap` or `HashSet` --- src/libcore/hash/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 756d472eca8d..0d34aeb7cb73 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -285,11 +285,17 @@ pub trait BuildHasher { fn build_hasher(&self) -> Self::Hasher; } -/// The `BuildHasherDefault` structure is used in scenarios where one has a -/// type that implements [`Hasher`] and [`Default`], but needs that type to -/// implement [`BuildHasher`]. +/// Used to create a default [`BuildHasher`] instance for types that implement +/// [`Hasher`] and [`Default`]. /// -/// This structure is zero-sized and does not need construction. +/// `BuildHasherDefault` can be used when a type `H` implements [`Hasher`] and +/// [`Default`], and you need a corresponding [`BuildHasher`] instance, but none is +/// defined. +/// +/// Any `BuildHasherDefault` is [zero-sized]. It can be created with +/// [`default`][method.Default]. When using `BuildHasherDefault` with [`HashMap`] or +/// [`HashSet`], this doesn't need to be done, since they implement appropriate +/// [`Default`] instances themselves. /// /// # Examples /// @@ -322,8 +328,11 @@ pub trait BuildHasher { /// /// [`BuildHasher`]: trait.BuildHasher.html /// [`Default`]: ../default/trait.Default.html +/// [method.default]: #method.default /// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html +/// [`HashSet`]: ../../std/collections/struct.HashSet.html +/// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts #[stable(since = "1.7.0", feature = "build_hasher")] pub struct BuildHasherDefault(marker::PhantomData); From e88a511fd50276b2d88edf9a7a7bbf6a89ca9f68 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 6 Apr 2017 22:32:51 +0200 Subject: [PATCH 334/905] improved std::hash::BuildHasher docs Part of #29357. * split summary and explanation more clearly, while expanding the explanation to make the reason for `BuildHasher` existing more clear * added an example illustrating that `Hasher`s created by one `BuildHasher` should be identical * added links * repeated the fact that hashers produced should be identical in `build_hasher`s method docs --- src/libcore/hash/mod.rs | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 0d34aeb7cb73..b24938b908a6 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -258,12 +258,35 @@ pub trait Hasher { } } -/// A `BuildHasher` is typically used as a factory for instances of `Hasher` -/// which a `HashMap` can then use to hash keys independently. +/// A trait for creating instances of [`Hasher`]. /// -/// Note that for each instance of `BuildHasher`, the created hashers should be -/// identical. That is, if the same stream of bytes is fed into each hasher, the -/// same output will also be generated. +/// A `BuildHasher` is typically used (e.g. by [`HashMap`]) to create +/// [`Hasher`]s for each key such that they are hashed independently of one +/// another, since [`Hasher`]s contain state. +/// +/// For each instance of `BuildHasher`, the [`Hasher`]s created by +/// [`build_hasher`] should be identical. That is, if the same stream of bytes +/// is fed into each hasher, the same output will also be generated. +/// +/// # Examples +/// +/// ``` +/// use std::collections::hash_map::RandomState; +/// use std::hash::{BuildHasher, Hasher}; +/// +/// let s = RandomState::new(); +/// let mut hasher_1 = s.build_hasher(); +/// let mut hasher_2 = s.build_hasher(); +/// +/// hasher_1.write_u32(8128); +/// hasher_2.write_u32(8128); +/// +/// assert_eq!(hasher_1.finish(), hasher_2.finish()); +/// ``` +/// +/// [`build_hasher`]: #method.build_hasher +/// [`Hasher`]: trait.Hasher.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] pub trait BuildHasher { /// Type of the hasher that will be created. @@ -272,6 +295,9 @@ pub trait BuildHasher { /// Creates a new hasher. /// + /// Each call to `build_hasher` on the same instance should produce identical + /// [`Hasher`]s. + /// /// # Examples /// /// ``` @@ -281,6 +307,8 @@ pub trait BuildHasher { /// let s = RandomState::new(); /// let new_s = s.build_hasher(); /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; } From 37275b6fc3635291d19331974e361c1ccd02a467 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 6 Apr 2017 23:39:32 +0200 Subject: [PATCH 335/905] improved std::hash::Hash docs Part of #29357. * merged "Derivable" and "How can I implement `Hash`?" sections into one "Implementing `Hash`" section to aid coherency * added an example for `#[derive(Hash)]` * moved part about relation between `Hash` and `Eq` into a new "`Hash` and `Eq`" section; changed wording to be more consistent with `HashMap` and `HashSet`'s * explicitly mentioned `#[derive(PartialEq, Eq, Hash)]` in the new section * changed method summaries for consistency, adding links and examples --- src/libcore/hash/mod.rs | 83 ++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index b24938b908a6..130a75a7027a 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -107,29 +107,25 @@ mod sip; /// A hashable type. /// -/// The `H` type parameter is an abstract hash state that is used by the `Hash` -/// to compute the hash. +/// Types implementing `Hash` are able to be [`hash`]ed with an instance of +/// [`Hasher`]. /// -/// If you are also implementing [`Eq`], there is an additional property that -/// is important: +/// ## Implementing `Hash` /// -/// ```text -/// k1 == k2 -> hash(k1) == hash(k2) +/// You can derive `Hash` with `#[derive(Hash)]` if all fields implement `Hash`. +/// The resulting hash will be the combination of the values from calling +/// [`hash`] on each field. +/// +/// ``` +/// #[derive(Hash)] +/// struct Rustacean { +/// name: String, +/// country: String, +/// } /// ``` /// -/// In other words, if two keys are equal, their hashes should also be equal. -/// [`HashMap`] and [`HashSet`] both rely on this behavior. -/// -/// ## Derivable -/// -/// This trait can be used with `#[derive]` if all fields implement `Hash`. -/// When `derive`d, the resulting hash will be the combination of the values -/// from calling [`.hash`] on each field. -/// -/// ## How can I implement `Hash`? -/// -/// If you need more control over how a value is hashed, you need to implement -/// the `Hash` trait: +/// If you need more control over how a value is hash, you can of course +/// implement the `Hash` trait yourself: /// /// ``` /// use std::hash::{Hash, Hasher}; @@ -148,17 +144,60 @@ mod sip; /// } /// ``` /// +/// ## `Hash` and `Eq` +/// +/// When implementing both `Hash` and [`Eq`], it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must also be equal. +/// [`HashMap`] and [`HashSet`] both rely on this behavior. +/// +/// Thankfully, you won't need to worry about upholding this property when +/// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. +/// /// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html -/// [`.hash`]: #tymethod.hash +/// [`hash`]: #tymethod.hash #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { - /// Feeds this value into the state given, updating the hasher as necessary. + /// Feeds this value into the given [`Hasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::{Hash, Hasher}; + /// + /// let mut hasher = DefaultHasher::new(); + /// 7920.hash(&mut hasher); + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(feature = "rust1", since = "1.0.0")] fn hash(&self, state: &mut H); - /// Feeds a slice of this type into the state provided. + /// Feeds a slice of this type into the given [`Hasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::{Hash, Hasher}; + /// + /// let mut hasher = DefaultHasher::new(); + /// let numbers = [6, 28, 496, 8128]; + /// Hash::hash_slice(&numbers, &mut hasher); + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(feature = "hash_slice", since = "1.3.0")] fn hash_slice(data: &[Self], state: &mut H) where Self: Sized From 9ffb54568c1d52bfee0162dd75b2c415cbf6fce4 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Thu, 6 Apr 2017 14:43:37 -0400 Subject: [PATCH 336/905] Remove some CStr transmutes. --- src/libstd/ffi/c_str.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2d14bb66bf4f..fc1b9a976322 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -356,7 +356,7 @@ impl ops::Deref for CString { type Target = CStr; fn deref(&self) -> &CStr { - unsafe { mem::transmute(self.as_bytes_with_nul()) } + unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } } } @@ -583,7 +583,8 @@ impl CStr { #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { let len = libc::strlen(ptr); - mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) + let ptr = ptr as *const u8; + CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) } /// Creates a C string wrapper from a byte slice. From 0dce5862fcb8677f416e0bf1eb75b8e53108c70c Mon Sep 17 00:00:00 2001 From: lukaramu Date: Fri, 7 Apr 2017 00:39:27 +0200 Subject: [PATCH 337/905] improved std::hash::Hasher docs Part of #29357. * rephrased summary sentences to be less redundant * expanded top-level docs, adding a usage example and links to relevant methods (`finish`, `write` etc) as well as `Hash` * added examples to the `finish` and `write` methods --- src/libcore/hash/mod.rs | 59 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 130a75a7027a..4ebec401669c 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -208,18 +208,73 @@ pub trait Hash { } } -/// A trait which represents the ability to hash an arbitrary stream of bytes. +/// A trait for hashing an arbitrary stream of bytes. +/// +/// Instances of `Hasher` usually represent state that is changed while hashing +/// data. +/// +/// `Hasher` provides a fairly basic interface for retrieving the generated hash +/// (with [`finish`]), and writing integers as well as slices of bytes into an +/// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher` +/// instances are used in conjunction with the [`Hash`] trait. +/// +/// # Examples +/// +/// ``` +/// use std::collections::hash_map::DefaultHasher; +/// use std::hash::Hasher; +/// +/// let mut hasher = DefaultHasher::new(); +/// +/// hasher.write_u32(1989); +/// hasher.write_u8(11); +/// hasher.write_u8(9); +/// hasher.write(b"Huh?"); +/// +/// println!("Hash is {:x}!", hasher.finish()); +/// ``` +/// +/// [`Hash`]: trait.Hash.html +/// [`finish`]: #tymethod.finish +/// [`write`]: #tymethod.write +/// [`write_u8`]: #method.write_u8 #[stable(feature = "rust1", since = "1.0.0")] pub trait Hasher { /// Completes a round of hashing, producing the output hash generated. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::Hasher; + /// + /// let mut hasher = DefaultHasher::new(); + /// hasher.write(b"Cool!"); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn finish(&self) -> u64; /// Writes some data into this `Hasher`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::Hasher; + /// + /// let mut hasher = DefaultHasher::new(); + /// let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; + /// + /// hasher.write(&data); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, bytes: &[u8]); - /// Write a single `u8` into this hasher. + /// Writes a single `u8` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u8(&mut self, i: u8) { From f4f79c3304602701b0a48e3ab77bc87903440e82 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 18:32:39 -0500 Subject: [PATCH 338/905] ignore the .init_array doctest as it's specific to ELF and won't pass on macOS / Windows --- src/doc/unstable-book/src/used.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md index cdda24acd708..75a8b2774f42 100644 --- a/src/doc/unstable-book/src/used.md +++ b/src/doc/unstable-book/src/used.md @@ -55,7 +55,7 @@ The ELF standard defines two special sections, `.init_array` and in these sections (at least when linking programs that target the `*-*-linux-*` targets). -``` rust +``` rust,ignore #![feature(used)] extern "C" fn before_main() { From bfd01b7f40ae2cbfe9acbc1d10e79ffe16870df8 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 6 Apr 2017 18:36:14 -0500 Subject: [PATCH 339/905] rustdoc: move the space at the end of where clauses ...so that we don't indent the next line by one extra space --- src/librustdoc/html/format.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 13a31c557021..d9bbc957c8a2 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -237,15 +237,23 @@ impl<'a> fmt::Display for WhereClause<'a> { clause.push(','); } } + + if end_newline { + //add a space so stripping
    tags and breaking spaces still renders properly + if f.alternate() { + clause.push(' '); + } else { + clause.push_str(" "); + } + } + if !f.alternate() { clause.push_str("
    "); let padding = repeat(" ").take(indent + 4).collect::(); clause = clause.replace("
    ", &format!("
    {}", padding)); clause.insert_str(0, &repeat(" ").take(indent.saturating_sub(1)) .collect::()); - if end_newline { - clause.push(' '); - } else { + if !end_newline { clause.insert_str(0, "
    "); } } From 8a1d2a3a5a4ec0288c72a1b68864c8ac8a3074e4 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 6 Apr 2017 14:53:15 -0400 Subject: [PATCH 340/905] rustdoc: collapse docblock before showing label --- src/librustdoc/html/static/main.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 200285862276..cf9408abf5e8 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -951,14 +951,21 @@ if (relatedDoc.is(".docblock")) { if (relatedDoc.is(":visible")) { if (animate === true) { - relatedDoc.slideUp({duration: 'fast', easing: 'linear'}); - toggle.children(".toggle-label").fadeIn(); + relatedDoc.slideUp({ + duration: 'fast', + easing: 'linear', + complete: function() { + toggle.children(".toggle-label").fadeIn(); + toggle.parent(".toggle-wrapper").addClass("collapsed"); + toggle.children(".inner").text(labelForToggleButton(true)); + }, + }); } else { relatedDoc.hide(); toggle.children(".toggle-label").show(); + toggle.parent(".toggle-wrapper").addClass("collapsed"); + toggle.children(".inner").text(labelForToggleButton(true)); } - toggle.parent(".toggle-wrapper").addClass("collapsed"); - toggle.children(".inner").text(labelForToggleButton(true)); } else { relatedDoc.slideDown({duration: 'fast', easing: 'linear'}); toggle.parent(".toggle-wrapper").removeClass("collapsed"); From c9932b395ada3c367aea5e79645c10657262ea6f Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Fri, 7 Apr 2017 12:20:37 +0900 Subject: [PATCH 341/905] Changes based on PR feedback --- src/librustc_mir/transform/qualify_consts.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index cdbc0bd8858a..8eabe92fb98c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -603,7 +603,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Rvalue::Cast(CastKind::ReifyFnPointer, ..) | Rvalue::Cast(CastKind::UnsafeFnPointer, ..) | Rvalue::Cast(CastKind::ClosureFnPointer, ..) | - Rvalue::Cast(CastKind::Unsize, ..) => {} + Rvalue::Cast(CastKind::Unsize, ..) | + Rvalue::Discriminant(..) => {} Rvalue::Len(_) => { // Static lvalues in consts would have errored already, @@ -721,12 +722,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - Rvalue::Discriminant(..) => { - // FIXME implement discriminant const qualify - self.add(Qualif::NOT_CONST); - // Discriminants in consts will error elsewhere as an unimplemented expression type - } - Rvalue::Box(_) => { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { From 5202ac57531ca42d26a778d99165f22db3c61632 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Thu, 6 Apr 2017 23:29:16 -0400 Subject: [PATCH 342/905] Correct book examples for hardware re-ordering --- .../unstable-book/src/compiler-barriers.md | 116 ++++++++++-------- 1 file changed, 62 insertions(+), 54 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 5a5c539609c7..3108494aa79f 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -21,78 +21,86 @@ A `compiler_barrier` restricts the kinds of memory re-ordering the compiler is allowed to do. Specifically, depending on the given ordering semantics, the compiler may be disallowed from moving reads or writes from before or after the call to the other side of the call to -`compiler_barrier`. +`compiler_barrier`. Note that it does **not** prevent the *hardware* +from doing such re-orderings -- for that, the `volatile_*` class of +functions, or full memory fences, need to be used. ## Examples -The need to prevent re-ordering of reads and writes often arises when -working with low-level devices. Consider a piece of code that interacts -with an ethernet card with a set of internal registers that are accessed -through an address port register (`a: &mut usize`) and a data port -register (`d: &usize`). To read internal register 5, the following code -might then be used: +`compiler_barrier` is generally only useful for preventing a thread from +racing *with itself*. That is, if a given thread is executing one piece +of code, and is then interrupted, and starts executing code elsewhere +(while still in the same thread, and conceptually still on the same +core). In traditional programs, this can only occur when a signal +handler is registered. Consider the following code: ```rust -fn read_fifth(a: &mut usize, d: &usize) -> usize { - *a = 5; - *d +#use std::sync::atomic::{AtomicBool, AtomicUsize}; +#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +#use std::sync::atomic::Ordering; +static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; +static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; + +fn main() { + IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); + IS_READY.store(true, Ordering::Relaxed); +} + +fn signal_handler() { + if IS_READY.load(Ordering::Relaxed) { + assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42); + } } ``` -In this case, the compiler is free to re-order these two statements if -it thinks doing so might result in better performance, register use, or -anything else compilers care about. However, in doing so, it would break -the code, as `x` would be set to the value of some other device -register! +The way it is currently written, the `assert_eq!` is *not* guaranteed to +succeed, despite everything happening in a single thread. To see why, +remember that the compiler is free to swap the stores to +`IMPORTANT_VARIABLE` and `IS_READ` since they are both +`Ordering::Relaxed`. If it does, and the signal handler is invoked right +after `IS_READY` is updated, then the signal handler will see +`IS_READY=1`, but `IMPORTANT_VARIABLE=0`. -By inserting a compiler barrier, we can force the compiler to not -re-arrange these two statements, making the code function correctly -again: +Using a `compiler_barrier`, we can remedy this situation: ```rust #![feature(compiler_barriers)] -use std::sync::atomic; +#use std::sync::atomic::{AtomicBool, AtomicUsize}; +#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +#use std::sync::atomic::Ordering; +use std::sync::atomic::compiler_barrier; -fn read_fifth(a: &mut usize, d: &usize) -> usize { - *a = 5; - atomic::compiler_barrier(atomic::Ordering::SeqCst); - *d +static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; +static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; + +fn main() { + IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); + // prevent earlier writes from being moved beyond this point + compiler_barrier(Ordering::Release); + IS_READY.store(true, Ordering::Relaxed); +} + +fn signal_handler() { + if IS_READY.load(Ordering::Relaxed) { + assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42); + } } ``` -Compiler barriers are also useful in code that implements low-level -synchronization primitives. Consider a structure with two different -atomic variables, with a dependency chain between them: +In more advanced cases (for example, if `IMPORTANT_VARIABLE` was an +`AtomicPtr` that starts as `NULL`), it may also be unsafe for the +compiler to hoist code using `IMPORTANT_VARIABLE` above the +`IS_READY.load`. In that case, a `compiler_barrier(Ordering::Acquire)` +should be placed at the top of the `if` to prevent this optimizations. -```rust -use std::sync::atomic; - -fn thread1(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { - x.store(1, atomic::Ordering::Release); - let v1 = y.load(atomic::Ordering::Acquire); -} -fn thread2(x: &atomic::AtomicUsize, y: &atomic::AtomicUsize) { - y.store(1, atomic::Ordering::Release); - let v2 = x.load(atomic::Ordering::Acquire); -} -``` - -This code will guarantee that `thread1` sees any writes to `y` made by -`thread2`, and that `thread2` sees any writes to `x`. Intuitively, one -might also expect that if `thread2` sees `v2 == 0`, `thread1` must see -`v1 == 1` (since `thread2`'s store happened before its `load`, and its -load did not see `thread1`'s store). However, the code as written does -*not* guarantee this, because the compiler is allowed to re-order the -store and load within each thread. To enforce this particular behavior, -a call to `compiler_barrier(Ordering::SeqCst)` would need to be inserted -between the `store` and `load` in both functions. - -Compiler barriers with weaker re-ordering semantics (such as -`Ordering::Acquire`) can also be useful, but are beyond the scope of -this text. Curious readers are encouraged to read the Linux kernel's -discussion of [memory barriers][1], as well as C++ references on -[`std::memory_order`][2] and [`atomic_signal_fence`][3]. +A deeper discussion of compiler barriers with various re-ordering +semantics (such as `Ordering::SeqCst`) is beyond the scope of this text. +Curious readers are encouraged to read the Linux kernel's discussion of +[memory barriers][1], the C++ references on [`std::memory_order`][2] and +[`atomic_signal_fence`][3], and [this StackOverflow answer][4] for +further details. [1]: https://www.kernel.org/doc/Documentation/memory-barriers.txt [2]: http://en.cppreference.com/w/cpp/atomic/memory_order [3]: http://www.cplusplus.com/reference/atomic/atomic_signal_fence/ +[4]: http://stackoverflow.com/a/18454971/472927 From 98037ca43d4d96f93e73e1eb3df8e64372d8f929 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 23:53:32 -0500 Subject: [PATCH 343/905] don't pass -C to nm the nm in our macOS bots don't support that flag and it's not really required --- src/test/run-make/used/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile index 5fe09e95a828..9d7aa30f8748 100644 --- a/src/test/run-make/used/Makefile +++ b/src/test/run-make/used/Makefile @@ -7,5 +7,5 @@ all: else all: $(RUSTC) -C opt-level=3 --emit=obj used.rs - nm -C $(TMPDIR)/used.o | grep FOO + nm $(TMPDIR)/used.o | grep FOO endif From f45c6d8fc7097b5186ece9c43c3237d1c58e8dd4 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 01:05:03 -0500 Subject: [PATCH 344/905] document some existing unstable features "msp430-interrupt", "ptx-kernel" and #![compiler_builtins_lib] --- .../unstable-book/src/abi-msp430-interrupt.md | 35 ++++++++++++ src/doc/unstable-book/src/abi-ptx.md | 56 ++++++++++++++++++- .../src/compiler-builtins-lib.md | 32 ++++++++++- .../unstable-book/src/compiler-builtins.md | 3 +- 4 files changed, 122 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/abi-msp430-interrupt.md b/src/doc/unstable-book/src/abi-msp430-interrupt.md index 9b2c7f298979..b10bc41cb143 100644 --- a/src/doc/unstable-book/src/abi-msp430-interrupt.md +++ b/src/doc/unstable-book/src/abi-msp430-interrupt.md @@ -5,3 +5,38 @@ The tracking issue for this feature is: [#38487] [#38487]: https://github.com/rust-lang/rust/issues/38487 ------------------------ + +In the MSP430 architecture, interrupt handlers have a special calling +convention. You can use the `"msp430-interrupt"` ABI to make the compiler apply +the right calling convention to the interrupt handlers you define. + + + +``` rust,ignore +#![feature(abi_msp430_interrupt)] +#![no_std] + +// Place the interrupt handler at the appropriate memory address +// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`) +#[link_section = "__interrupt_vector_10"] +#[no_mangle] +pub static TIM0_VECTOR: extern "msp430-interrupt" fn() = tim0; + +// The interrupt handler +extern "msp430-interrupt" fn tim0() { + // .. +} +``` + +``` text +$ msp430-elf-objdump -CD ./target/msp430/release/app +Disassembly of section __interrupt_vector_10: + +0000fff2 : + fff2: 00 c0 interrupt service routine at 0xc000 + +Disassembly of section .text: + +0000c000 : + c000: 00 13 reti +``` diff --git a/src/doc/unstable-book/src/abi-ptx.md b/src/doc/unstable-book/src/abi-ptx.md index 9c1b8868aceb..89b2a199279b 100644 --- a/src/doc/unstable-book/src/abi-ptx.md +++ b/src/doc/unstable-book/src/abi-ptx.md @@ -1,5 +1,59 @@ # `abi_ptx` -The tracking issue for this feature is: None. +The tracking issue for this feature +is: [38788](https://github.com/rust-lang/rust/issues/38788) ------------------------ + +When emitting PTX code, all vanilla Rust functions (`fn`) get translated to +"device" functions. These functions are *not* callable from the host via the +CUDA API so a crate with only device functions is not too useful! + +OTOH, "global" functions *can* be called by the host; you can think of them +as the real public API of your crate. To produce a global function use the +`"ptx-kernel"` ABI. + + + +``` rust,ignore +#![feature(abi_ptx)] +#![no_std] + +pub unsafe extern "ptx-kernel" fn global_function() { + device_function(); +} + +pub fn device_function() { + // .. +} +``` + +``` text +$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm + +$ cat $(find -name '*.s') +// +// Generated by LLVM NVPTX Back-End +// + +.version 3.2 +.target sm_20 +.address_size 64 + + // .globl _ZN6kernel15global_function17h46111ebe6516b382E + +.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E() +{ + + + ret; +} + + // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E +.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E() +{ + + + ret; +} +``` diff --git a/src/doc/unstable-book/src/compiler-builtins-lib.md b/src/doc/unstable-book/src/compiler-builtins-lib.md index 8986b968ca6c..5da8968fd0ce 100644 --- a/src/doc/unstable-book/src/compiler-builtins-lib.md +++ b/src/doc/unstable-book/src/compiler-builtins-lib.md @@ -1,5 +1,35 @@ # `compiler_builtins_lib` -This feature is internal to the Rust compiler and is not intended for general use. +The tracking issue for this feature is: None. ------------------------ + +This feature is required to link to the `compiler_builtins` crate which contains +"compiler intrinsics". Compiler intrinsics are software implementations of basic +operations like multiplication of `u64`s. These intrinsics are only required on +platforms where these operations don't directly map to a hardware instruction. + +You should never need to explicitly link to the `compiler_builtins` crate when +building "std" programs as `compiler_builtins` is already in the dependency +graph of `std`. But you may need it when building `no_std` **binary** crates. If +you get a *linker* error like: + +``` text +$PWD/src/main.rs:11: undefined reference to `__aeabi_lmul' +$PWD/src/main.rs:11: undefined reference to `__aeabi_uldivmod' +``` + +That means that you need to link to this crate. + +When you link to this crate, make sure it only appears once in your crate +dependency graph. Also, it doesn't matter where in the dependency graph, you +place the `compiler_builtins` crate. + + + +``` rust,ignore +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; +``` diff --git a/src/doc/unstable-book/src/compiler-builtins.md b/src/doc/unstable-book/src/compiler-builtins.md index 3ec3cba257a9..52fac575b6e8 100644 --- a/src/doc/unstable-book/src/compiler-builtins.md +++ b/src/doc/unstable-book/src/compiler-builtins.md @@ -1,6 +1,5 @@ # `compiler_builtins` -The tracking issue for this feature is: None. +This feature is internal to the Rust compiler and is not intended for general use. ------------------------ - From b135c1291d8cc186647092765c5d94955a311410 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Thu, 6 Apr 2017 18:49:41 -0700 Subject: [PATCH 345/905] travis: Use upstream LLVM repositories for Fuchsia The Fuchsia copies of LLVM repositories contain additional patches for work-in-progress features and there is some amount of churn that may break Rust. Use upstream LLVM repositories instead for building the toolchain used by the Fuchsia builder. --- src/ci/docker/dist-fuchsia/Dockerfile | 5 ++- src/ci/docker/dist-fuchsia/build-toolchain.sh | 30 +++++++++----- .../dist-fuchsia/compiler-rt-dso-handle.patch | 41 +++++++++++++++++++ 3 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index ed37a9e842e2..0fd55b585a52 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -14,13 +14,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ swig \ libedit-dev \ - libncurses5-dev + libncurses5-dev \ + patch RUN curl -L https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.tar.gz | \ tar xzf - -C /usr/local --strip-components=1 WORKDIR /tmp -COPY shared.sh build-toolchain.sh /tmp/ +COPY shared.sh build-toolchain.sh compiler-rt-dso-handle.patch /tmp/ RUN /tmp/build-toolchain.sh RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-fuchsia/build-toolchain.sh b/src/ci/docker/dist-fuchsia/build-toolchain.sh index cad73eee1e01..10b285a54665 100755 --- a/src/ci/docker/dist-fuchsia/build-toolchain.sh +++ b/src/ci/docker/dist-fuchsia/build-toolchain.sh @@ -9,26 +9,31 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +# ignore-tidy-linelength + set -ex source shared.sh # Download sources SRCS=( - "https://fuchsia.googlesource.com/magenta magenta ac69119" - "https://fuchsia.googlesource.com/third_party/llvm llvm 5463083" - "https://fuchsia.googlesource.com/third_party/clang llvm/tools/clang 4ff7b4b" - "https://fuchsia.googlesource.com/third_party/lld llvm/tools/lld fd465a3" - "https://fuchsia.googlesource.com/third_party/lldb llvm/tools/lldb 6bb11f8" - "https://fuchsia.googlesource.com/third_party/compiler-rt llvm/runtimes/compiler-rt 52d4ecc" - "https://fuchsia.googlesource.com/third_party/libcxx llvm/runtimes/libcxx e891cc8" - "https://fuchsia.googlesource.com/third_party/libcxxabi llvm/runtimes/libcxxabi f0f0257" - "https://fuchsia.googlesource.com/third_party/libunwind llvm/runtimes/libunwind 50bddc1" + "https://fuchsia.googlesource.com/magenta magenta d17073dc8de344ead3b65e8cc6a12280dec38c84" + "https://llvm.googlesource.com/llvm llvm 3f58a16d8eec385e2b3ebdfbb84ff9d3bf27e025" + "https://llvm.googlesource.com/clang llvm/tools/clang 727ea63e6e82677f6e10e05e08bc7d6bdbae3111" + "https://llvm.googlesource.com/lld llvm/tools/lld a31286c1366e5e89b8872803fded13805a1a084b" + "https://llvm.googlesource.com/lldb llvm/tools/lldb 0b2384abec4cb99ad66687712e07dee4dd9d187e" + "https://llvm.googlesource.com/compiler-rt llvm/runtimes/compiler-rt 9093a35c599fe41278606a20b51095ea8bd5a081" + "https://llvm.googlesource.com/libcxx llvm/runtimes/libcxx 607e0c71ec4f7fd377ad3f6c47b08dbe89f66eaa" + "https://llvm.googlesource.com/libcxxabi llvm/runtimes/libcxxabi 0a3a1a8a5ca5ef69e0f6b7d5b9d13e63e6fd2c19" + "https://llvm.googlesource.com/libunwind llvm/runtimes/libunwind e128003563d99d9ee62247c4cee40f07d21c03e3" ) fetch() { mkdir -p $2 pushd $2 > /dev/null - curl -sL $1/+archive/$3.tar.gz | tar xzf - + git init + git remote add origin $1 + git fetch --depth=1 origin $3 + git reset --hard FETCH_HEAD popd > /dev/null } @@ -36,6 +41,11 @@ for i in "${SRCS[@]}"; do fetch $i done +# Remove this once https://reviews.llvm.org/D28791 is resolved +cd llvm/runtimes/compiler-rt +patch -Np1 < /tmp/compiler-rt-dso-handle.patch +cd ../../.. + # Build toolchain cd llvm mkdir build diff --git a/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch b/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch new file mode 100644 index 000000000000..0b702894bb21 --- /dev/null +++ b/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch @@ -0,0 +1,41 @@ +diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt +index fc4384af2..b442264c0 100644 +--- a/lib/builtins/CMakeLists.txt ++++ b/lib/builtins/CMakeLists.txt +@@ -194,6 +194,12 @@ if(APPLE) + atomic_thread_fence.c) + endif() + ++if(FUCHSIA) ++ set(GENERIC_SOURCES ++ ${GENERIC_SOURCES} ++ dso_handle.c) ++endif() ++ + if(NOT WIN32 OR MINGW) + set(GENERIC_SOURCES + ${GENERIC_SOURCES} +diff --git a/lib/builtins/dso_handle.c b/lib/builtins/dso_handle.c +new file mode 100644 +index 000000000..7766cd0aa +--- /dev/null ++++ b/lib/builtins/dso_handle.c +@@ -0,0 +1,18 @@ ++/* ===-- dso_handle.c - Provide __dso_handle -------------------------------=== ++ * ++ * The LLVM Compiler Infrastructure ++ * ++ * This file is dual licensed under the MIT and the University of Illinois Open ++ * Source Licenses. See LICENSE.TXT for details. ++ * ++ * ===----------------------------------------------------------------------=== ++ */ ++ ++/* __dso_handle symbol is mandated by C++ ABI with a value which is an address ++ * in one of the object's segments, and as such this symbol has to be included ++ * statically and cannot be a part of a shared library. Traditionally, it has ++ * been defined in crtbegin.o but there's no principled reason for it to be ++ * there. We defined this symbol in the builtin library which is built as a ++ * static library and always included in the final link. ++ */ ++__attribute__((visibility("hidden"))) void *const __dso_handle; From edc1ac3016d0e8383e174312db7c3b7a885af0c3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 3 Apr 2017 19:20:26 +0200 Subject: [PATCH 346/905] ICH: Centrally compute and cache DefPath hashes as part of DefPathTable. --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/map/def_collector.rs | 19 +-- src/librustc/hir/map/definitions.rs | 115 ++++++++++++++---- src/librustc/ich/def_path_hash.rs | 36 ------ src/librustc/ich/hcx.rs | 6 +- src/librustc/ich/mod.rs | 2 - src/librustc/middle/cstore.rs | 4 + src/librustc/ty/mod.rs | 9 ++ src/librustc/ty/util.rs | 14 +-- src/librustc_driver/driver.rs | 8 +- src/librustc_incremental/persist/directory.rs | 4 - src/librustc_incremental/persist/save.rs | 13 +- src/librustc_metadata/cstore_impl.rs | 6 +- src/librustc_metadata/decoder.rs | 13 +- src/librustc_resolve/lib.rs | 4 +- src/librustc_trans/back/symbol_names.rs | 25 ++-- src/librustc_typeck/collect.rs | 2 +- 17 files changed, 152 insertions(+), 130 deletions(-) delete mode 100644 src/librustc/ich/def_path_hash.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 17185a6ab69f..3f4390536b04 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2697,7 +2697,7 @@ impl<'a> LoweringContext<'a> { fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode) -> P { let id = self.next_id(); - let parent_def = self.parent_def; + let parent_def = self.parent_def.unwrap(); let def_id = { let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name.as_str()); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index afdb9059ea7c..c1417f718b27 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -40,11 +40,9 @@ impl<'a> DefCollector<'a> { } } - pub fn collect_root(&mut self) { - let root = self.create_def_with_parent(None, - CRATE_NODE_ID, - DefPathData::CrateRoot, - ITEM_LIKE_SPACE); + pub fn collect_root(&mut self, crate_name: &str, crate_disambiguator: &str) { + let root = self.definitions.create_root_def(crate_name, + crate_disambiguator); assert_eq!(root, CRATE_DEF_INDEX); self.parent_def = Some(root); } @@ -54,20 +52,11 @@ impl<'a> DefCollector<'a> { data: DefPathData, address_space: DefIndexAddressSpace) -> DefIndex { - let parent_def = self.parent_def; + let parent_def = self.parent_def.unwrap(); debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); self.definitions.create_def_with_parent(parent_def, node_id, data, address_space) } - fn create_def_with_parent(&mut self, - parent: Option, - node_id: NodeId, - data: DefPathData, - address_space: DefIndexAddressSpace) - -> DefIndex { - self.definitions.create_def_with_parent(parent, node_id, data, address_space) - } - pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { let parent = self.parent_def; self.parent_def = Some(parent_def); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index dca9ebb3397a..6118df2ddfc8 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -21,7 +21,7 @@ use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::fmt::Write; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use syntax::ast; use syntax::symbol::{Symbol, InternedString}; use ty::TyCtxt; @@ -34,6 +34,7 @@ use util::nodemap::NodeMap; pub struct DefPathTable { index_to_key: [Vec; 2], key_to_index: FxHashMap, + def_path_hashes: [Vec; 2], } // Unfortunately we have to provide a manual impl of Clone because of the @@ -44,6 +45,8 @@ impl Clone for DefPathTable { index_to_key: [self.index_to_key[0].clone(), self.index_to_key[1].clone()], key_to_index: self.key_to_index.clone(), + def_path_hashes: [self.def_path_hashes[0].clone(), + self.def_path_hashes[1].clone()], } } } @@ -52,6 +55,7 @@ impl DefPathTable { fn allocate(&mut self, key: DefKey, + def_path_hash: u64, address_space: DefIndexAddressSpace) -> DefIndex { let index = { @@ -62,6 +66,9 @@ impl DefPathTable { index }; self.key_to_index.insert(key, index); + self.def_path_hashes[address_space.index()].push(def_path_hash); + debug_assert!(self.def_path_hashes[address_space.index()].len() == + self.index_to_key[address_space.index()].len()); index } @@ -71,6 +78,12 @@ impl DefPathTable { [index.as_array_index()].clone() } + #[inline(always)] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.def_path_hashes[index.address_space().index()] + [index.as_array_index()] + } + #[inline(always)] pub fn def_index_for_def_key(&self, key: &DefKey) -> Option { self.key_to_index.get(key).cloned() @@ -116,17 +129,28 @@ impl DefPathTable { impl Encodable for DefPathTable { fn encode(&self, s: &mut S) -> Result<(), S::Error> { + // Index to key self.index_to_key[DefIndexAddressSpace::Low.index()].encode(s)?; - self.index_to_key[DefIndexAddressSpace::High.index()].encode(s) + self.index_to_key[DefIndexAddressSpace::High.index()].encode(s)?; + + // DefPath hashes + self.def_path_hashes[DefIndexAddressSpace::Low.index()].encode(s)?; + self.def_path_hashes[DefIndexAddressSpace::High.index()].encode(s)?; + + Ok(()) } } impl Decodable for DefPathTable { fn decode(d: &mut D) -> Result { let index_to_key_lo: Vec = Decodable::decode(d)?; - let index_to_key_high: Vec = Decodable::decode(d)?; + let index_to_key_hi: Vec = Decodable::decode(d)?; - let index_to_key = [index_to_key_lo, index_to_key_high]; + let def_path_hashes_lo: Vec = Decodable::decode(d)?; + let def_path_hashes_hi: Vec = Decodable::decode(d)?; + + let index_to_key = [index_to_key_lo, index_to_key_hi]; + let def_path_hashes = [def_path_hashes_lo, def_path_hashes_hi]; let mut key_to_index = FxHashMap(); @@ -141,6 +165,7 @@ impl Decodable for DefPathTable { Ok(DefPathTable { index_to_key: index_to_key, key_to_index: key_to_index, + def_path_hashes: def_path_hashes, }) } } @@ -184,6 +209,29 @@ pub struct DefKey { pub disambiguated_data: DisambiguatedDefPathData, } +impl DefKey { + fn compute_stable_hash(&self, parent_hash: u64) -> u64 { + let mut hasher = StableHasher::new(); + + // We hash a 0u8 here to disambiguate between regular DefPath hashes, + // and the special "root_parent" below. + 0u8.hash(&mut hasher); + parent_hash.hash(&mut hasher); + self.disambiguated_data.hash(&mut hasher); + hasher.finish() + } + + fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> u64 { + let mut hasher = StableHasher::new(); + // Disambiguate this from a regular DefPath hash, + // see compute_stable_hash() above. + 1u8.hash(&mut hasher); + crate_name.hash(&mut hasher); + crate_disambiguator.hash(&mut hasher); + hasher.finish() + } +} + /// Pair of `DefPathData` and an integer disambiguator. The integer is /// normally 0, but in the event that there are multiple defs with the /// same `parent` and `data`, we use this field to disambiguate @@ -271,19 +319,6 @@ impl DefPath { s } - - pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 { - debug!("deterministic_hash({:?})", self); - let mut state = StableHasher::new(); - self.deterministic_hash_to(tcx, &mut state); - state.finish() - } - - pub fn deterministic_hash_to(&self, tcx: TyCtxt, state: &mut H) { - tcx.original_crate_name(self.krate).as_str().hash(state); - tcx.crate_disambiguator(self.krate).as_str().hash(state); - self.data.hash(state); - } } #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -338,6 +373,7 @@ impl Definitions { table: DefPathTable { index_to_key: [vec![], vec![]], key_to_index: FxHashMap(), + def_path_hashes: [vec![], vec![]], }, node_to_def_index: NodeMap(), def_index_to_node: [vec![], vec![]], @@ -359,6 +395,11 @@ impl Definitions { self.table.def_key(index) } + #[inline(always)] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.table.def_path_hash(index) + } + pub fn def_index_for_def_key(&self, key: DefKey) -> Option { self.table.def_index_for_def_key(&key) } @@ -398,12 +439,38 @@ impl Definitions { self.node_to_hir_id[node_id] } + /// Add a definition with a parent definition. + pub fn create_root_def(&mut self, + crate_name: &str, + crate_disambiguator: &str) + -> DefIndex { + let key = DefKey { + parent: None, + disambiguated_data: DisambiguatedDefPathData { + data: DefPathData::CrateRoot, + disambiguator: 0 + } + }; + + let parent_hash = DefKey::root_parent_stable_hash(crate_name, + crate_disambiguator); + let def_path_hash = key.compute_stable_hash(parent_hash); + + // Create the definition. + let address_space = super::ITEM_LIKE_SPACE; + let index = self.table.allocate(key, def_path_hash, address_space); + assert!(self.def_index_to_node[address_space.index()].is_empty()); + self.def_index_to_node[address_space.index()].push(ast::CRATE_NODE_ID); + self.node_to_def_index.insert(ast::CRATE_NODE_ID, index); + + index + } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, - parent: Option, + parent: DefIndex, node_id: ast::NodeId, data: DefPathData, - // is_owner: bool) address_space: DefIndexAddressSpace) -> DefIndex { debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})", @@ -415,12 +482,13 @@ impl Definitions { data, self.table.def_key(self.node_to_def_index[&node_id])); - assert_eq!(parent.is_some(), data != DefPathData::CrateRoot); + // The root node must be created with create_root_def() + assert!(data != DefPathData::CrateRoot); // Find a unique DefKey. This basically means incrementing the disambiguator // until we get no match. let mut key = DefKey { - parent: parent, + parent: Some(parent), disambiguated_data: DisambiguatedDefPathData { data: data, disambiguator: 0 @@ -431,10 +499,13 @@ impl Definitions { key.disambiguated_data.disambiguator += 1; } + let parent_hash = self.table.def_path_hash(parent); + let def_path_hash = key.compute_stable_hash(parent_hash); + debug!("create_def_with_parent: after disambiguation, key = {:?}", key); // Create the definition. - let index = self.table.allocate(key, address_space); + let index = self.table.allocate(key, def_path_hash, address_space); assert_eq!(index.as_array_index(), self.def_index_to_node[address_space.index()].len()); self.def_index_to_node[address_space.index()].push(node_id); diff --git a/src/librustc/ich/def_path_hash.rs b/src/librustc/ich/def_path_hash.rs deleted file mode 100644 index 03051dc00342..000000000000 --- a/src/librustc/ich/def_path_hash.rs +++ /dev/null @@ -1,36 +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 hir::def_id::DefId; -use ty::TyCtxt; -use util::nodemap::DefIdMap; - -pub struct DefPathHashes<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - data: DefIdMap, -} - -impl<'a, 'tcx> DefPathHashes<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - DefPathHashes { - tcx: tcx, - data: DefIdMap() - } - } - - pub fn hash(&mut self, def_id: DefId) -> u64 { - let tcx = self.tcx; - *self.data.entry(def_id) - .or_insert_with(|| { - let def_path = tcx.def_path(def_id); - def_path.deterministic_hash(tcx) - }) - } -} diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 73d81212cd77..5ef30550f115 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -10,7 +10,7 @@ use hir; use hir::def_id::DefId; -use ich::{self, CachingCodemapView, DefPathHashes}; +use ich::{self, CachingCodemapView}; use session::config::DebugInfoLevel::NoDebugInfo; use ty; @@ -32,7 +32,6 @@ use rustc_data_structures::accumulate_vec::AccumulateVec; /// things (e.g. each DefId/DefPath is only hashed once). pub struct StableHashingContext<'a, 'tcx: 'a> { tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: DefPathHashes<'a, 'tcx>, codemap: CachingCodemapView<'tcx>, hash_spans: bool, hash_bodies: bool, @@ -64,7 +63,6 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { StableHashingContext { tcx: tcx, - def_path_hashes: DefPathHashes::new(tcx), codemap: CachingCodemapView::new(tcx), hash_spans: hash_spans_initial, hash_bodies: true, @@ -111,7 +109,7 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { #[inline] pub fn def_path_hash(&mut self, def_id: DefId) -> u64 { - self.def_path_hashes.hash(def_id) + self.tcx.def_path_hash(def_id) } #[inline] diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index f0601a0efabf..f932c90a331e 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -11,12 +11,10 @@ //! ICH - Incremental Compilation Hash pub use self::fingerprint::Fingerprint; -pub use self::def_path_hash::DefPathHashes; pub use self::caching_codemap_view::CachingCodemapView; pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; mod fingerprint; -mod def_path_hash; mod caching_codemap_view; mod hcx; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 8bc0cf2577b5..ee0635ac9a17 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -230,6 +230,7 @@ pub trait CrateStore { -> Option; fn def_key(&self, def: DefId) -> DefKey; fn def_path(&self, def: DefId) -> hir_map::DefPath; + fn def_path_hash(&self, def: DefId) -> u64; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; @@ -377,6 +378,9 @@ impl CrateStore for DummyCrateStore { fn def_path(&self, def: DefId) -> hir_map::DefPath { bug!("relative_def_path") } + fn def_path_hash(&self, def: DefId) -> u64 { + bug!("wa") + } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3c529a698204..292e30e3d41f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,6 +2227,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + #[inline] + pub fn def_path_hash(self, def_id: DefId) -> u64 { + if def_id.is_local() { + self.hir.definitions().def_path_hash(def_id.index) + } else { + self.sess.cstore.def_path_hash(def_id) + } + } + pub fn def_span(self, def_id: DefId) -> Span { if let Some(id) = self.hir.as_local_node_id(def_id) { self.hir.span(id) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1c1e0d91cb4d..fd8191303a9a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,7 +13,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use infer::InferCtxt; -use hir::map as hir_map; +// use hir::map as hir_map; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; @@ -441,13 +441,11 @@ impl<'a, 'gcx, 'tcx, W> TypeIdHasher<'a, 'gcx, 'tcx, W> fn def_id(&mut self, did: DefId) { // Hash the DefPath corresponding to the DefId, which is independent - // of compiler internal state. - let path = self.tcx.def_path(did); - self.def_path(&path) - } - - pub fn def_path(&mut self, def_path: &hir_map::DefPath) { - def_path.deterministic_hash_to(self.tcx, &mut self.state); + // of compiler internal state. We already have a stable hash value of + // all DefPaths available via tcx.def_path_hash(), so we just feed that + // into the hasher. + let hash = self.tcx.def_path_hash(did); + self.hash(hash); } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 96eb5dd602f5..4e6c919c7f56 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -647,8 +647,12 @@ pub fn phase_2_configure_and_expand(sess: &Session, let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name); crate_loader.preprocess(&krate); let resolver_arenas = Resolver::arenas(); - let mut resolver = - Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas); + let mut resolver = Resolver::new(sess, + &krate, + crate_name, + make_glob_map, + &mut crate_loader, + &resolver_arenas); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index 546feb212243..b9b860222968 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -186,10 +186,6 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> { .clone() } - pub fn lookup_def_path(&self, id: DefPathIndex) -> &DefPath { - &self.directory.paths[id.index as usize] - } - pub fn map(&mut self, node: &DepNode) -> DepNode { node.map_def(|&def_id| Some(self.add(def_id))).unwrap() } diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 2e5186493370..1591503865e8 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -258,8 +258,6 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, index_map: FxHashMap() }; - let mut def_id_hashes = FxHashMap(); - for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() { let index = NodeIndex(index); let def_id = match *target.data { @@ -267,15 +265,6 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, _ => continue, }; - let mut def_id_hash = |def_id: DefId| -> u64 { - *def_id_hashes.entry(def_id) - .or_insert_with(|| { - let index = builder.add(def_id); - let path = builder.lookup_def_path(index); - path.deterministic_hash(tcx) - }) - }; - // To create the hash for each item `X`, we don't hash the raw // bytes of the metadata (though in principle we // could). Instead, we walk the predecessors of `MetaData(X)` @@ -295,7 +284,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, .map(|index| preds.reduced_graph.node_data(index)) .filter(|dep_node| HashContext::is_hashable(dep_node)) .map(|dep_node| { - let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id))) + let hash_dep_node = dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))) .unwrap(); let hash = preds.hashes[dep_node]; (hash_dep_node, hash) diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 41a2e8a8d55e..efcd2f007d66 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -73,7 +73,7 @@ provide! { <'tcx> tcx, def_id, cdata predicates => { cdata.get_predicates(def_id.index, tcx) } super_predicates => { cdata.get_super_predicates(def_id.index, tcx) } trait_def => { - tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx)) + tcx.alloc_trait_def(cdata.get_trait_def(def_id.index)) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { @@ -370,6 +370,10 @@ impl CrateStore for cstore::CStore { self.get_crate_data(def.krate).def_path(def.index) } + fn def_path_hash(&self, def: DefId) -> u64 { + self.get_crate_data(def.krate).def_path_hash(def.index) + } + fn struct_field_names(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 43e076e799b3..cdbecb3ae2e4 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -492,10 +492,7 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_trait_def(&self, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::TraitDef { + pub fn get_trait_def(&self, item_id: DefIndex) -> ty::TraitDef { let data = match self.entry(item_id).kind { EntryKind::Trait(data) => data.decode(self), _ => bug!(), @@ -504,7 +501,7 @@ impl<'a, 'tcx> CrateMetadata { let def = ty::TraitDef::new(self.local_def_id(item_id), data.unsafety, data.paren_sugar, - self.def_path(item_id).deterministic_hash(tcx)); + self.def_path_table.def_path_hash(item_id)); if data.has_default_impl { def.record_has_default_impl(); @@ -1053,6 +1050,7 @@ impl<'a, 'tcx> CrateMetadata { } } + #[inline] pub fn def_key(&self, index: DefIndex) -> DefKey { self.def_path_table.def_key(index) } @@ -1063,6 +1061,11 @@ impl<'a, 'tcx> CrateMetadata { DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent)) } + #[inline] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.def_path_table.def_path_hash(index) + } + /// Imports the codemap from an external crate into the codemap of the crate /// currently being compiled (the "local crate"). /// diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da..d9900340a2e9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1289,6 +1289,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { impl<'a> Resolver<'a> { pub fn new(session: &'a Session, krate: &Crate, + crate_name: &str, make_glob_map: MakeGlobMap, crate_loader: &'a mut CrateLoader, arenas: &'a ResolverArenas<'a>) @@ -1303,7 +1304,8 @@ impl<'a> Resolver<'a> { module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); let mut definitions = Definitions::new(); - DefCollector::new(&mut definitions).collect_root(); + DefCollector::new(&mut definitions) + .collect_root(crate_name, &session.local_crate_disambiguator().as_str()); let mut invocations = FxHashMap(); invocations.insert(Mark::root(), diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 3ad04e10cb02..3568c1ba8f4c 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -101,13 +101,13 @@ use common::SharedCrateContext; use monomorphize::Instance; use rustc::middle::weak_lang_items; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::fold::TypeVisitor; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; -use rustc::hir::map::definitions::{DefPath, DefPathData}; +use rustc::hir::map::definitions::DefPathData; use rustc::util::common::record_time; use syntax::attr; @@ -115,8 +115,8 @@ use syntax::symbol::{Symbol, InternedString}; fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - // path to the item this name is for - def_path: &DefPath, + // the DefId of the item this name is for + def_id: Option, // type of the item, without any generic // parameters substituted; this is @@ -128,8 +128,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // if any. substs: Option<&'tcx Substs<'tcx>>) -> String { - debug!("get_symbol_hash(def_path={:?}, parameters={:?})", - def_path, substs); + debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); let tcx = scx.tcx(); @@ -139,7 +138,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // 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.def_path(def_path); + hasher.hash(def_id.map(|def_id| 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 @@ -224,8 +223,6 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, return scx.tcx().item_name(def_id).as_str().to_string(); } - let def_path = scx.tcx().def_path(def_id); - // 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 @@ -256,10 +253,10 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, // and should not matter anyhow. let instance_ty = scx.tcx().erase_regions(&instance_ty); - let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs)); + let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs)); let mut buffer = SymbolPathBuffer { - names: Vec::with_capacity(def_path.data.len()) + names: Vec::new() }; item_path::with_forced_absolute_paths(|| { @@ -288,11 +285,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, t: Ty<'tcx>, prefix: &str) -> String { - let empty_def_path = DefPath { - data: vec![], - krate: LOCAL_CRATE, - }; - let hash = get_symbol_hash(scx, &empty_def_path, t, None); + let hash = get_symbol_hash(scx, None, t, None); let path = [Symbol::intern(prefix).as_str()]; mangle(path.iter().cloned(), &hash) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1ed42b842c6f..77ab076eba38 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -806,7 +806,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, err.emit(); } - let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx); + let def_path_hash = tcx.def_path_hash(def_id); let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash); if tcx.hir.trait_is_auto(def_id) { From bb6387295a85da70546ed3ce7fa0d702b9cb9d6c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 3 Apr 2017 19:39:12 +0200 Subject: [PATCH 347/905] SVH: Don't hash the HIR twice when once is enough. The SVH (Strict Version Hash) of a crate is currently computed by hashing the ICHes (Incremental Computation Hashes) of the crate's HIR. This is fine, expect that for incr. comp. we compute two ICH values for each HIR item, one for the complete item and one that just includes the item's interface. The two hashes are are needed for dependency tracking but if we are compiling non-incrementally and just need the ICH values for the SVH, one of them is enough, giving us the opportunity to save some work in this case. --- src/librustc_incremental/calculate_svh/mod.rs | 9 ++++++++- src/librustc_incremental/lib.rs | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c80a5a162779..c67866971e19 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -99,6 +99,13 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { item_like: T) where T: HashStable> { + if !hash_bodies && !self.hcx.tcx().sess.opts.build_dep_graph() { + // If we just need the hashes in order to compute the SVH, we don't + // need have two hashes per item. Just the one containing also the + // item's body is sufficient. + return + } + let mut hasher = IchHasher::new(); self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| { item_like.hash_stable(hcx, &mut hasher); @@ -143,7 +150,7 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { (item_dep_node, item_hash) }) .collect(); - item_hashes.sort(); // avoid artificial dependencies on item ordering + item_hashes.sort_unstable(); // avoid artificial dependencies on item ordering item_hashes.hash(&mut crate_state); } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index d10df17f8583..aa7eb36581f3 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -23,6 +23,7 @@ #![feature(staged_api)] #![feature(rand)] #![feature(conservative_impl_trait)] +#![feature(sort_unstable)] #![cfg_attr(stage0, feature(pub_restricted))] extern crate graphviz; From 8fc3ab20b01044cfebfcd963ef7b69cdb11381b2 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 7 Apr 2017 09:11:07 -0400 Subject: [PATCH 348/905] rustdoc needs space after # to ignore --- src/doc/unstable-book/src/compiler-barriers.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 3108494aa79f..df0e20eefadb 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -35,9 +35,9 @@ core). In traditional programs, this can only occur when a signal handler is registered. Consider the following code: ```rust -#use std::sync::atomic::{AtomicBool, AtomicUsize}; -#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; -#use std::sync::atomic::Ordering; +# use std::sync::atomic::{AtomicBool, AtomicUsize}; +# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +# use std::sync::atomic::Ordering; static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; @@ -65,9 +65,9 @@ Using a `compiler_barrier`, we can remedy this situation: ```rust #![feature(compiler_barriers)] -#use std::sync::atomic::{AtomicBool, AtomicUsize}; -#use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; -#use std::sync::atomic::Ordering; +# use std::sync::atomic::{AtomicBool, AtomicUsize}; +# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +# use std::sync::atomic::Ordering; use std::sync::atomic::compiler_barrier; static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; From e6597e12bc40a28ed4c682e71f7159b9cb2403e7 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 7 Apr 2017 09:13:06 -0400 Subject: [PATCH 349/905] Mention interrupts and green threads --- src/doc/unstable-book/src/compiler-barriers.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index df0e20eefadb..9e137a5c4f87 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -32,7 +32,12 @@ racing *with itself*. That is, if a given thread is executing one piece of code, and is then interrupted, and starts executing code elsewhere (while still in the same thread, and conceptually still on the same core). In traditional programs, this can only occur when a signal -handler is registered. Consider the following code: +handler is registered. In more low-level code, such situations can also +arise when handling interrupts, when implementing green threads with +pre-emption, etc. + +To give a straightforward example of when a `compiler_barrier` is +necessary, consider the following example: ```rust # use std::sync::atomic::{AtomicBool, AtomicUsize}; From 15fa301b7aa903235e70f8b5a4c2ef7ae31268f3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 09:46:55 -0500 Subject: [PATCH 350/905] change the format of the linked issue number --- src/doc/unstable-book/src/abi-ptx.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/abi-ptx.md b/src/doc/unstable-book/src/abi-ptx.md index 89b2a199279b..0ded3ceeaef2 100644 --- a/src/doc/unstable-book/src/abi-ptx.md +++ b/src/doc/unstable-book/src/abi-ptx.md @@ -1,7 +1,8 @@ # `abi_ptx` -The tracking issue for this feature -is: [38788](https://github.com/rust-lang/rust/issues/38788) +The tracking issue for this feature is: [#38788] + +[#38788]: https://github.com/rust-lang/rust/issues/38788 ------------------------ From 5c5a5182c94d07409fac8cb40b2cdab488c140ff Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 7 Apr 2017 17:28:55 +0200 Subject: [PATCH 351/905] Optimize AtomicBool::fetch_nand --- src/libcore/sync/atomic.rs | 22 +++++++++++++--------- src/libcore/tests/atomic.rs | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 2e1058bfc341..dd0069502dee 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -539,17 +539,21 @@ impl AtomicBool { // 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 // with an 8-bit integer internally, which would set the upper 7 bits. - // So we just use a compare-exchange loop instead, which is what the - // intrinsic actually expands to anyways on many platforms. - let mut old = self.load(Relaxed); - loop { - let new = !(old && val); - match self.compare_exchange_weak(old, new, order, Relaxed) { - Ok(_) => break, - Err(x) => old = x, + // So we just use fetch_xor or compare_exchange instead. + if val { + // !(x & true) == !x + // We must invert the bool. + self.fetch_xor(true, order) + } else { + // !(x & false) == true + // We must set the bool to true. Instead of delegating to swap or fetch_or, use + // compare_exchange instead in order to avoid unnecessary writes to memory, which + // might minimize cache-coherence traffic. + match self.compare_exchange(false, true, order, Ordering::Relaxed) { + Ok(_) => false, + Err(_) => true, } } - old } /// Logical "or" with a boolean value. diff --git a/src/libcore/tests/atomic.rs b/src/libcore/tests/atomic.rs index b6bb5fddf4a4..9babe24a9856 100644 --- a/src/libcore/tests/atomic.rs +++ b/src/libcore/tests/atomic.rs @@ -24,10 +24,23 @@ fn bool_() { #[test] fn bool_and() { let a = AtomicBool::new(true); - assert_eq!(a.fetch_and(false, SeqCst),true); + assert_eq!(a.fetch_and(false, SeqCst), true); assert_eq!(a.load(SeqCst),false); } +#[test] +fn bool_nand() { + let a = AtomicBool::new(false); + assert_eq!(a.fetch_nand(false, SeqCst), false); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(false, SeqCst), true); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(true, SeqCst), true); + assert_eq!(a.load(SeqCst), false); + assert_eq!(a.fetch_nand(true, SeqCst), false); + assert_eq!(a.load(SeqCst), true); +} + #[test] fn uint_and() { let x = AtomicUsize::new(0xf731); From 9d11b089ad136432dff6c49c6eb3c48c7f6e5273 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 21 Feb 2017 14:47:15 -0500 Subject: [PATCH 352/905] -Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications --- src/librustc/session/config.rs | 16 +- src/librustc/session/mod.rs | 5 +- src/librustc_back/lib.rs | 42 ++++++ src/librustc_back/target/aarch64_apple_ios.rs | 2 + .../target/aarch64_linux_android.rs | 2 + .../target/aarch64_unknown_freebsd.rs | 2 + .../target/aarch64_unknown_fuchsia.rs | 2 + .../target/aarch64_unknown_linux_gnu.rs | 2 + src/librustc_back/target/android_base.rs | 4 +- src/librustc_back/target/apple_base.rs | 4 +- src/librustc_back/target/apple_ios_base.rs | 15 +- .../target/arm_linux_androideabi.rs | 2 + .../target/arm_unknown_linux_gnueabi.rs | 2 + .../target/arm_unknown_linux_gnueabihf.rs | 2 + .../target/arm_unknown_linux_musleabi.rs | 2 + .../target/arm_unknown_linux_musleabihf.rs | 2 + .../target/armv5te_unknown_linux_gnueabi.rs | 3 +- src/librustc_back/target/armv7_apple_ios.rs | 2 + .../target/armv7_linux_androideabi.rs | 2 + .../target/armv7_unknown_linux_gnueabihf.rs | 3 +- .../target/armv7_unknown_linux_musleabihf.rs | 2 + src/librustc_back/target/armv7s_apple_ios.rs | 2 + .../target/asmjs_unknown_emscripten.rs | 11 +- src/librustc_back/target/dragonfly_base.rs | 26 ++-- src/librustc_back/target/freebsd_base.rs | 26 ++-- src/librustc_back/target/fuchsia_base.rs | 34 +++-- src/librustc_back/target/i386_apple_ios.rs | 2 + src/librustc_back/target/i686_apple_darwin.rs | 4 +- .../target/i686_linux_android.rs | 2 + .../target/i686_pc_windows_gnu.rs | 5 +- .../target/i686_pc_windows_msvc.rs | 7 +- .../target/i686_unknown_dragonfly.rs | 4 +- .../target/i686_unknown_freebsd.rs | 4 +- .../target/i686_unknown_haiku.rs | 4 +- .../target/i686_unknown_linux_gnu.rs | 4 +- .../target/i686_unknown_linux_musl.rs | 6 +- .../target/i686_unknown_netbsd.rs | 4 +- .../target/i686_unknown_openbsd.rs | 4 +- src/librustc_back/target/le32_unknown_nacl.rs | 19 ++- src/librustc_back/target/linux_base.rs | 32 ++-- src/librustc_back/target/linux_musl_base.rs | 9 +- .../target/mips64_unknown_linux_gnuabi64.rs | 2 + .../target/mips64el_unknown_linux_gnuabi64.rs | 2 + .../target/mips_unknown_linux_gnu.rs | 2 + .../target/mips_unknown_linux_musl.rs | 2 + .../target/mips_unknown_linux_uclibc.rs | 2 + .../target/mipsel_unknown_linux_gnu.rs | 2 + .../target/mipsel_unknown_linux_musl.rs | 2 + .../target/mipsel_unknown_linux_uclibc.rs | 2 + src/librustc_back/target/mod.rs | 77 ++++++++-- src/librustc_back/target/netbsd_base.rs | 26 ++-- src/librustc_back/target/openbsd_base.rs | 26 ++-- .../target/powerpc64_unknown_linux_gnu.rs | 4 +- .../target/powerpc64le_unknown_linux_gnu.rs | 4 +- .../target/powerpc_unknown_linux_gnu.rs | 4 +- src/librustc_back/target/redox_base.rs | 33 +++-- .../target/s390x_unknown_linux_gnu.rs | 2 + .../target/sparc64_unknown_linux_gnu.rs | 2 + .../target/sparc64_unknown_netbsd.rs | 4 +- .../target/sparcv9_sun_solaris.rs | 4 +- .../target/thumbv6m_none_eabi.rs | 2 + .../target/thumbv7em_none_eabi.rs | 2 + .../target/thumbv7em_none_eabihf.rs | 2 + .../target/thumbv7m_none_eabi.rs | 2 + .../target/wasm32_unknown_emscripten.rs | 14 +- src/librustc_back/target/windows_base.rs | 59 ++++---- src/librustc_back/target/windows_msvc_base.rs | 13 +- .../target/x86_64_apple_darwin.rs | 4 +- src/librustc_back/target/x86_64_apple_ios.rs | 2 + .../target/x86_64_pc_windows_gnu.rs | 4 +- .../target/x86_64_pc_windows_msvc.rs | 2 + .../target/x86_64_rumprun_netbsd.rs | 4 +- .../target/x86_64_sun_solaris.rs | 4 +- .../target/x86_64_unknown_bitrig.rs | 4 +- .../target/x86_64_unknown_dragonfly.rs | 4 +- .../target/x86_64_unknown_freebsd.rs | 4 +- .../target/x86_64_unknown_fuchsia.rs | 4 +- .../target/x86_64_unknown_haiku.rs | 4 +- .../target/x86_64_unknown_linux_gnu.rs | 4 +- .../target/x86_64_unknown_linux_musl.rs | 4 +- .../target/x86_64_unknown_netbsd.rs | 4 +- .../target/x86_64_unknown_openbsd.rs | 4 +- .../target/x86_64_unknown_redox.rs | 4 +- src/librustc_llvm/lib.rs | 1 + src/librustc_trans/back/link.rs | 13 +- src/librustc_trans/back/linker.rs | 138 ++++++++++++------ .../target-specs/my-awesome-platform.json | 1 + .../target-specs/my-incomplete-platform.json | 1 + .../x86_64-unknown-linux-gnu.json | 1 + 89 files changed, 598 insertions(+), 240 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a0603c579524..ef825a6854ce 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -19,7 +19,7 @@ pub use self::DebugInfoLevel::*; use session::{early_error, early_warn, Session}; use session::search_paths::SearchPaths; -use rustc_back::PanicStrategy; +use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::target::Target; use lint; use middle::cstore; @@ -641,12 +641,14 @@ macro_rules! options { Some("either `panic` or `abort`"); pub const parse_sanitizer: Option<&'static str> = Some("one of: `address`, `leak`, `memory` or `thread`"); + pub const parse_linker_flavor: Option<&'static str> = + Some(::rustc_back::LinkerFlavor::one_of()); } #[allow(dead_code)] mod $mod_set { use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer}; - use rustc_back::PanicStrategy; + use rustc_back::{LinkerFlavor, PanicStrategy}; $( pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { @@ -777,6 +779,14 @@ macro_rules! options { } true } + + fn parse_linker_flavor(slote: &mut Option, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavor::from_str) { + Some(lf) => *slote = Some(lf), + _ => return false, + } + true + } } ) } @@ -979,6 +989,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "pass `-install_name @rpath/...` to the macOS linker"), sanitizer: Option = (None, parse_sanitizer, [TRACKED], "Use a sanitizer"), + linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], + "Linker flavor"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3ba82f34c326..70b2809ccbed 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -36,7 +36,7 @@ use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; use syntax_pos::{Span, MultiSpan}; -use rustc_back::PanicStrategy; +use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::target::Target; use rustc_data_structures::flock; use llvm; @@ -363,6 +363,9 @@ impl Session { pub fn panic_strategy(&self) -> PanicStrategy { self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy) } + pub fn linker_flavor(&self) -> LinkerFlavor { + self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor) + } pub fn no_landing_pads(&self) -> bool { self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 000e4eb59bf0..6679cc73029c 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -52,6 +52,48 @@ pub mod dynamic_lib; use serialize::json::{Json, ToJson}; +macro_rules! linker_flavor { + ($(($variant:ident, $string:expr),)+) => { + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, + RustcEncodable, RustcDecodable)] + pub enum LinkerFlavor { + $($variant,)+ + } + + impl LinkerFlavor { + pub const fn one_of() -> &'static str { + concat!("one of: ", $($string, " ",)+) + } + + pub fn from_str(s: &str) -> Option { + Some(match s { + $($string => LinkerFlavor::$variant,)+ + _ => return None, + }) + } + + pub fn desc(&self) -> &str { + match *self { + $(LinkerFlavor::$variant => $string,)+ + } + } + } + + impl ToJson for LinkerFlavor { + fn to_json(&self) -> Json { + self.desc().to_json() + } + } + } +} + +linker_flavor! { + (Em, "em"), + (Gcc, "gcc"), + (Ld, "ld"), + (Msvc, "msvc"), +} + #[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub enum PanicStrategy { Unwind, diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 5ef79359140f..802a8c77db05 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+neon,+fp-armv8,+cyclone".to_string(), eliminate_frame_pointer: false, diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 54eead94986c..7d8610b4a368 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_freebsd.rs b/src/librustc_back/target/aarch64_unknown_freebsd.rs index 3c5d6308ee6b..c5cfff0be03a 100644 --- a/src/librustc_back/target/aarch64_unknown_freebsd.rs +++ b/src/librustc_back/target/aarch64_unknown_freebsd.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_fuchsia.rs b/src/librustc_back/target/aarch64_unknown_fuchsia.rs index 6ba1732e67f7..5d680504a02d 100644 --- a/src/librustc_back/target/aarch64_unknown_fuchsia.rs +++ b/src/librustc_back/target/aarch64_unknown_fuchsia.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -23,6 +24,7 @@ pub fn target() -> TargetResult { target_os: "fuchsia".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index 5f6335d405f5..043bd881c729 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { arch: "aarch64".to_string(), target_os: "linux".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/android_base.rs b/src/librustc_back/target/android_base.rs index 9791520e9339..49baa1b96cee 100644 --- a/src/librustc_back/target/android_base.rs +++ b/src/librustc_back/target/android_base.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::TargetOptions; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); // Many of the symbols defined in compiler-rt are also defined in libgcc. // Android's linker doesn't like that by default. - base.pre_link_args.push("-Wl,--allow-multiple-definition".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--allow-multiple-definition".to_string()); base.is_like_android = true; base.position_independent_executables = true; base.has_elf_tls = false; diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs index 3a551a2b124b..159f93a74c68 100644 --- a/src/librustc_back/target/apple_base.rs +++ b/src/librustc_back/target/apple_base.rs @@ -10,7 +10,7 @@ use std::env; -use target::TargetOptions; +use target::{LinkArgs, TargetOptions}; pub fn opts() -> TargetOptions { // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6 @@ -43,7 +43,7 @@ pub fn opts() -> TargetOptions { dll_prefix: "lib".to_string(), dll_suffix: ".dylib".to_string(), archive_format: "bsd".to_string(), - pre_link_args: Vec::new(), + pre_link_args: LinkArgs::new(), exe_allocation_crate: super::maybe_jemalloc(), has_elf_tls: version >= (10, 7), .. Default::default() diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index 17492b8bdcb6..2e7d30d969ec 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use std::io; use std::process::Command; -use target::TargetOptions; +use target::{LinkArgs, TargetOptions}; use self::Arch::*; @@ -60,7 +61,7 @@ pub fn get_sdk_root(sdk_name: &str) -> Result { } } -fn build_pre_link_args(arch: Arch) -> Result, String> { +fn build_pre_link_args(arch: Arch) -> Result { let sdk_name = match arch { Armv7 | Armv7s | Arm64 => "iphoneos", I386 | X86_64 => "iphonesimulator" @@ -70,8 +71,14 @@ fn build_pre_link_args(arch: Arch) -> Result, String> { let sdk_root = get_sdk_root(sdk_name)?; - Ok(vec!["-arch".to_string(), arch_name.to_string(), - "-Wl,-syslibroot".to_string(), sdk_root]) + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, + vec!["-arch".to_string(), + arch_name.to_string(), + "-Wl,-syslibroot".to_string(), + sdk_root]); + + Ok(args) } fn target_cpu(arch: Arch) -> String { diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index c7d2df4344cb..bccd5a41ab11 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -24,6 +25,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index 77d35edfbd09..165d34fe6c7c 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v6".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index b183412be193..731021d979bc 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v6,+vfp2".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index 261d4353c7a0..f81bcd78b03a 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -29,6 +30,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index 1443dcf5bad4..6c47678ede6a 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -29,6 +30,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs index 37216e20762d..200c6ab74cc6 100644 --- a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -21,6 +22,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+soft-float".to_string(), @@ -31,4 +33,3 @@ pub fn target() -> TargetResult { } }) } - diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index 9e9c44393062..4d8745828329 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v7,+vfp3,+neon".to_string(), max_atomic_width: Some(64), diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs index 36f409b7948c..0c90e834006f 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_back/target/armv7_linux_androideabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#v7a @@ -27,6 +28,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs index 96ccedd5bea5..d3a6a68449c3 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -21,6 +22,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // Info about features at https://wiki.debian.org/ArmHardFloatPort @@ -32,4 +34,3 @@ pub fn target() -> TargetResult { } }) } - diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index 8f66e6a4f58d..5086cd44f7ac 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index 6edde6e73efd..96c89a7ed3bd 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v7,+vfp4,+neon".to_string(), max_atomic_width: Some(64), diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index 4d38b0d17059..b884d4e54101 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions}; use super::emscripten_base::{cmd}; pub fn target() -> Result { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Em, + vec!["-s".to_string(), + "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]); + let opts = TargetOptions { linker: cmd("emcc"), ar: cmd("emar"), @@ -24,7 +30,7 @@ pub fn target() -> Result { obj_is_bitcode: true, is_like_emscripten: true, max_atomic_width: Some(32), - post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], + post_link_args: args, target_family: Some("unix".to_string()), .. Default::default() }; @@ -37,6 +43,7 @@ pub fn target() -> Result { target_vendor: "unknown".to_string(), data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "asmjs".to_string(), + linker_flavor: LinkerFlavor::Em, options: opts, }) } diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs index dca33e45af7c..e44cd393289b 100644 --- a/src/librustc_back/target/dragonfly_base.rs +++ b/src/librustc_back/target/dragonfly_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs index dca33e45af7c..e44cd393289b 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_back/target/freebsd_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_back/target/fuchsia_base.rs index 8c517224201b..c6207cdc4d9c 100644 --- a/src/librustc_back/target/fuchsia_base.rs +++ b/src/librustc_back/target/fuchsia_base.rs @@ -8,30 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + // FIXME: figure out whether these linker args are desirable + //"-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + //"-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - // FIXME: figure out whether these linker args are desirable - //"-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - //"-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: "alloc_system".to_string(), has_elf_tls: true, diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index 319ada4f8e17..a6383179f3ae 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(64), .. base diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index d3b09d9a0f11..6b14972e9f75 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "yonah".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); Ok(Target { llvm_target: "i686-apple-darwin".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "macos".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index f8a8f5a3500b..a5390cbfb725 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#x86 @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index 294772613920..4a736a93be7d 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -18,7 +19,8 @@ pub fn target() -> TargetResult { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args.push("-Wl,--large-address-aware".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--large-address-aware".to_string()); Ok(Target { llvm_target: "i686-pc-windows-gnu".to_string(), @@ -29,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "gnu".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs index 2290d2057f13..17fe306804f4 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -17,12 +18,13 @@ pub fn target() -> TargetResult { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args.push("/LARGEADDRESSAWARE".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Msvc).unwrap().push("/LARGEADDRESSAWARE".to_string()); // Ensure the linker will only produce an image if it can also produce a table of // the image's safe exception handlers. // https://msdn.microsoft.com/en-us/library/9a89h429.aspx - base.pre_link_args.push("/SAFESEH".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string()); Ok(Target { llvm_target: "i686-pc-windows-msvc".to_string(), @@ -33,6 +35,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "msvc".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Msvc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index d8f8431e66e7..052bc23c119e 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-dragonfly".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "dragonfly".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs index ddbc74f25c9c..d77a9cca2683 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_back/target/i686_unknown_freebsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-freebsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_haiku.rs b/src/librustc_back/target/i686_unknown_haiku.rs index 9078206c9e06..b0e67bd90ddd 100644 --- a/src/librustc_back/target/i686_unknown_haiku.rs +++ b/src/librustc_back/target/i686_unknown_haiku.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); Ok(Target { llvm_target: "i686-unknown-haiku".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "haiku".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index bf9c28b0c10e..3c5c10676260 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-linux-gnu".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_back/target/i686_unknown_linux_musl.rs index ced59448f7f6..3ed8c94d0bf2 100644 --- a/src/librustc_back/target/i686_unknown_linux_musl.rs +++ b/src/librustc_back/target/i686_unknown_linux_musl.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); - base.pre_link_args.push("-Wl,-melf_i386".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string()); // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind // implementation, apparently relies on frame pointers existing... somehow. @@ -40,6 +41,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_netbsd.rs b/src/librustc_back/target/i686_unknown_netbsd.rs index e7e2ee3f9056..fc92e5aee6af 100644 --- a/src/librustc_back/target/i686_unknown_netbsd.rs +++ b/src/librustc_back/target/i686_unknown_netbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-netbsdelf".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_openbsd.rs b/src/librustc_back/target/i686_unknown_openbsd.rs index 81efd37386a0..7ef68bd6d9c3 100644 --- a/src/librustc_back/target/i686_unknown_openbsd.rs +++ b/src/librustc_back/target/i686_unknown_openbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-openbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "openbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index 891e7dda14a2..f4265e0eb146 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -8,17 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions, TargetResult}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { + let mut pre_link_args = LinkArgs::new(); + pre_link_args.insert(LinkerFlavor::Gcc, + vec!["--pnacl-exceptions=sjlj".to_string(), + "--target=le32-unknown-nacl".to_string(), + "-Wl,--start-group".to_string()]); + let mut post_link_args = LinkArgs::new(); + post_link_args.insert(LinkerFlavor::Gcc, + vec!["-Wl,--end-group".to_string()]); + let opts = TargetOptions { linker: "pnacl-clang".to_string(), ar: "pnacl-ar".to_string(), - pre_link_args: vec!["--pnacl-exceptions=sjlj".to_string(), - "--target=le32-unknown-nacl".to_string(), - "-Wl,--start-group".to_string()], - post_link_args: vec!["-Wl,--end-group".to_string()], + pre_link_args: pre_link_args, + post_link_args: post_link_args, dynamic_linking: false, executables: true, exe_suffix: ".pexe".to_string(), @@ -36,6 +44,7 @@ pub fn target() -> TargetResult { target_vendor: "unknown".to_string(), data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(), arch: "le32".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: opts, }) } diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_back/target/linux_base.rs index 4b2ae9c8e699..722d2fa16ef7 100644 --- a/src/librustc_back/target/linux_base.rs +++ b/src/librustc_back/target/linux_base.rs @@ -8,29 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), has_elf_tls: true, diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index 18cca425a32c..236f2c1ef0aa 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::TargetOptions; pub fn opts() -> TargetOptions { @@ -15,13 +16,13 @@ pub fn opts() -> TargetOptions { // Make sure that the linker/gcc really don't pull in anything, including // default objects, libs, etc. - base.pre_link_args.push("-nostdlib".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string()); // At least when this was tested, the linker would not add the // `GNU_EH_FRAME` program header to executables generated, which is required // when unwinding to locate the unwinding information. I'm not sure why this // argument is *not* necessary for normal builds, but it can't hurt! - base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string()); // There's a whole bunch of circular dependencies when dealing with MUSL // unfortunately. To put this in perspective libc is statically linked to @@ -45,8 +46,8 @@ pub fn opts() -> TargetOptions { // link everything as a group, not stripping anything out until everything // is processed. The linker will still perform a pass to strip out object // files but it won't do so until all objects/archives have been processed. - base.pre_link_args.push("-Wl,-(".to_string()); - base.post_link_args.push("-Wl,-)".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string()); + base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]); // When generating a statically linked executable there's generally some // small setup needed which is listed in these files. These are provided by diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs index c284840ecb4b..038a70ed6b17 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs index 17895836fe87..aed4c4fbb08d 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index a6d8fae2536c..9ef61f9caddc 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index e4a6d2a55d98..f54790bab970 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs index ccc64ea393b7..59c07efe0fdc 100644 --- a/src/librustc_back/target/mips_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "uclibc".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index 9b8b1d5713f1..ec19cc1a536a 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index 5693bddd0488..00085d18e6d0 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), features: "+mips32,+soft-float".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs index 3acade5a4744..b3ca2edec1ed 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "uclibc".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 559418d2c4f5..ca6894a7b704 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -50,7 +50,7 @@ use std::default::Default; use std::io::prelude::*; use syntax::abi::{Abi, lookup as lookup_abi}; -use PanicStrategy; +use {LinkerFlavor, PanicStrategy}; mod android_base; mod apple_base; @@ -72,6 +72,7 @@ mod thumb_base; mod fuchsia_base; mod redox_base; +pub type LinkArgs = BTreeMap>; pub type TargetResult = Result; macro_rules! supported_targets { @@ -241,6 +242,8 @@ pub struct Target { pub arch: String, /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM. pub data_layout: String, + /// Linker flavor + pub linker_flavor: LinkerFlavor, /// Optional settings with defaults. pub options: TargetOptions, } @@ -261,7 +264,7 @@ pub struct TargetOptions { /// Linker arguments that are unconditionally passed *before* any /// user-defined libraries. - pub pre_link_args: Vec, + pub pre_link_args: LinkArgs, /// Objects to link before all others, always found within the /// sysroot folder. pub pre_link_objects_exe: Vec, // ... when linking an executable @@ -269,13 +272,13 @@ pub struct TargetOptions { /// Linker arguments that are unconditionally passed after any /// user-defined but before post_link_objects. Standard platform /// libraries that should be always be linked to, usually go here. - pub late_link_args: Vec, + pub late_link_args: LinkArgs, /// Objects to link after all others, always found within the /// sysroot folder. pub post_link_objects: Vec, /// Linker arguments that are unconditionally passed *after* any /// user-defined libraries. - pub post_link_args: Vec, + pub post_link_args: LinkArgs, /// Extra arguments to pass to the external assembler (when used) pub asm_args: Vec, @@ -412,8 +415,8 @@ impl Default for TargetOptions { is_builtin: false, linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(), ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(), - pre_link_args: Vec::new(), - post_link_args: Vec::new(), + pre_link_args: LinkArgs::new(), + post_link_args: LinkArgs::new(), asm_args: Vec::new(), cpu: "generic".to_string(), features: "".to_string(), @@ -445,7 +448,7 @@ impl Default for TargetOptions { pre_link_objects_exe: Vec::new(), pre_link_objects_dll: Vec::new(), post_link_objects: Vec::new(), - late_link_args: Vec::new(), + late_link_args: LinkArgs::new(), archive_format: "gnu".to_string(), custom_unwind_resume: false, lib_allocation_crate: "alloc_system".to_string(), @@ -529,6 +532,10 @@ impl Target { target_os: get_req_field("os")?, target_env: get_opt_field("env", ""), target_vendor: get_opt_field("vendor", "unknown"), + linker_flavor: LinkerFlavor::from_str(&*get_req_field("linker-flavor")?) + .ok_or_else(|| { + format!("linker flavor must be {}", LinkerFlavor::one_of()) + })?, options: Default::default(), }; @@ -579,17 +586,49 @@ impl Target { .map(|s| s.to_string() ); } } ); + ($key_name:ident, LinkerFlavor) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.find(&name[..]).and_then(|o| o.as_string().map(|s| { + LinkerFlavor::from_str(&s).ok_or_else(|| { + Err(format!("'{}' is not a valid value for linker-flavor. \ + Use 'em', 'gcc', 'ld' or 'msvc.", s)) + }) + })).unwrap_or(Ok(())) + } ); + ($key_name:ident, link_args) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(obj) = obj.find(&name[..]).and_then(|o| o.as_object()) { + let mut args = LinkArgs::new(); + for (k, v) in obj { + let k = LinkerFlavor::from_str(&k).ok_or_else(|| { + format!("{}: '{}' is not a valid value for linker-flavor. \ + Use 'em', 'gcc', 'ld' or 'msvc'", name, k) + })?; + + let v = v.as_array().map(|a| { + a + .iter() + .filter_map(|o| o.as_string()) + .map(|s| s.to_owned()) + .collect::>() + }).unwrap_or(vec![]); + + args.insert(k, v); + } + base.options.$key_name = args; + } + } ); } key!(is_builtin, bool); key!(linker); key!(ar); - key!(pre_link_args, list); + key!(pre_link_args, link_args); key!(pre_link_objects_exe, list); key!(pre_link_objects_dll, list); - key!(late_link_args, list); + key!(late_link_args, link_args); key!(post_link_objects, list); - key!(post_link_args, list); + key!(post_link_args, link_args); key!(asm_args, list); key!(cpu); key!(features); @@ -734,6 +773,16 @@ impl ToJson for Target { d.insert(name.to_string(), self.options.$attr.to_json()); } } ); + (link_args - $attr:ident) => ( { + let name = (stringify!($attr)).replace("_", "-"); + if default.$attr != self.options.$attr { + let obj = self.options.$attr + .iter() + .map(|(k, v)| (k.desc().to_owned(), v.clone())) + .collect::>(); + d.insert(name.to_string(), obj.to_json()); + } + } ); } target_val!(llvm_target); @@ -743,18 +792,18 @@ impl ToJson for Target { target_val!(target_os, "os"); target_val!(target_env, "env"); target_val!(target_vendor, "vendor"); - target_val!(arch); target_val!(data_layout); + target_val!(linker_flavor); target_option_val!(is_builtin); target_option_val!(linker); target_option_val!(ar); - target_option_val!(pre_link_args); + target_option_val!(link_args - pre_link_args); target_option_val!(pre_link_objects_exe); target_option_val!(pre_link_objects_dll); - target_option_val!(late_link_args); + target_option_val!(link_args - late_link_args); target_option_val!(post_link_objects); - target_option_val!(post_link_args); + target_option_val!(link_args - post_link_args); target_option_val!(asm_args); target_option_val!(cpu); target_option_val!(features); diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs index 57179a68afd8..63245fcae767 100644 --- a/src/librustc_back/target/netbsd_base.rs +++ b/src/librustc_back/target/netbsd_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, .. Default::default() } diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 12b8e8bdc88f..2df9b8e03ff5 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -8,10 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, @@ -19,16 +32,7 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, is_like_openbsd: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: "alloc_system".to_string(), .. Default::default() diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs index 909c5488dcb7..55a5bfd1e674 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); // see #36994 @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs index a692346ca0ff..c22bc3b041a4 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64le".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); // see #36994 @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs index 284772c43319..677d198b1a37 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); base.max_atomic_width = Some(32); // see #36994 @@ -27,6 +28,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/redox_base.rs b/src/librustc_back/target/redox_base.rs index c5e1e107753f..f26a86d4bdc0 100644 --- a/src/librustc_back/target/redox_base.rs +++ b/src/librustc_back/target/redox_base.rs @@ -8,25 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use PanicStrategy; -use target::TargetOptions; +use {LinkerFlavor, PanicStrategy}; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { - TargetOptions { - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string() - ], + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string() + ]); + + TargetOptions { + pre_link_args: args, executables: true, relocation_model: "static".to_string(), disable_redzone: true, diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs index 671fb4f4319b..cc8eb7c4e842 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs index f627cc18f0b3..1bd51ac62581 100644 --- a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparc64_unknown_netbsd.rs b/src/librustc_back/target/sparc64_unknown_netbsd.rs index f30cebbc2d5a..bc65a17ce6ea 100644 --- a/src/librustc_back/target/sparc64_unknown_netbsd.rs +++ b/src/librustc_back/target/sparc64_unknown_netbsd.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "v9".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); Ok(Target { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_back/target/sparcv9_sun_solaris.rs index c88e5a402f2f..122b38968a9c 100644 --- a/src/librustc_back/target/sparcv9_sun_solaris.rs +++ b/src/librustc_back/target/sparcv9_sun_solaris.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); // llvm calls this "v9" base.cpu = "v9".to_string(); base.max_atomic_width = Some(64); @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "solaris".to_string(), target_env: "".to_string(), target_vendor: "sun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/thumbv6m_none_eabi.rs b/src/librustc_back/target/thumbv6m_none_eabi.rs index 6c22f9853845..08bf145e5518 100644 --- a/src/librustc_back/target/thumbv6m_none_eabi.rs +++ b/src/librustc_back/target/thumbv6m_none_eabi.rs @@ -10,6 +10,7 @@ // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them diff --git a/src/librustc_back/target/thumbv7em_none_eabi.rs b/src/librustc_back/target/thumbv7em_none_eabi.rs index ddad4e3624f3..13f9cc5f65fb 100644 --- a/src/librustc_back/target/thumbv7em_none_eabi.rs +++ b/src/librustc_back/target/thumbv7em_none_eabi.rs @@ -19,6 +19,7 @@ // To opt-in to hardware accelerated floating point operations, you can use, for example, // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(32), diff --git a/src/librustc_back/target/thumbv7em_none_eabihf.rs b/src/librustc_back/target/thumbv7em_none_eabihf.rs index a9fac48e8e5a..929b6db6fb2c 100644 --- a/src/librustc_back/target/thumbv7em_none_eabihf.rs +++ b/src/librustc_back/target/thumbv7em_none_eabihf.rs @@ -18,6 +18,7 @@ // // To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the diff --git a/src/librustc_back/target/thumbv7m_none_eabi.rs b/src/librustc_back/target/thumbv7m_none_eabi.rs index ed61dd0459b4..8d46e7cb9076 100644 --- a/src/librustc_back/target/thumbv7m_none_eabi.rs +++ b/src/librustc_back/target/thumbv7m_none_eabi.rs @@ -10,6 +10,7 @@ // Targets the Cortex-M3 processor (ARMv7-M) +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(32), diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs index b1967fa8f37a..a51f59d6ff19 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -8,10 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions}; use super::emscripten_base::{cmd}; pub fn target() -> Result { + let mut post_link_args = LinkArgs::new(); + post_link_args.insert(LinkerFlavor::Gcc, + vec!["-s".to_string(), + "BINARYEN=1".to_string(), + "-s".to_string(), + "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]); + let opts = TargetOptions { linker: cmd("emcc"), ar: cmd("emar"), @@ -26,8 +34,7 @@ pub fn target() -> Result { obj_is_bitcode: true, is_like_emscripten: true, max_atomic_width: Some(32), - post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(), - "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], + post_link_args: post_link_args, target_family: Some("unix".to_string()), .. Default::default() }; @@ -40,6 +47,7 @@ pub fn target() -> Result { target_vendor: "unknown".to_string(), data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "wasm32".to_string(), + linker_flavor: LinkerFlavor::Em, options: opts, }) } diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index db02e142fcc8..9bde24a28dd9 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -8,26 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { - TargetOptions { - // FIXME(#13846) this should be enabled for windows - function_sections: false, - linker: "gcc".to_string(), - dynamic_linking: true, - executables: true, - dll_prefix: "".to_string(), - dll_suffix: ".dll".to_string(), - exe_suffix: ".exe".to_string(), - staticlib_prefix: "".to_string(), - staticlib_suffix: ".lib".to_string(), - no_default_libraries: true, - target_family: Some("windows".to_string()), - is_like_windows: true, - allows_weak_linkage: false, - pre_link_args: vec![ + let mut pre_link_args = LinkArgs::new(); + pre_link_args.insert(LinkerFlavor::Gcc, vec![ // And here, we see obscure linker flags #45. On windows, it has been // found to be necessary to have this flag to compile liblibc. // @@ -64,7 +51,34 @@ pub fn opts() -> TargetOptions { // Do not use the standard system startup files or libraries when linking "-nostdlib".to_string(), - ], + ]); + + let mut late_link_args = LinkArgs::new(); + late_link_args.insert(LinkerFlavor::Gcc, vec![ + "-lmingwex".to_string(), + "-lmingw32".to_string(), + "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc + "-lmsvcrt".to_string(), + "-luser32".to_string(), + "-lkernel32".to_string(), + ]); + + TargetOptions { + // FIXME(#13846) this should be enabled for windows + function_sections: false, + linker: "gcc".to_string(), + dynamic_linking: true, + executables: true, + dll_prefix: "".to_string(), + dll_suffix: ".dll".to_string(), + exe_suffix: ".exe".to_string(), + staticlib_prefix: "".to_string(), + staticlib_suffix: ".lib".to_string(), + no_default_libraries: true, + target_family: Some("windows".to_string()), + is_like_windows: true, + allows_weak_linkage: false, + pre_link_args: pre_link_args, pre_link_objects_exe: vec![ "crt2.o".to_string(), // mingw C runtime initialization for executables "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs @@ -73,14 +87,7 @@ pub fn opts() -> TargetOptions { "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls "rsbegin.o".to_string(), ], - late_link_args: vec![ - "-lmingwex".to_string(), - "-lmingw32".to_string(), - "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc - "-lmsvcrt".to_string(), - "-luser32".to_string(), - "-lkernel32".to_string(), - ], + late_link_args: late_link_args, post_link_objects: vec![ "rsend.o".to_string() ], diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index efa215b419d7..421f59aea93b 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Msvc, + vec!["/NOLOGO".to_string(), + "/NXCOMPAT".to_string()]); + TargetOptions { function_sections: true, linker: "link.exe".to_string(), @@ -56,10 +62,7 @@ pub fn opts() -> TargetOptions { target_family: Some("windows".to_string()), is_like_windows: true, is_like_msvc: true, - pre_link_args: vec![ - "/NOLOGO".to_string(), - "/NXCOMPAT".to_string(), - ], + pre_link_args: args, exe_allocation_crate: "alloc_system".to_string(), .. Default::default() diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index b3c1561dbcc0..8fd1b80430f4 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -15,7 +16,7 @@ pub fn target() -> TargetResult { base.cpu = "core2".to_string(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.eliminate_frame_pointer = false; - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-apple-darwin".to_string(), @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { target_os: "macos".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 7a58bb34ce7f..bbd81fd86ff5 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(64), .. base diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index 321585cd65eb..10e88d88ee37 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); Ok(Target { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "gnu".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs index ea8909d213e8..b07031c4bf1a 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -24,6 +25,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "msvc".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Msvc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index 331372143969..eea4389cfd64 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); base.ar = "x86_64-rumprun-netbsd-ar".to_string(); base.max_atomic_width = Some(64); @@ -34,6 +35,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "rumprun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_back/target/x86_64_sun_solaris.rs index 8e4fd94e7bce..fe8691f36950 100644 --- a/src/librustc_back/target/x86_64_sun_solaris.rs +++ b/src/librustc_back/target/x86_64_sun_solaris.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "solaris".to_string(), target_env: "".to_string(), target_vendor: "sun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs index eda16c29466b..5f87fe177a98 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::bitrig_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-unknown-bitrig".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "bitrig".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index 194efb8fc232..96f608409ffa 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "dragonfly".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index b127bee163b8..500629a16808 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-freebsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_fuchsia.rs b/src/librustc_back/target/x86_64_unknown_fuchsia.rs index 08fe17a556ec..6e37896d4148 100644 --- a/src/librustc_back/target/x86_64_unknown_fuchsia.rs +++ b/src/librustc_back/target/x86_64_unknown_fuchsia.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-fuchsia".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "fuchsia".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_haiku.rs b/src/librustc_back/target/x86_64_unknown_haiku.rs index 7cf0599037c1..7fab9128b295 100644 --- a/src/librustc_back/target/x86_64_unknown_haiku.rs +++ b/src/librustc_back/target/x86_64_unknown_haiku.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-unknown-haiku".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "haiku".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs index f95bcb556e57..f73055cebaa2 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs index c3bf9dcca6ee..38b9c0bace52 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs index 87a7c184644d..6fe2e3fc08e2 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-netbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs index e9d645b0d38f..b292b5fc1e4e 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-openbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "openbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_redox.rs b/src/librustc_back/target/x86_64_unknown_redox.rs index cecac06b2352..a693e76099bd 100644 --- a/src/librustc_back/target/x86_64_unknown_redox.rs +++ b/src/librustc_back/target/x86_64_unknown_redox.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::redox_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-redox".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "redox".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index f300bf16145a..6e34f551f5df 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -422,3 +422,4 @@ impl Drop for OperandBundleDef { } } } +#[link(name = "ffi")] extern {} diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 12a1ffa27672..66380079a8b2 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -707,13 +707,16 @@ fn link_natively(sess: &Session, outputs: &OutputFilenames, tmpdir: &Path) { info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename); + let flavor = sess.linker_flavor(); // The invocations of cc share some flags across platforms let (pname, mut cmd, extra) = get_linker(sess); cmd.env("PATH", command_path(sess, extra)); let root = sess.target_filesearch(PathKind::Native).get_lib_path(); - cmd.args(&sess.target.target.options.pre_link_args); + if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { + cmd.args(args); + } let pre_link_objects = if crate_type == config::CrateTypeExecutable { &sess.target.target.options.pre_link_objects_exe @@ -739,11 +742,15 @@ fn link_natively(sess: &Session, objects, out_filename, outputs, trans); cmd = linker.finalize(); } - cmd.args(&sess.target.target.options.late_link_args); + 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)); } - cmd.args(&sess.target.target.options.post_link_args); + if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { + cmd.args(args); + } if sess.opts.debugging_opts.print_link_args { println!("{:?}", &cmd); diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index a178d17a7c2d..48e469e28ee3 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::collections::HashMap; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter}; @@ -22,6 +22,7 @@ use back::archive; use back::symbol_export::{self, ExportedSymbols}; use middle::dependency_format::Linkage; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; +use rustc_back::LinkerFlavor; use session::Session; use session::config::{self, CrateType, OptLevel, DebugInfoLevel}; use serialize::{json, Encoder}; @@ -45,25 +46,39 @@ impl<'a, 'tcx> LinkerInfo { pub fn to_linker(&'a self, cmd: Command, sess: &'a Session) -> Box { - if sess.target.target.options.is_like_msvc { - Box::new(MsvcLinker { - cmd: cmd, - sess: sess, - info: self - }) as Box - } else if sess.target.target.options.is_like_emscripten { - Box::new(EmLinker { - cmd: cmd, - sess: sess, - info: self - }) as Box - } else { - Box::new(GnuLinker { - cmd: cmd, - sess: sess, - info: self, - hinted_static: false, - }) as Box + match sess.linker_flavor() { + LinkerFlavor::Msvc => { + Box::new(MsvcLinker { + cmd: cmd, + sess: sess, + info: self + }) as Box + } + LinkerFlavor::Em => { + Box::new(EmLinker { + cmd: cmd, + sess: sess, + info: self + }) as Box + } + LinkerFlavor::Gcc => { + Box::new(GccLinker { + cmd: cmd, + sess: sess, + info: self, + hinted_static: false, + is_ld: false, + }) as Box + } + LinkerFlavor::Ld => { + Box::new(GccLinker { + cmd: cmd, + sess: sess, + info: self, + hinted_static: false, + is_ld: true, + }) as Box + } } } } @@ -100,14 +115,32 @@ pub trait Linker { fn finalize(&mut self) -> Command; } -pub struct GnuLinker<'a> { +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> GnuLinker<'a> { +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 } @@ -119,7 +152,7 @@ impl<'a> GnuLinker<'a> { fn hint_static(&mut self) { if !self.takes_hints() { return } if !self.hinted_static { - self.cmd.arg("-Wl,-Bstatic"); + self.linker_arg("-Bstatic"); self.hinted_static = true; } } @@ -127,13 +160,13 @@ impl<'a> GnuLinker<'a> { fn hint_dynamic(&mut self) { if !self.takes_hints() { return } if self.hinted_static { - self.cmd.arg("-Wl,-Bdynamic"); + self.linker_arg("-Bdynamic"); self.hinted_static = false; } } } -impl<'a> Linker for GnuLinker<'a> { +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); } @@ -164,27 +197,26 @@ impl<'a> Linker for GnuLinker<'a> { self.hint_static(); let target = &self.sess.target.target; if !target.options.is_like_osx { - self.cmd.arg("-Wl,--whole-archive") - .arg("-l").arg(lib) - .arg("-Wl,--no-whole-archive"); + 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("-Wl,-force_load,"); + let mut v = OsString::from("-force_load,"); v.push(&archive::find_library(lib, search_path, &self.sess)); - self.cmd.arg(&v); + 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("-Wl,-force_load,"); + let mut v = OsString::from("-force_load,"); v.push(lib); - self.cmd.arg(&v); + self.linker_arg(&v); } else { - self.cmd.arg("-Wl,--whole-archive").arg(lib) - .arg("-Wl,--no-whole-archive"); + self.linker_arg("--whole-archive").cmd.arg(lib); + self.linker_arg("--no-whole-archive"); } } @@ -204,10 +236,10 @@ impl<'a> Linker for GnuLinker<'a> { // for partial linking when using multiple codegen units (-r). So we // insert it here. if self.sess.target.target.options.is_like_osx { - self.cmd.arg("-Wl,-dead_strip"); + self.linker_arg("-dead_strip"); } else if self.sess.target.target.options.is_like_solaris { - self.cmd.arg("-Wl,-z"); - self.cmd.arg("-Wl,ignore"); + 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 @@ -215,7 +247,7 @@ impl<'a> Linker for GnuLinker<'a> { // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. } else if !keep_metadata { - self.cmd.arg("-Wl,--gc-sections"); + self.linker_arg("--gc-sections"); } } @@ -226,7 +258,7 @@ impl<'a> Linker for GnuLinker<'a> { // need a numeric argument, but other linkers do. if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.cmd.arg("-Wl,-O1"); + self.linker_arg("-O1"); } } @@ -235,13 +267,16 @@ impl<'a> Linker for GnuLinker<'a> { } fn no_default_libraries(&mut self) { - self.cmd.arg("-nodefaultlibs"); + 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.args(&["-dynamiclib", "-Wl,-dylib"]); + 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 @@ -249,9 +284,9 @@ impl<'a> Linker for GnuLinker<'a> { // 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("-Wl,-install_name,@rpath/"); + let mut v = OsString::from("-install_name,@rpath/"); v.push(out_filename.file_name().unwrap()); - self.cmd.arg(&v); + self.linker_arg(&v); } } else { self.cmd.arg("-shared"); @@ -307,11 +342,20 @@ impl<'a> Linker for GnuLinker<'a> { } if self.sess.target.target.options.is_like_osx { - arg.push("-Wl,-exported_symbols_list,"); + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("-exported_symbols_list,"); } else if self.sess.target.target.options.is_like_solaris { - arg.push("-Wl,-M,"); + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("-M,"); } else { - arg.push("-Wl,--version-script="); + if !self.is_ld { + arg.push("-Wl,") + } + arg.push("--version-script="); } arg.push(&path); @@ -319,7 +363,7 @@ impl<'a> Linker for GnuLinker<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem)); + self.cmd.arg(&format!("--subsystem,{}", subsystem)); } fn finalize(&mut self) -> Command { diff --git a/src/test/run-make/target-specs/my-awesome-platform.json b/src/test/run-make/target-specs/my-awesome-platform.json index b7083c2776ae..14515ad7f00b 100644 --- a/src/test/run-make/target-specs/my-awesome-platform.json +++ b/src/test/run-make/target-specs/my-awesome-platform.json @@ -1,5 +1,6 @@ { "data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128", + "linker-flavor": "gcc", "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "32", diff --git a/src/test/run-make/target-specs/my-incomplete-platform.json b/src/test/run-make/target-specs/my-incomplete-platform.json index 053f2dd63358..74787b28d223 100644 --- a/src/test/run-make/target-specs/my-incomplete-platform.json +++ b/src/test/run-make/target-specs/my-incomplete-platform.json @@ -1,5 +1,6 @@ { "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32", + "linker-flavor": "gcc", "target-endian": "little", "target-pointer-width": "32", "arch": "x86", diff --git a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json index 688bbe46bfaf..cfe152f9e872 100644 --- a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json +++ b/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json @@ -1,6 +1,7 @@ { "pre-link-args": ["-m64"], "data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128", + "linker-flavor": "gcc", "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "little", "target-pointer-width": "64", From 95bb45431ade3995b5936f522de131453326f2c1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 20:39:10 -0500 Subject: [PATCH 353/905] remove workaround for rust-lang/rust#39880 committed by mistake --- src/librustc_llvm/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 6e34f551f5df..f300bf16145a 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -422,4 +422,3 @@ impl Drop for OperandBundleDef { } } } -#[link(name = "ffi")] extern {} From 2a177b7715043cffd27912dde2db07af562295c3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 6 Apr 2017 22:36:30 -0500 Subject: [PATCH 354/905] add some documentation to the unstable book --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/linker-flavor.md | 61 ++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/doc/unstable-book/src/linker-flavor.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 20812de524ad..65b448c9a78b 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -106,6 +106,7 @@ - [link_llvm_intrinsics](link-llvm-intrinsics.md) - [linkage](linkage.md) - [linked_list_extras](linked-list-extras.md) +- [linker-flavor](linker-flavor.md) - [log_syntax](log-syntax.md) - [lookup_host](lookup-host.md) - [loop_break_value](loop-break-value.md) diff --git a/src/doc/unstable-book/src/linker-flavor.md b/src/doc/unstable-book/src/linker-flavor.md new file mode 100644 index 000000000000..2e8511678349 --- /dev/null +++ b/src/doc/unstable-book/src/linker-flavor.md @@ -0,0 +1,61 @@ +# `linker-flavor` + +The tracking issue for this feature is: None + +------------------------ + +Every `rustc` target defaults to some linker. For example, Linux targets default +to gcc. In some cases, you may want to override the default; you can do that +with the unstable CLI argument: `-Z linker-flavor`. + +Here how you would use this flag to link a Rust binary for the +`thumbv7m-none-eabi` using LLD instead of GCC. + +``` text +$ xargo rustc --target thumbv7m-none-eabi -- \ + -C linker=ld.lld \ + -Z linker-flavor=ld \ + -Z print-link-args | tr ' ' '\n' +"ld.lld" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c.0.o" +"-o" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c" +"--gc-sections" +"-L" +"$PWD/target/thumbv7m-none-eabi/debug/deps" +"-L" +"$PWD/target/debug/deps" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"-Bstatic" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib" +"-Bdynamic" +``` + +Whereas the default is: + +``` +$ xargo rustc --target thumbv7m-none-eabi -- \ + -C link-arg=-nostartfiles \ + -Z print-link-args | tr ' ' '\n' +"arm-none-eabi-gcc" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9.0.o" +"-o" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9" +"-Wl,--gc-sections" +"-nodefaultlibs" +"-L" +"$PWD/target/thumbv7m-none-eabi/debug/deps" +"-L" +"$PWD/target/debug/deps" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"-Wl,-Bstatic" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib" +"-nostartfiles" +"-Wl,-Bdynamic" +``` From e280515499dd24dcfbfe9455806f328b879b243d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 10:51:36 -0500 Subject: [PATCH 355/905] hack: add a linker_flavor feature gate to make tidy accept `-Z linker-flavor` documentation --- src/doc/unstable-book/src/SUMMARY.md | 2 +- src/libsyntax/feature_gate.rs | 3 +++ src/test/compile-fail/feature-gate-linker-flavor.rs | 13 +++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/feature-gate-linker-flavor.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 65b448c9a78b..e30848f20fdf 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -106,7 +106,7 @@ - [link_llvm_intrinsics](link-llvm-intrinsics.md) - [linkage](linkage.md) - [linked_list_extras](linked-list-extras.md) -- [linker-flavor](linker-flavor.md) +- [linker_flavor](linker-flavor.md) - [log_syntax](log-syntax.md) - [lookup_host](lookup-host.md) - [loop_break_value](loop-break-value.md) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 550f1160bed8..2b3d3c0febc4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -343,6 +343,9 @@ declare_features! ( // Used to preserve symbols (see llvm.used) (active, used, "1.18.0", Some(40289)), + + // Hack to document `-Z linker-flavor` in The Unstable Book + (active, linker_flavor, "1.18.0", Some(41142)), ); declare_features! ( diff --git a/src/test/compile-fail/feature-gate-linker-flavor.rs b/src/test/compile-fail/feature-gate-linker-flavor.rs new file mode 100644 index 000000000000..099d488376e7 --- /dev/null +++ b/src/test/compile-fail/feature-gate-linker-flavor.rs @@ -0,0 +1,13 @@ +// 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. + +#![linker_flavor] //~ ERROR the `#[linker_flavor]` attribute is + +fn main() {} From f7ffe5bd2499663026787f91f60e3e3ecf946a03 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 7 Apr 2017 18:04:15 +0200 Subject: [PATCH 356/905] Replace compare_exchange with swap --- src/libcore/sync/atomic.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index dd0069502dee..a4050f271eb9 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -539,20 +539,15 @@ impl AtomicBool { // 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 // with an 8-bit integer internally, which would set the upper 7 bits. - // So we just use fetch_xor or compare_exchange instead. + // So we just use fetch_xor or swap instead. if val { // !(x & true) == !x // We must invert the bool. self.fetch_xor(true, order) } else { // !(x & false) == true - // We must set the bool to true. Instead of delegating to swap or fetch_or, use - // compare_exchange instead in order to avoid unnecessary writes to memory, which - // might minimize cache-coherence traffic. - match self.compare_exchange(false, true, order, Ordering::Relaxed) { - Ok(_) => false, - Err(_) => true, - } + // We must set the bool to true. + self.swap(true, order) } } From bfc08c13ccf9a88159a634bf0a19bf271d341c48 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 7 Apr 2017 20:47:22 +0200 Subject: [PATCH 357/905] pub(restricted) didn't make it into 1.17 Gets shipped in 1.18 instead. --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 550f1160bed8..c68e2ae34687 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -408,7 +408,7 @@ declare_features! ( // Allows the definition recursive static items. (accepted, static_recursion, "1.17.0", Some(29719)), // pub(restricted) visibilities (RFC 1422) - (accepted, pub_restricted, "1.17.0", Some(32409)), + (accepted, pub_restricted, "1.18.0", Some(32409)), // The #![windows_subsystem] attribute (accepted, windows_subsystem, "1.18.0", Some(37499)), ); From bd4f3815eb3f6339f6f0a97894e8b1766df25ea0 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Fri, 7 Apr 2017 19:55:52 +0100 Subject: [PATCH 358/905] Disable errexit for sanity checking git repo --- src/ci/init_repo.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index c235681cddd0..633b88dd2c42 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -41,8 +41,10 @@ if [ ! -f "$cache_valid_file" ]; then rm -rf "$CACHE_DIR" mkdir "$CACHE_DIR" else + set +o errexit stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) - stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1 && echo $?) + stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1; echo $?) + set -o errexit if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then # Something is badly wrong - the cache valid file is here, but something # about the git repo is fishy. Nuke it all, just in case From 68909b0ec0d8738a8f1a0bb7a80998a246943471 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 5 Apr 2017 17:13:46 -0400 Subject: [PATCH 359/905] Add as_c_str. --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/as-c-str.md | 8 ++++++++ src/libstd/ffi/c_str.rs | 6 ++++++ 3 files changed, 15 insertions(+) create mode 100644 src/doc/unstable-book/src/as-c-str.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9ce097e78a4e..1f2ef3669b84 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -12,6 +12,7 @@ - [alloc_system](alloc-system.md) - [allocator](allocator.md) - [allow_internal_unstable](allow-internal-unstable.md) +- [as_c_str](as-c-str.md) - [as_unsafe_cell](as-unsafe-cell.md) - [ascii_ctype](ascii-ctype.md) - [asm](asm.md) diff --git a/src/doc/unstable-book/src/as-c-str.md b/src/doc/unstable-book/src/as-c-str.md new file mode 100644 index 000000000000..ed32eedb3481 --- /dev/null +++ b/src/doc/unstable-book/src/as-c-str.md @@ -0,0 +1,8 @@ +# `as_c_str` + +The tracking issue for this feature is: [#40380] + +[#40380]: https://github.com/rust-lang/rust/issues/40380 + +------------------------ + diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2d14bb66bf4f..d157d52259d2 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -324,6 +324,12 @@ impl CString { &self.inner } + /// Extracts a `CStr` slice containing the entire string. + #[unstable(feature = "as_c_str", issue = "40380")] + pub fn as_c_str(&self) -> &CStr { + &*self + } + /// Converts this `CString` into a boxed `CStr`. #[unstable(feature = "into_boxed_c_str", issue = "40380")] pub fn into_boxed_c_str(self) -> Box { From 9765fbc8130bb7dcd14e1ebc64c0b797840ca488 Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Fri, 7 Apr 2017 16:42:56 -0400 Subject: [PATCH 360/905] fix build errors --- src/libstd/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b5a4cabafdce..d6f7f58a9789 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -96,11 +96,12 @@ //! //! # Contributing changes to the documentation //! -//! Check out the rust contribution guidelines [here](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). +//! Check out the rust contribution guidelines [here]( +//! https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md). //! The source for this documentation can be found on [Github](https://github.com/rust-lang). //! To contribute changes, make sure you read the guidelines first, then submit //! pull-requests for your suggested changes. -//! +//! //! Contributions are appreciated! If you see a part of the docs that can be //! improved, submit a PR, or chat with us first on irc.mozilla.org #rust-docs. //! From d35fa1e98b244773129f18b0e8bcc81fa099ae68 Mon Sep 17 00:00:00 2001 From: Dylan Maccora Date: Fri, 7 Apr 2017 18:26:36 +1000 Subject: [PATCH 361/905] Removing broken examples --- src/libcore/convert.rs | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 0bc055064136..abab4bb0f63b 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -86,19 +86,6 @@ use str::FromStr; /// `&mut Foo` or `&&mut Foo`) /// /// # Examples -/// An example implementation of the trait is [`Path`]. -/// -/// [`Path`]: ../../std/path/struct.Path.html -/// -/// ``` -/// use std::path::Path; -/// -/// impl AsRef for str { -/// fn as_ref(&self) -> &Path { -/// Path::new(self) -/// } -/// } -/// ``` /// /// Both [`String`] and `&str` implement `AsRef`: /// @@ -156,15 +143,6 @@ pub trait AsRef { /// assert_eq!(*boxed_num, 1); /// ``` /// -/// `Vec` implements `AsMut` for converting between itself and a primitive array: -/// -/// ``` -/// impl AsMut<[T]> for Vec { -/// fn as_mut(&mut self) -> &mut [T] { -/// self -/// } -/// } -/// ``` /// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsMut { @@ -275,11 +253,12 @@ pub trait Into: Sized { /// } /// } /// -/// fn open_and_parse_file(file_name: &str) -> Result { -/// let file = std::fs::File::open("test")?; +/// fn open_and_parse_file(file_name: &str) -> Result { +/// let mut file = std::fs::File::open("test")?; /// let mut contents = String::new(); /// file.read_to_string(&mut contents)?; /// let num: i32 = contents.trim().parse()?; +/// Ok(num) /// } /// ``` /// From 5c0c3e803d6070cc4d1ce0362e0ae3bae4962720 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 7 Apr 2017 17:16:52 -0700 Subject: [PATCH 362/905] bootstrap.py: fix armv7 detection This matches the logic that was in `./configure` before f8ca805422db8. --- src/bootstrap/bootstrap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5bc6127a1e7..4b0491f8bd09 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -463,10 +463,10 @@ class RustBuild(object): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype in {'armv6l', 'armv7l', 'armv8l'}: + elif cputype == 'armv6l': cputype = 'arm' ostype += 'eabihf' - elif cputype == 'armv7l': + elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' ostype += 'eabihf' elif cputype == 'aarch64': From 2b2eeda0831401935a45c70667cf4c3eaedafe7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 7 Apr 2017 16:08:07 -0700 Subject: [PATCH 363/905] Move tests from ui to cfail --- src/test/compile-fail/issue-35675.rs | 67 +++++++++++++++++++ src/test/ui/did_you_mean/issue-35675.rs | 44 ------------ src/test/ui/did_you_mean/issue-35675.stderr | 74 --------------------- 3 files changed, 67 insertions(+), 118 deletions(-) create mode 100644 src/test/compile-fail/issue-35675.rs delete mode 100644 src/test/ui/did_you_mean/issue-35675.rs delete mode 100644 src/test/ui/did_you_mean/issue-35675.stderr diff --git a/src/test/compile-fail/issue-35675.rs b/src/test/compile-fail/issue-35675.rs new file mode 100644 index 000000000000..f990c2c42fe1 --- /dev/null +++ b/src/test/compile-fail/issue-35675.rs @@ -0,0 +1,67 @@ +// 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. + +enum Fruit { + Apple(i64), + //~^ HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + //~| HELP there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + Orange(i64), +} + +fn should_return_fruit() -> Apple { + //~^ ERROR cannot find type `Apple` in this scope + //~| NOTE not found in this scope + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn should_return_fruit_too() -> Fruit::Apple { + //~^ ERROR expected type, found variant `Fruit::Apple` + //~| NOTE not a type + Apple(5) + //~^ ERROR cannot find function `Apple` in this scope + //~| NOTE not found in this scope + //~| HELP possible candidate is found in another module, you can import it into scope +} + +fn foo() -> Ok { + //~^ ERROR expected type, found variant `Ok` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Ok(()) +} + +fn bar() -> Variant3 { + //~^ ERROR cannot find type `Variant3` in this scope + //~| NOTE not found in this scope +} + +fn qux() -> Some { + //~^ ERROR expected type, found variant `Some` + //~| NOTE not a type + //~| HELP there is an enum variant + //~| HELP there is an enum variant + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + //~^ HELP there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + Variant4 {}, + } +} diff --git a/src/test/ui/did_you_mean/issue-35675.rs b/src/test/ui/did_you_mean/issue-35675.rs deleted file mode 100644 index ff29f3ad4078..000000000000 --- a/src/test/ui/did_you_mean/issue-35675.rs +++ /dev/null @@ -1,44 +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. - -enum Fruit { - Apple(i64), - Orange(i64), -} - -fn should_return_fruit() -> Apple { - Apple(5) -} - -fn should_return_fruit_too() -> Fruit::Apple { - Apple(5) -} - -fn foo() -> Ok { - Ok(()) -} - -fn bar() -> Variant3 { -} - -fn qux() -> Some { - Some(1) -} - -fn main() {} - -mod x { - enum Enum { - Variant1, - Variant2(), - Variant3(usize), - Variant4 {}, - } -} diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr deleted file mode 100644 index 3d615785b25f..000000000000 --- a/src/test/ui/did_you_mean/issue-35675.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error[E0412]: cannot find type `Apple` in this scope - --> $DIR/issue-35675.rs:16:29 - | -16 | fn should_return_fruit() -> Apple { - | ^^^^^ not found in this scope - | -help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? - --> $DIR/issue-35675.rs:12:5 - | -12 | Apple(i64), - | ^^^^^^^^^^ - -error[E0425]: cannot find function `Apple` in this scope - --> $DIR/issue-35675.rs:17:5 - | -17 | Apple(5) - | ^^^^^ not found in this scope - | - = help: possible candidate is found in another module, you can import it into scope: - `use Fruit::Apple;` - -error[E0573]: expected type, found variant `Fruit::Apple` - --> $DIR/issue-35675.rs:20:33 - | -20 | fn should_return_fruit_too() -> Fruit::Apple { - | ^^^^^^^^^^^^ not a type - | -help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? - --> $DIR/issue-35675.rs:12:5 - | -12 | Apple(i64), - | ^^^^^^^^^^ - -error[E0425]: cannot find function `Apple` in this scope - --> $DIR/issue-35675.rs:21:5 - | -21 | Apple(5) - | ^^^^^ not found in this scope - | - = help: possible candidate is found in another module, you can import it into scope: - `use Fruit::Apple;` - -error[E0573]: expected type, found variant `Ok` - --> $DIR/issue-35675.rs:24:13 - | -24 | fn foo() -> Ok { - | ^^ not a type - | - = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? - = help: there is an enum variant `std::prelude::v1::Result::Ok`, did you mean to use `std::prelude::v1::Result`? - -error[E0412]: cannot find type `Variant3` in this scope - --> $DIR/issue-35675.rs:28:13 - | -28 | fn bar() -> Variant3 { - | ^^^^^^^^ not found in this scope - | -help: there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? - --> $DIR/issue-35675.rs:41:9 - | -41 | Variant3(usize), - | ^^^^^^^^^^^^^^^ - -error[E0573]: expected type, found variant `Some` - --> $DIR/issue-35675.rs:31:13 - | -31 | fn qux() -> Some { - | ^^^^ not a type - | - = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? - = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? - -error: aborting due to 7 previous errors - From 5d2f270395814564f674141a99ace77ea9a03352 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 8 Apr 2017 03:43:18 +0200 Subject: [PATCH 364/905] slice: Implement .rfind() for slice iterators Iter and IterMut Just like the forward case find, implement rfind explicitly --- src/libcore/slice/mod.rs | 13 +++++++++++++ src/libcore/tests/lib.rs | 1 + src/libcore/tests/slice.rs | 13 +++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6d598677c9ba..87dfdfe57b65 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1190,6 +1190,19 @@ macro_rules! iterator { } } } + + fn rfind(&mut self, mut predicate: F) -> Option + where F: FnMut(&Self::Item) -> bool, + { + self.rsearch_while(None, move |elt| { + if predicate(&elt) { + SearchWhile::Done(Some(elt)) + } else { + SearchWhile::Continue + } + }) + } + } // search_while is a generalization of the internal iteration methods. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index d92c378160d2..528ab3bc8452 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(iter_rfind)] #![feature(libc)] #![feature(nonzero)] #![feature(rand)] diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index ec38345030fa..15047204e50d 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -225,6 +225,19 @@ fn get_unchecked_mut_range() { } } +#[test] +fn test_find_rfind() { + let v = [0, 1, 2, 3, 4, 5]; + let mut iter = v.iter(); + let mut i = v.len(); + while let Some(&elt) = iter.rfind(|_| true) { + i -= 1; + assert_eq!(elt, v[i]); + } + assert_eq!(i, 0); + assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3)); +} + #[test] fn sort_unstable() { let mut v = [0; 600]; From f76a3036ef2379e26f1a3777ba032f025f22d5cf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 7 Apr 2017 21:47:58 -0500 Subject: [PATCH 365/905] fake the feature-gate-linker-flavor compile fail test as there's no way to generate a `#![feature(linker_flavor)]` error --- src/test/compile-fail/feature-gate-linker-flavor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/feature-gate-linker-flavor.rs b/src/test/compile-fail/feature-gate-linker-flavor.rs index 099d488376e7..68679d7dac89 100644 --- a/src/test/compile-fail/feature-gate-linker-flavor.rs +++ b/src/test/compile-fail/feature-gate-linker-flavor.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![linker_flavor] //~ ERROR the `#[linker_flavor]` attribute is +#[used] +fn foo() {} +//~^^ ERROR the `#[used]` attribute is an experimental feature fn main() {} From ad58d37c56c4121182b37fb9062c681d3d314c22 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 8 Apr 2017 02:25:40 +0300 Subject: [PATCH 366/905] Fix move checking for nested union fields --- src/librustc_borrowck/borrowck/move_data.rs | 30 +++++----- .../union/union-borrow-move-parent-sibling.rs | 57 +++++++++++++++++++ 2 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 src/test/compile-fail/union/union-borrow-move-parent-sibling.rs diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 2047a58f8ed8..5012969eef90 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -362,31 +362,31 @@ impl<'a, 'tcx> MoveData<'tcx> { /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`. pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - lp: Rc>, + orig_lp: Rc>, id: ast::NodeId, kind: MoveKind) { - // Moving one union field automatically moves all its fields. - if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + // Moving one union field automatically moves all its fields. Also move siblings of + // all parent union fields, moves do not propagate upwards automatically. + let mut lp = orig_lp.clone(); + while let LpExtend(ref base_lp, mutbl, lp_elem) = lp.clone().kind { + if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior)) + = (&base_lp.ty.sty, lp_elem) { if adt_def.is_union() { for field in &adt_def.struct_variant().fields { let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_move_helper(tcx, sibling_lp, id, kind); + if field != interior { + let sibling_lp_kind = + LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err)); + self.add_move_helper(tcx, sibling_lp, id, kind); + } } - return; } } + lp = base_lp.clone(); } - self.add_move_helper(tcx, lp.clone(), id, kind); + self.add_move_helper(tcx, orig_lp.clone(), id, kind); } fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/test/compile-fail/union/union-borrow-move-parent-sibling.rs b/src/test/compile-fail/union/union-borrow-move-parent-sibling.rs new file mode 100644 index 000000000000..5f504feabb26 --- /dev/null +++ b/src/test/compile-fail/union/union-borrow-move-parent-sibling.rs @@ -0,0 +1,57 @@ +// 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(untagged_unions)] +#![allow(unused)] + +#[allow(unions_with_drop_fields)] +union U { + x: ((Vec, Vec), Vec), + y: Box>, +} + +unsafe fn parent_sibling_borrow() { + let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let a = &mut u.x.0; + let a = &u.y; //~ ERROR cannot borrow `u.y` +} + +unsafe fn parent_sibling_move() { + let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let a = u.x.0; + let a = u.y; //~ ERROR use of moved value: `u.y` +} + +unsafe fn grandparent_sibling_borrow() { + let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let a = &mut (u.x.0).0; + let a = &u.y; //~ ERROR cannot borrow `u.y` +} + +unsafe fn grandparent_sibling_move() { + let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let a = (u.x.0).0; + let a = u.y; //~ ERROR use of moved value: `u.y` +} + +unsafe fn deref_sibling_borrow() { + let mut u = U { y: Box::default() }; + let a = &mut *u.y; + let a = &u.x; //~ ERROR cannot borrow `u` (via `u.x`) +} + +unsafe fn deref_sibling_move() { + let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let a = *u.y; + let a = u.x; //~ ERROR use of moved value: `u.x` +} + + +fn main() {} From aeab73c9388effe1295cd9c844393613633f5f5b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 8 Apr 2017 17:53:16 +0300 Subject: [PATCH 367/905] Specify type libraries for llvm-config --ldflags This matters on systems where static libraries and dynamic libraries reside in different location --- src/librustc_llvm/build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 7d5887e699fd..a8def4bafd86 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -217,6 +217,9 @@ fn main() { // hack around this by replacing the host triple with the target and pray // that those -L directories are the same! let mut cmd = Command::new(&llvm_config); + if let Some(link_arg) = llvm_link_arg { + cmd.arg(link_arg); + } cmd.arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { if lib.starts_with("-LIBPATH:") { From f093d59c31bd2064328e24d0ec76e0d105fc32fc Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Sat, 8 Apr 2017 14:03:17 -0400 Subject: [PATCH 368/905] Address @parched's comments --- src/doc/unstable-book/src/compiler-barriers.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-barriers.md index 9e137a5c4f87..827447f0bd51 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-barriers.md @@ -22,8 +22,9 @@ compiler is allowed to do. Specifically, depending on the given ordering semantics, the compiler may be disallowed from moving reads or writes from before or after the call to the other side of the call to `compiler_barrier`. Note that it does **not** prevent the *hardware* -from doing such re-orderings -- for that, the `volatile_*` class of -functions, or full memory fences, need to be used. +from doing such re-ordering. This is not a problem in a single-threaded, +execution context, but when other threads may modify memory at the same +time, stronger synchronization primitives are required. ## Examples @@ -92,12 +93,6 @@ fn signal_handler() { } ``` -In more advanced cases (for example, if `IMPORTANT_VARIABLE` was an -`AtomicPtr` that starts as `NULL`), it may also be unsafe for the -compiler to hoist code using `IMPORTANT_VARIABLE` above the -`IS_READY.load`. In that case, a `compiler_barrier(Ordering::Acquire)` -should be placed at the top of the `if` to prevent this optimizations. - A deeper discussion of compiler barriers with various re-ordering semantics (such as `Ordering::SeqCst`) is beyond the scope of this text. Curious readers are encouraged to read the Linux kernel's discussion of From 28a232a59ac4ded4e6de9e9c06a17a801c5199dd Mon Sep 17 00:00:00 2001 From: projektir Date: Mon, 3 Apr 2017 23:32:59 -0400 Subject: [PATCH 369/905] Adding links around Sender/SyncSender/Receiver errors; Adding more documentation to channel() and sync_channel(); adding more links #29377 --- src/libstd/sync/mpsc/mod.rs | 134 ++++++++++++++++++++------------ src/libstd/sys_common/poison.rs | 4 +- 2 files changed, 87 insertions(+), 51 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 0da65a4f2e12..852675edc023 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -436,81 +436,97 @@ unsafe impl Send for SyncSender {} #[stable(feature = "rust1", since = "1.0.0")] impl !Sync for SyncSender {} -/// An error returned from the [`send`] function on channels. +/// An error returned from the [`Sender::send`] or [`SyncSender::send`] +/// function on **channel**s. /// -/// A [`send`] operation can only fail if the receiving end of a channel is +/// A **send** operation can only fail if the receiving end of a channel is /// disconnected, implying that the data could never be received. The error /// contains the data being sent as a payload so it can be recovered. /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`Sender::send`]: struct.Sender.html#method.send +/// [`SyncSender::send`]: struct.SyncSender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); /// An error returned from the [`recv`] function on a [`Receiver`]. /// -/// The [`recv`] operation can only fail if the sending half of a channel is -/// disconnected, implying that no further messages will ever be received. +/// The [`recv`] operation can only fail if the sending half of a +/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further +/// messages will ever be received. /// -/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// [`recv`]: struct.Receiver.html#method.recv +/// [`Receiver`]: struct.Receiver.html +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; /// This enumeration is the list of the possible reasons that [`try_recv`] could -/// not return data when called. +/// not return data when called. This can occur with both a [`channel`] and +/// a [`sync_channel`]. /// -/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv +/// [`try_recv`]: struct.Receiver.html#method.try_recv +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { - /// This channel is currently empty, but the sender(s) have not yet + /// This **channel** is currently empty, but the **Sender**(s) have not yet /// disconnected, so data may yet become available. #[stable(feature = "rust1", since = "1.0.0")] Empty, - /// This channel's sending half has become disconnected, and there will - /// never be any more data received on this channel + /// The **channel**'s sending half has become disconnected, and there will + /// never be any more data received on it. #[stable(feature = "rust1", since = "1.0.0")] Disconnected, } -/// This enumeration is the list of possible errors that [`recv_timeout`] could -/// not return data when called. +/// This enumeration is the list of possible errors that made [`recv_timeout`] +/// unable to return data when called. This can occur with both a [`channel`] and +/// a [`sync_channel`]. /// -/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout +/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout +/// [`channel`]: fn.channel.html +/// [`sync_channel`]: fn.sync_channel.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { - /// This channel is currently empty, but the sender(s) have not yet + /// This **channel** is currently empty, but the **Sender**(s) have not yet /// disconnected, so data may yet become available. #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Timeout, - /// This channel's sending half has become disconnected, and there will - /// never be any more data received on this channel + /// The **channel**'s sending half has become disconnected, and there will + /// never be any more data received on it. #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] Disconnected, } /// This enumeration is the list of the possible error outcomes for the -/// [`SyncSender::try_send`] method. +/// [`try_send`] method. /// -/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send +/// [`try_send`]: struct.SyncSender.html#method.try_send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub enum TrySendError { - /// The data could not be sent on the channel because it would require that + /// The data could not be sent on the [`sync_channel`] because it would require that /// the callee block to send the data. /// /// If this is a buffered channel, then the buffer is full at this time. If - /// this is not a buffered channel, then there is no receiver available to + /// this is not a buffered channel, then there is no [`Receiver`] available to /// acquire the data. + /// + /// [`sync_channel`]: fn.sync_channel.html + /// [`Receiver`]: struct.Receiver.html #[stable(feature = "rust1", since = "1.0.0")] Full(#[stable(feature = "rust1", since = "1.0.0")] T), - /// This channel's receiving half has disconnected, so the data could not be + /// This [`sync_channel`]'s receiving half has disconnected, so the data could not be /// sent. The data is returned back to the callee in this case. + /// + /// [`sync_channel`]: fn.sync_channel.html #[stable(feature = "rust1", since = "1.0.0")] Disconnected(#[stable(feature = "rust1", since = "1.0.0")] T), } @@ -544,15 +560,27 @@ impl UnsafeFlavor for Receiver { } /// Creates a new asynchronous channel, returning the sender/receiver halves. -/// All data sent on the sender will become available on the receiver, and no -/// send will block the calling thread (this channel has an "infinite buffer"). +/// All data sent on the [`Sender`] will become available on the [`Receiver`] in +/// the same order as it was sent, and no [`send`] will block the calling thread +/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will +/// block after its buffer limit is reached). [`recv`] will block until a message +/// is available. +/// +/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but +/// only one [`Receiver`] is supported. /// /// If the [`Receiver`] is disconnected while trying to [`send`] with the -/// [`Sender`], the [`send`] method will return an error. +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the +/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will +/// return a [`RecvError`]. /// -/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send -/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// [`send`]: struct.Sender.html#method.send +/// [`recv`]: struct.Receiver.html#method.recv +/// [`Sender`]: struct.Sender.html +/// [`Receiver`]: struct.Receiver.html +/// [`sync_channel`]: fn.sync_channel.html +/// [`SendError`]: struct.SendError.html +/// [`RecvError`]: struct.RecvError.html /// /// # Examples /// @@ -560,20 +588,18 @@ impl UnsafeFlavor for Receiver { /// use std::sync::mpsc::channel; /// use std::thread; /// -/// // tx is the sending half (tx for transmission), and rx is the receiving -/// // half (rx for receiving). -/// let (tx, rx) = channel(); +/// let (sender, receiver) = channel(); /// /// // Spawn off an expensive computation /// thread::spawn(move|| { /// # fn expensive_computation() {} -/// tx.send(expensive_computation()).unwrap(); +/// sender.send(expensive_computation()).unwrap(); /// }); /// /// // Do some useful work for awhile /// /// // Let's see what that answer was -/// println!("{:?}", rx.recv().unwrap()); +/// println!("{:?}", receiver.recv().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn channel() -> (Sender, Receiver) { @@ -582,24 +608,32 @@ pub fn channel() -> (Sender, Receiver) { } /// Creates a new synchronous, bounded channel. -/// -/// Like asynchronous channels, the [`Receiver`] will block until a message -/// becomes available. These channels differ greatly in the semantics of the -/// sender from asynchronous channels, however. +/// All data sent on the [`SyncSender`] will become available on the [`Receiver`] +/// in the same order as it was sent. Like asynchronous [`channel`]s, the +/// [`Receiver`] will block until a message becomes available. `sync_channel` +/// differs greatly in the semantics of the sender, however. /// /// This channel has an internal buffer on which messages will be queued. /// `bound` specifies the buffer size. When the internal buffer becomes full, /// future sends will *block* waiting for the buffer to open up. Note that a /// buffer size of 0 is valid, in which case this becomes "rendezvous channel" -/// where each [`send`] will not return until a recv is paired with it. +/// where each [`send`] will not return until a [`recv`] is paired with it. /// -/// Like asynchronous channels, if the [`Receiver`] is disconnected while -/// trying to [`send`] with the [`SyncSender`], the [`send`] method will -/// return an error. +/// The [`SyncSender`] can be cloned to [`send`] to the same channel multiple +/// times, but only one [`Receiver`] is supported. /// -/// [`send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send -/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html -/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying +/// to [`send`] with the [`SyncSender`], the [`send`] method will return a +/// [`SendError`]. Similarly, If the [`SyncSender`] is disconnected while trying +/// to [`recv`], the [`recv`] method will return a [`RecvError`]. +/// +/// [`channel`]: fn.channel.html +/// [`send`]: struct.SyncSender.html#method.send +/// [`recv`]: struct.Receiver.html#method.recv +/// [`SyncSender`]: struct.SyncSender.html +/// [`Receiver`]: struct.Receiver.html +/// [`SendError`]: struct.SendError.html +/// [`RecvError`]: struct.RecvError.html /// /// # Examples /// @@ -607,18 +641,18 @@ pub fn channel() -> (Sender, Receiver) { /// use std::sync::mpsc::sync_channel; /// use std::thread; /// -/// let (tx, rx) = sync_channel(1); +/// let (sender, receiver) = sync_channel(1); /// /// // this returns immediately -/// tx.send(1).unwrap(); +/// sender.send(1).unwrap(); /// /// thread::spawn(move|| { /// // this will block until the previous message has been received -/// tx.send(2).unwrap(); +/// sender.send(2).unwrap(); /// }); /// -/// assert_eq!(rx.recv().unwrap(), 1); -/// assert_eq!(rx.recv().unwrap(), 2); +/// assert_eq!(receiver.recv().unwrap(), 1); +/// assert_eq!(receiver.recv().unwrap(), 2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index d9d13240fcc3..0127a9eb7596 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -73,7 +73,9 @@ pub struct PoisonError { } /// An enumeration of possible errors which can occur while calling the -/// `try_lock` method. +/// [`try_lock`] method. +/// +/// [`try_lock`]: struct.Mutex.html#method.try_lock #[stable(feature = "rust1", since = "1.0.0")] pub enum TryLockError { /// The lock could not be acquired because another thread failed while holding From 69797986879f12db067f5cd8fb89c193548b04f5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 7 Apr 2017 01:00:53 +0300 Subject: [PATCH 370/905] borrowck::mir::dataflow: ignore unwind edges of empty drops This avoids creating drop flags in many unnecessary situations. Fixes #41110. --- .../borrowck/mir/dataflow/mod.rs | 11 +- .../borrowck/mir/elaborate_drops.rs | 113 +++++++++++++----- src/librustc_borrowck/borrowck/mir/mod.rs | 35 +++++- src/test/mir-opt/issue-41110.rs | 53 ++++++++ 4 files changed, 174 insertions(+), 38 deletions(-) create mode 100644 src/test/mir-opt/issue-41110.rs diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 8b246105f616..f0f082a2561c 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -181,6 +181,7 @@ pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation { flow_state: DataflowState, + dead_unwinds: &'a IdxSet, mir: &'a Mir<'tcx>, } @@ -377,6 +378,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> { pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, + dead_unwinds: &'a IdxSet, denotation: D) -> Self { let bits_per_block = denotation.bits_per_block(); let usize_bits = mem::size_of::() * 8; @@ -397,6 +399,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> DataflowAnalysis { mir: mir, + dead_unwinds: dead_unwinds, flow_state: DataflowState { sets: AllSets { bits_per_block: bits_per_block, @@ -452,7 +455,9 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> ref target, value: _, location: _, unwind: Some(ref unwind) } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + if !self.dead_unwinds.contains(&bb) { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } } mir::TerminatorKind::SwitchInt { ref targets, .. } => { for target in targets { @@ -461,7 +466,9 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> } mir::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { if let Some(ref unwind) = *cleanup { - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + if !self.dead_unwinds.contains(&bb) { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } } if let Some((ref dest_lval, ref dest_bb)) = *destination { // N.B.: This must be done *last*, after all other diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 88ec86cc95d6..713e65666627 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -11,8 +11,8 @@ use super::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; -use super::{drop_flag_effects_for_location, on_all_children_bits}; -use super::on_lookup_result_bits; +use super::{on_all_children_bits, on_all_drop_children_bits}; +use super::{drop_flag_effects_for_location, on_lookup_result_bits}; use super::MoveDataParamEnv; use rustc::ty::{self, TyCtxt}; use rustc::mir::*; @@ -24,6 +24,7 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_mir::util::patch::MirPatch; use rustc_mir::util::elaborate_drops::{DropFlagState, elaborate_drop}; use rustc_mir::util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode}; +use syntax::ast; use syntax_pos::Span; use std::fmt; @@ -49,12 +50,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { move_data: move_data, param_env: param_env }; + let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env); let flow_inits = - super::do_dataflow(tcx, mir, id, &[], + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, MaybeInitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); let flow_uninits = - super::do_dataflow(tcx, mir, id, &[], + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, MaybeUninitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); @@ -74,6 +76,67 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { impl Pass for ElaborateDrops {} +/// Return the set of basic blocks whose unwind edges are known +/// to not be reachable, because they are `drop` terminators +/// that can't drop anything. +fn find_dead_unwinds<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + id: ast::NodeId, + env: &MoveDataParamEnv<'tcx>) + -> IdxSetBuf +{ + debug!("find_dead_unwinds({:?})", mir.span); + // We only need to do this pass once, because unwind edges can only + // reach cleanup blocks, which can't have unwind edges themselves. + let mut dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); + let flow_inits = + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, + MaybeInitializedLvals::new(tcx, mir, &env), + |bd, p| &bd.move_data().move_paths[p]); + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + match bb_data.terminator().kind { + TerminatorKind::Drop { ref location, unwind: Some(_), .. } | + TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => { + let mut init_data = InitializationData { + live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), + dead: IdxSetBuf::new_empty(env.move_data.move_paths.len()), + }; + debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", + bb, bb_data, init_data.live); + for stmt in 0..bb_data.statements.len() { + let loc = Location { block: bb, statement_index: stmt }; + init_data.apply_location(tcx, mir, env, loc); + } + + let path = match env.move_data.rev_lookup.find(location) { + LookupResult::Exact(e) => e, + LookupResult::Parent(..) => { + debug!("find_dead_unwinds: has parent; skipping"); + continue + } + }; + + debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path); + + let mut maybe_live = false; + on_all_drop_children_bits(tcx, mir, &env, path, |child| { + let (child_maybe_live, _) = init_data.state(child); + maybe_live |= child_maybe_live; + }); + + debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); + if !maybe_live { + dead_unwinds.add(&bb); + } + } + _ => {} + } + } + + dead_unwinds +} + struct InitializationData { live: IdxSetBuf, dead: IdxSetBuf @@ -144,17 +207,14 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { let mut some_live = false; let mut some_dead = false; let mut children_count = 0; - on_all_children_bits( - self.tcx(), self.mir(), self.ctxt.move_data(), - path, |child| { - if self.ctxt.path_needs_drop(child) { - let (live, dead) = self.init_data.state(child); - debug!("elaborate_drop: state({:?}) = {:?}", - child, (live, dead)); - some_live |= live; - some_dead |= dead; - children_count += 1; - } + on_all_drop_children_bits( + self.tcx(), self.mir(), self.ctxt.env, path, |child| { + let (live, dead) = self.init_data.state(child); + debug!("elaborate_drop: state({:?}) = {:?}", + child, (live, dead)); + some_live |= live; + some_dead |= dead; + children_count += 1; }); ((some_live, some_dead), children_count != 1) } @@ -276,15 +336,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.patch } - fn path_needs_drop(&self, path: MovePathIndex) -> bool - { - let lvalue = &self.move_data().move_paths[path].lvalue; - let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty); - - self.tcx.type_needs_drop_given_env(ty, self.param_env()) - } - fn collect_drop_flags(&mut self) { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { @@ -318,14 +369,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } }; - on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { - if self.path_needs_drop(child) { - let (maybe_live, maybe_dead) = init_data.state(child); - debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", - child, location, path, (maybe_live, maybe_dead)); - if maybe_live && maybe_dead { - self.create_drop_flag(child) - } + on_all_drop_children_bits(self.tcx, self.mir, self.env, path, |child| { + let (maybe_live, maybe_dead) = init_data.state(child); + debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", + child, location, path, (maybe_live, maybe_dead)); + if maybe_live && maybe_dead { + self.create_drop_flag(child) } }); } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 9237bb31f6bd..dc01cbe5e760 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -17,6 +17,7 @@ use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, L use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use rustc_mir::util::elaborate_drops::DropFlagState; +use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; mod abs_domain; pub mod elaborate_drops; @@ -64,14 +65,18 @@ pub fn borrowck_mir(bcx: &mut BorrowckCtxt, let param_env = ty::ParameterEnvironment::for_item(tcx, id); let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; + let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); let flow_inits = - do_dataflow(tcx, mir, id, attributes, MaybeInitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + MaybeInitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); let flow_uninits = - do_dataflow(tcx, mir, id, attributes, MaybeUninitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + MaybeUninitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); let flow_def_inits = - do_dataflow(tcx, mir, id, attributes, DefinitelyInitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + DefinitelyInitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() { @@ -108,6 +113,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, node_id: ast::NodeId, attributes: &[ast::Attribute], + dead_unwinds: &IdxSet, bd: BD, p: P) -> DataflowResults @@ -137,7 +143,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: node_id, print_preflow_to: print_preflow_to, print_postflow_to: print_postflow_to, - flow_state: DataflowAnalysis::new(tcx, mir, bd), + flow_state: DataflowAnalysis::new(tcx, mir, dead_unwinds, bd), }; mbcx.dataflow(p); @@ -303,6 +309,27 @@ fn on_all_children_bits<'a, 'tcx, F>( on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child); } +fn on_all_drop_children_bits<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, + path: MovePathIndex, + mut each_child: F) + where F: FnMut(MovePathIndex) +{ + on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| { + let lvalue = &ctxt.move_data.move_paths[path].lvalue; + let ty = lvalue.ty(mir, tcx).to_ty(tcx); + debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty); + + if tcx.type_needs_drop_given_env(ty, &ctxt.param_env) { + each_child(child); + } else { + debug!("on_all_drop_children_bits - skipping") + } + }) +} + fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs new file mode 100644 index 000000000000..fec635b3abf6 --- /dev/null +++ b/src/test/mir-opt/issue-41110.rs @@ -0,0 +1,53 @@ +// 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. + +// check that we don't emit multiple drop flags when they are not needed. + +fn main() { + let x = S.other(S.id()); +} + +pub fn test() { + let u = S; + let mut v = S; + drop(v); + v = u; +} + +struct S; +impl Drop for S { + fn drop(&mut self) { + } +} + +impl S { + fn id(self) -> Self { self } + fn other(self, s: Self) {} +} + +// END RUST SOURCE +// START rustc.node4.ElaborateDrops.after.mir +// let mut _2: S; +// let mut _3: (); +// let mut _4: S; +// let mut _5: S; +// let mut _6: bool; +// +// bb0: { +// END rustc.node4.ElaborateDrops.after.mir +// START rustc.node13.ElaborateDrops.after.mir +// let mut _2: (); +// let mut _4: (); +// let mut _5: S; +// let mut _6: S; +// let mut _7: bool; +// +// bb0: { +// END rustc.node13.ElaborateDrops.after.mir From d94f2c928c2c41dc0efd4122157e604788141b03 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 8 Apr 2017 13:10:08 -0700 Subject: [PATCH 371/905] Update cargo submodules Brings in a fix for #40955 through rust-lang/cargo#3898. Closes #40955 --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index 4729175045b4..c416fb60b11e 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 +Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 From 536011d929ecbd1170baf34e09580e567c971f95 Mon Sep 17 00:00:00 2001 From: Shiz Date: Sat, 8 Apr 2017 20:36:00 +0200 Subject: [PATCH 372/905] Fix jemalloc support for musl Just like DragonFlyBSD, using the same symbols as the system allocator will result in a segmentation fault at runtime due to allocator mismatches. As such, prefix the jemalloc symbols instead. --- src/liballoc_jemalloc/build.rs | 2 +- src/liballoc_jemalloc/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index ae040a239065..f3a0eebe6984 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -129,7 +129,7 @@ fn main() { // should be good to go! cmd.arg("--with-jemalloc-prefix=je_"); cmd.arg("--disable-tls"); - } else if target.contains("dragonfly") { + } else if target.contains("dragonfly") || target.contains("musl") { cmd.arg("--with-jemalloc-prefix=je_"); } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index a7a67ef76d4f..83cc1ef09c29 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -35,23 +35,23 @@ mod imp { // request it as unprefixing cause segfaults (mismatches in allocators). extern "C" { #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_mallocx")] fn mallocx(size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_rallocx")] fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_xallocx")] fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_sdallocx")] fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_nallocx")] fn nallocx(size: size_t, flags: c_int) -> size_t; } From 49872b859ec71e53266a717f4ec865c88e2bdefe Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 28 Feb 2017 17:50:28 +0200 Subject: [PATCH 373/905] rustc: add a TyLayout helper for type-related layout queries. --- src/librustc/ty/layout.rs | 244 ++++++++++++++++++++++- src/librustc_trans/context.rs | 4 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- 3 files changed, 237 insertions(+), 13 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 571ef30b6b90..8d68eff92517 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -25,6 +25,7 @@ use std::cmp; use std::fmt; use std::i64; use std::iter; +use std::ops::Deref; /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout) /// for a target, which contains everything needed to compute layouts. @@ -904,7 +905,8 @@ pub enum Layout { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, align: Align, - size: Size + element_size: Size, + count: u64 }, /// TyRawPtr or TyRef with a !Sized pointee. @@ -1087,25 +1089,35 @@ impl<'a, 'gcx, 'tcx> Layout { // Arrays and slices. ty::TyArray(element, count) => { let element = element.layout(infcx)?; + let element_size = element.size(dl); + // FIXME(eddyb) Don't use host `usize` for array lengths. + let usize_count: usize = count; + let count = usize_count as u64; + if element_size.checked_mul(count, dl).is_none() { + return Err(LayoutError::SizeOverflow(ty)); + } Array { sized: true, align: element.align(dl), - size: element.size(dl).checked_mul(count as u64, dl) - .map_or(Err(LayoutError::SizeOverflow(ty)), Ok)? + element_size: element_size, + count: count } } ty::TySlice(element) => { + let element = element.layout(infcx)?; Array { sized: false, - align: element.layout(infcx)?.align(dl), - size: Size::from_bytes(0) + align: element.align(dl), + element_size: element.size(dl), + count: 0 } } ty::TyStr => { Array { sized: false, align: dl.i8_align, - size: Size::from_bytes(0) + element_size: Size::from_bytes(1), + count: 0 } } @@ -1447,15 +1459,23 @@ impl<'a, 'gcx, 'tcx> Layout { } Vector { element, count } => { - let elem_size = element.size(dl); - let vec_size = match elem_size.checked_mul(count, dl) { + let element_size = element.size(dl); + let vec_size = match element_size.checked_mul(count, dl) { Some(size) => size, None => bug!("Layout::size({:?}): {} * {} overflowed", - self, elem_size.bytes(), count) + self, element_size.bytes(), count) }; vec_size.abi_align(self.align(dl)) } + Array { element_size, count, .. } => { + match element_size.checked_mul(count, dl) { + Some(size) => size, + None => bug!("Layout::size({:?}): {} * {} overflowed", + self, element_size.bytes(), count) + } + } + FatPointer { metadata, .. } => { // Effectively a (ptr, meta) tuple. Pointer.size(dl).abi_align(metadata.align(dl)) @@ -1464,7 +1484,7 @@ impl<'a, 'gcx, 'tcx> Layout { } CEnum { discr, .. } => Int(discr).size(dl), - Array { size, .. } | General { size, .. } => size, + General { size, .. } => size, UntaggedUnion { ref variants } => variants.stride(), Univariant { ref variant, .. } | @@ -1513,6 +1533,59 @@ impl<'a, 'gcx, 'tcx> Layout { } } } + + pub fn field_offset(&self, + dl: &TargetDataLayout, + i: usize, + variant_index: Option) + -> Size { + match *self { + Scalar { .. } | + CEnum { .. } | + UntaggedUnion { .. } | + RawNullablePointer { .. } => { + Size::from_bytes(0) + } + + Vector { element, count } => { + let element_size = element.size(dl); + let i = i as u64; + assert!(i < count); + Size::from_bytes(element_size.bytes() * count) + } + + Array { element_size, count, .. } => { + let i = i as u64; + assert!(i < count); + Size::from_bytes(element_size.bytes() * count) + } + + FatPointer { metadata, .. } => { + // Effectively a (ptr, meta) tuple. + assert!(i < 2); + if i == 0 { + Size::from_bytes(0) + } else { + Pointer.size(dl).abi_align(metadata.align(dl)) + } + } + + Univariant { ref variant, .. } => variant.offsets[i], + + General { ref variants, .. } => { + let v = variant_index.expect("variant index required"); + variants[v].offsets[i + 1] + } + + StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => { + if Some(nndiscr as usize) == variant_index { + nonnull.offsets[i] + } else { + Size::from_bytes(0) + } + } + } + } } /// Type size "skeleton", i.e. the only information determining a type's size. @@ -1658,3 +1731,154 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } } + +/// A pair of a type and its layout. Implements various +/// type traversal APIs (e.g. recursing into fields). +#[derive(Copy, Clone, Debug)] +pub struct TyLayout<'tcx> { + pub ty: Ty<'tcx>, + pub layout: &'tcx Layout, + pub variant_index: Option, +} + +impl<'tcx> Deref for TyLayout<'tcx> { + type Target = Layout; + fn deref(&self) -> &Layout { + self.layout + } +} + +impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { + pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>) + -> Result> { + let ty = normalize_associated_type(infcx, ty); + + Ok(TyLayout { + ty: ty, + layout: ty.layout(infcx)?, + variant_index: None + }) + } + + pub fn for_variant(&self, variant_index: usize) -> Self { + TyLayout { + variant_index: Some(variant_index), + ..*self + } + } + + pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size { + self.layout.field_offset(dl, i, self.variant_index) + } + + pub fn field_count(&self) -> usize { + // Handle enum/union through the type rather than Layout. + if let ty::TyAdt(def, _) = self.ty.sty { + let v = self.variant_index.unwrap_or(0); + if def.variants.is_empty() { + assert_eq!(v, 0); + return 0; + } else { + return def.variants[v].fields.len(); + } + } + + match *self.layout { + Scalar { .. } => { + bug!("TyLayout::field_count({:?}): not applicable", self) + } + + // Handled above (the TyAdt case). + CEnum { .. } | + General { .. } | + UntaggedUnion { .. } | + RawNullablePointer { .. } | + StructWrappedNullablePointer { .. } => bug!(), + + FatPointer { .. } => 2, + + Vector { count, .. } | + Array { count, .. } => { + let usize_count = count as usize; + assert_eq!(usize_count as u64, count); + usize_count + } + + Univariant { ref variant, .. } => variant.offsets.len(), + } + } + + pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> { + let ptr_field_type = |pointee: Ty<'gcx>| { + let slice = |element: Ty<'gcx>| { + assert!(i < 2); + if i == 0 { + tcx.mk_mut_ptr(element) + } else { + tcx.types.usize + } + }; + match tcx.struct_tail(pointee).sty { + ty::TySlice(element) => slice(element), + ty::TyStr => slice(tcx.types.u8), + ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()), + _ => bug!("TyLayout::field_type({:?}): not applicable", self) + } + }; + + match self.ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyFnPtr(_) | + ty::TyNever | + ty::TyFnDef(..) | + ty::TyDynamic(..) => { + bug!("TyLayout::field_type({:?}): not applicable", self) + } + + // Potentially-fat pointers. + ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + ptr_field_type(pointee) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_field_type(self.ty.boxed_ty()) + } + + // Arrays and slices. + ty::TyArray(element, _) | + ty::TySlice(element) => element, + ty::TyStr => tcx.types.u8, + + // Tuples and closures. + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx).nth(i).unwrap() + } + + ty::TyTuple(tys, _) => tys[i], + + // SIMD vector types. + ty::TyAdt(def, ..) if def.repr.simd => { + self.ty.simd_type(tcx) + } + + // ADTs. + ty::TyAdt(def, substs) => { + def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs) + } + + ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | + ty::TyInfer(_) | ty::TyError => { + bug!("TyLayout::field_type: unexpected type `{}`", self.ty) + } + } + } + + pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize) + -> Result> { + TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i)) + } +} diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index afb94f546abe..3649216eaa85 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -828,9 +828,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { TypeOfDepthLock(self.local()) } - pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout { + pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> { self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { - ty.layout(&infcx).unwrap_or_else(|e| { + ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| { match e { ty::layout::LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 049178a2575f..93798e7bd333 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1564,7 +1564,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, enum_llvm_type, EnumMDF(EnumMemberDescriptionFactory { enum_type: enum_type, - type_rep: type_rep, + type_rep: type_rep.layout, discriminant_type_metadata: discriminant_type_metadata, containing_scope: containing_scope, file_metadata: file_metadata, From c977daf97cd7aa8b964b9b89e7ebd2da26022b2a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 2 Mar 2017 05:35:25 +0200 Subject: [PATCH 374/905] rustc_trans: avoid sizing_type_of everywhere possible. --- src/librustc_trans/abi.rs | 12 +++--------- src/librustc_trans/adt.rs | 20 ++++++-------------- src/librustc_trans/base.rs | 10 ++++------ src/librustc_trans/common.rs | 6 ++---- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/glue.rs | 21 +++++++-------------- src/librustc_trans/intrinsic.rs | 14 +++++++------- src/librustc_trans/meth.rs | 9 ++------- src/librustc_trans/mir/block.rs | 4 ++-- src/librustc_trans/mir/constant.rs | 17 ++++++----------- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/type_of.rs | 14 ++++++++++---- 14 files changed, 53 insertions(+), 82 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 453f65eb762f..550f337d9b1c 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -439,14 +439,10 @@ impl FnType { match ret_ty.sty { // These are not really pointers but pairs, (pointer, len) ty::TyRef(_, ty::TypeAndMut { ty, .. }) => { - let llty = type_of::sizing_type_of(ccx, ty); - let llsz = llsize_of_alloc(ccx, llty); - ret.attrs.set_dereferenceable(llsz); + ret.attrs.set_dereferenceable(ccx.size_of(ty)); } ty::TyAdt(def, _) if def.is_box() => { - let llty = type_of::sizing_type_of(ccx, ret_ty.boxed_ty()); - let llsz = llsize_of_alloc(ccx, llty); - ret.attrs.set_dereferenceable(llsz); + ret.attrs.set_dereferenceable(ccx.size_of(ret_ty.boxed_ty())); } _ => {} } @@ -517,9 +513,7 @@ impl FnType { args.push(info); } else { if let Some(inner) = rust_ptr_attrs(ty, &mut arg) { - let llty = type_of::sizing_type_of(ccx, inner); - let llsz = llsize_of_alloc(ccx, llty); - arg.attrs.set_dereferenceable(llsz); + arg.attrs.set_dereferenceable(ccx.size_of(inner)); } args.push(arg); } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 5c1ced573402..fb7ddd2bf420 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -47,7 +47,7 @@ use std; use llvm::{ValueRef, True, IntEQ, IntNE}; use rustc::ty::layout; -use rustc::ty::{self, Ty, AdtKind}; +use rustc::ty::{self, Ty}; use common::*; use builder::Builder; use base; @@ -285,11 +285,6 @@ pub fn trans_get_discr<'a, 'tcx>( cast_to: Option, range_assert: bool ) -> ValueRef { - let (def, substs) = match t.sty { - ty::TyAdt(ref def, substs) if def.adt_kind() == AdtKind::Enum => (def, substs), - _ => bug!("{} is not an enum", t) - }; - debug!("trans_get_discr t: {:?}", t); let l = bcx.ccx.layout_of(t); @@ -297,19 +292,17 @@ pub fn trans_get_discr<'a, 'tcx>( layout::CEnum { discr, min, max, .. } => { load_discr(bcx, discr, scrutinee, alignment, min, max, range_assert) } - layout::General { discr, .. } => { + layout::General { discr, ref variants, .. } => { let ptr = bcx.struct_gep(scrutinee, 0); load_discr(bcx, discr, ptr, alignment, - 0, def.variants.len() as u64 - 1, + 0, variants.len() as u64 - 1, range_assert) } layout::Univariant { .. } | layout::UntaggedUnion { .. } => C_u8(bcx.ccx, 0), layout::RawNullablePointer { nndiscr, .. } => { let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; - let llptrty = type_of::sizing_type_of(bcx.ccx, - monomorphize::field_ty(bcx.tcx(), substs, - &def.variants[nndiscr as usize].fields[0])); - bcx.icmp(cmp, bcx.load(scrutinee, alignment.to_align()), C_null(llptrty)) + let discr = bcx.load(scrutinee, alignment.to_align()); + bcx.icmp(cmp, discr, C_null(val_ty(discr))) } layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee, alignment) @@ -383,9 +376,8 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu assert_eq!(to, Disr(0)); } layout::RawNullablePointer { nndiscr, .. } => { - let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0]; if to.0 != nndiscr { - let llptrty = type_of::sizing_type_of(bcx.ccx, nnty); + let llptrty = val_ty(val).element_type(); bcx.store(C_null(llptrty), val, None); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index d204703b7759..0b6d9cfd96fa 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -59,7 +59,6 @@ use context::{SharedCrateContext, CrateContextList}; use debuginfo; use declare; use machine; -use machine::llsize_of; use meth; use mir; use monomorphize::{self, Instance}; @@ -534,14 +533,13 @@ pub fn memcpy_ty<'a, 'tcx>( ) { let ccx = bcx.ccx; - if type_is_zero_size(ccx, t) { + let size = ccx.size_of(t); + if size == 0 { return; } - let llty = type_of::type_of(ccx, t); - let llsz = llsize_of(ccx, llty); - let llalign = align.unwrap_or_else(|| type_of::align_of(ccx, t)); - call_memcpy(bcx, dst, src, llsz, llalign as u32); + let align = align.unwrap_or_else(|| ccx.align_of(t)); + call_memcpy(bcx, dst, src, C_uint(ccx, size), align); } pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index a0906bb02f5a..cd9635363685 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -125,10 +125,8 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) /// Identify types which have size zero at runtime. pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { - use machine::llsize_of_alloc; - use type_of::sizing_type_of; - let llty = sizing_type_of(ccx, ty); - llsize_of_alloc(ccx, llty) == 0 + let layout = ccx.layout_of(ty); + !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0 } /* diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index daf1a1ba95f9..6b6fa538dc03 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -255,7 +255,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.statics_to_rauw().borrow_mut().push((g, new_g)); new_g }; - llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty)); + llvm::LLVMSetAlignment(g, ccx.align_of(ty)); llvm::LLVMSetInitializer(g, v); // As an optimization, all shared statics which do not have interior diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 93798e7bd333..f1e1a3bb2213 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1772,7 +1772,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, let var_name = CString::new(var_name).unwrap(); let linkage_name = CString::new(linkage_name).unwrap(); - let global_align = type_of::align_of(cx, variable_type); + let global_align = cx.align_of(variable_type); unsafe { llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 8e86b50b3f7d..1b7cf26853bc 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -449,7 +449,7 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, LocalVariable | CapturedVariable => (0, DW_TAG_auto_variable) }; - let align = ::type_of::align_of(cx, variable_type); + let align = cx.align_of(variable_type); let name = CString::new(variable_name.as_str().as_bytes()).unwrap(); match (variable_access, &[][..]) { diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 41a9ab2842dc..c2aa6c829415 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -19,10 +19,8 @@ use llvm::{ValueRef}; use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; use common::*; -use machine::*; use meth; use monomorphize; -use type_of::{sizing_type_of, align_of}; use value::Value; use builder::Builder; @@ -69,9 +67,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf debug!("calculate size of DST: {}; with lost info: {:?}", t, Value(info)); if bcx.ccx.shared().type_is_sized(t) { - let sizing_type = sizing_type_of(bcx.ccx, t); - let size = llsize_of_alloc(bcx.ccx, sizing_type); - let align = align_of(bcx.ccx, t); + let size = bcx.ccx.size_of(t); + let align = bcx.ccx.align_of(t); debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}", t, Value(info), size, align); let size = C_uint(bcx.ccx, size); @@ -82,9 +79,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf ty::TyAdt(def, substs) => { let ccx = bcx.ccx; // First get the size of all statically known fields. - // Don't use type_of::sizing_type_of because that expects t to be sized, - // and it also rounds up to alignment, which we want to avoid, - // as the unsized field's alignment could be smaller. + // 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 = ccx.layout_of(t); debug!("DST {} layout: {:?}", t, layout); @@ -154,14 +150,11 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf (meth::SIZE.get_usize(bcx, info), meth::ALIGN.get_usize(bcx, info)) } ty::TySlice(_) | ty::TyStr => { - let unit_ty = t.sequence_element_type(bcx.tcx()); + let unit = t.sequence_element_type(bcx.tcx()); // The info in this case is the length of the str, so the size is that // times the unit size. - let llunit_ty = sizing_type_of(bcx.ccx, unit_ty); - let unit_align = llalign_of_min(bcx.ccx, llunit_ty); - let unit_size = llsize_of_alloc(bcx.ccx, llunit_ty); - (bcx.mul(info, C_uint(bcx.ccx, unit_size)), - C_uint(bcx.ccx, unit_align)) + (bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))), + C_uint(bcx.ccx, bcx.ccx.align_of(unit))) } _ => bug!("Unexpected unsized type, found {}", t) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 762bf8592ffc..5e7d612d17f8 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -151,7 +151,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "min_align_of" => { let tp_ty = substs.type_at(0); - C_uint(ccx, type_of::align_of(ccx, tp_ty)) + C_uint(ccx, ccx.align_of(tp_ty)) } "min_align_of_val" => { let tp_ty = substs.type_at(0); @@ -160,7 +160,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llalign } else { - C_uint(ccx, type_of::align_of(ccx, tp_ty)) + C_uint(ccx, ccx.align_of(tp_ty)) } } "pref_align_of" => { @@ -234,7 +234,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } let load = bcx.volatile_load(ptr); unsafe { - llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty)); + llvm::LLVMSetAlignment(load, ccx.align_of(tp_ty)); } to_immediate(bcx, load, tp_ty) }, @@ -252,7 +252,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to()); let store = bcx.volatile_store(val, ptr); unsafe { - llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty)); + llvm::LLVMSetAlignment(store, ccx.align_of(tp_ty)); } } C_nil(ccx) @@ -634,7 +634,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 { if let Some(ty) = fn_ty.ret.cast { let ptr = bcx.pointercast(llresult, ty.ptr_to()); - bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty))); + bcx.store(llval, ptr, Some(ccx.align_of(ret_ty))); } else { store_ty(bcx, llval, llresult, Alignment::AbiAligned, ret_ty); } @@ -651,7 +651,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, -> ValueRef { let ccx = bcx.ccx; let lltp_ty = type_of::type_of(ccx, tp_ty); - let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32); + let align = C_i32(ccx, ccx.align_of(tp_ty) as i32); let size = machine::llsize_of(ccx, lltp_ty); let int_size = machine::llbitsize_of_real(ccx, ccx.int_type()); @@ -685,7 +685,7 @@ fn memset_intrinsic<'a, 'tcx>( count: ValueRef ) -> ValueRef { let ccx = bcx.ccx; - let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32); + let align = C_i32(ccx, ccx.align_of(ty) as i32); let lltp_ty = type_of::type_of(ccx, ty); let size = machine::llsize_of(ccx, lltp_ty); let dst = bcx.pointercast(dst, Type::i8p(ccx)); diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 75ab40761405..f5f924178589 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -17,7 +17,6 @@ use consts; use machine; use monomorphize; use type_::Type; -use type_of::*; use value::Value; use rustc::ty; @@ -80,14 +79,10 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Not in the cache. Build it. let nullptr = C_null(Type::nil(ccx).ptr_to()); - let size_ty = sizing_type_of(ccx, ty); - let size = machine::llsize_of_alloc(ccx, size_ty); - let align = align_of(ccx, ty); - let mut components: Vec<_> = [ callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)), - C_uint(ccx, size), - C_uint(ccx, align) + C_uint(ccx, ccx.size_of(ty)), + C_uint(ccx, ccx.align_of(ty)) ].iter().cloned().collect(); if let Some(trait_ref) = trait_ref { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index d69f31a45048..84ae8143b301 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -24,8 +24,8 @@ use consts; use machine::llalign_of_min; use meth; use monomorphize; +use type_of; use tvec; -use type_of::{self, align_of}; use type_::Type; use rustc_data_structures::indexed_vec::IndexVec; @@ -910,7 +910,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to()); let in_type = val.ty; let out_type = dst.ty.to_ty(bcx.tcx());; - let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type)); + let llalign = cmp::min(bcx.ccx.align_of(in_type), bcx.ccx.align_of(out_type)); self.store_operand(bcx, cast_ptr, Some(llalign), val); } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index dbd928194c03..bd58178b0742 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -148,7 +148,7 @@ impl<'tcx> Const<'tcx> { } else { // Otherwise, or if the value is not immediate, we create // a constant LLVM global and cast its address if necessary. - let align = type_of::align_of(ccx, self.ty); + let align = ccx.align_of(self.ty); let ptr = consts::addr_of(ccx, self.llval, align, "const"); OperandValue::Ref(consts::ptrcast(ptr, llty.ptr_to()), Alignment::AbiAligned) }; @@ -717,7 +717,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { Base::Value(llval) => { // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug) let align = if self.ccx.shared().type_is_sized(ty) { - type_of::align_of(self.ccx, ty) + self.ccx.align_of(ty) } else { self.ccx.tcx().data_layout.pointer_align.abi() as machine::llalign }; @@ -1022,25 +1022,20 @@ fn trans_const<'a, 'tcx>( C_vector(vals) } layout::RawNullablePointer { nndiscr, .. } => { - let nnty = adt::compute_fields(ccx, t, nndiscr as usize, false)[0]; if variant_index as u64 == nndiscr { assert_eq!(vals.len(), 1); vals[0] } else { - C_null(type_of::sizing_type_of(ccx, nnty)) + C_null(type_of::type_of(ccx, t)) } } layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => { if variant_index as u64 == nndiscr { C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false) } else { - let fields = adt::compute_fields(ccx, t, nndiscr as usize, false); - let vals = fields.iter().map(|&ty| { - // Always use null even if it's not the `discrfield`th - // field; see #8506. - C_null(type_of::sizing_type_of(ccx, ty)) - }).collect::>(); - C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false) + // Always use null even if it's not the `discrfield`th + // field; see #8506. + C_null(type_of::type_of(ccx, t)) } } _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l) diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index d487aa6cd5be..12633720ef87 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -438,7 +438,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let content_ty: Ty<'tcx> = self.monomorphize(&content_ty); let llty = type_of::type_of(bcx.ccx, content_ty); let llsize = machine::llsize_of(bcx.ccx, llty); - let align = type_of::align_of(bcx.ccx, content_ty); + let align = bcx.ccx.align_of(content_ty); let llalign = C_uint(bcx.ccx, align); let llty_ptr = llty.ptr_to(); let box_ty = bcx.tcx().mk_box(content_ty); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index a5722e6e520d..b195429711d1 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -322,10 +322,16 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> llty } -pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) - -> machine::llalign { - let layout = cx.layout_of(t); - layout.align(&cx.tcx().data_layout).abi() as machine::llalign +impl<'a, 'tcx> CrateContext<'a, 'tcx> { + pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign { + let layout = self.layout_of(ty); + layout.align(&self.tcx().data_layout).abi() as machine::llalign + } + + pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize { + let layout = self.layout_of(ty); + layout.size(&self.tcx().data_layout).bytes() as machine::llsize + } } fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String { From 43b227f3bdea473c69cb5568adfedfbbb18ff929 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 10 Mar 2017 06:25:51 +0200 Subject: [PATCH 375/905] rustc: add some abstractions to ty::layout for a more concise API. --- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/ty/layout.rs | 140 +++++++++++++++++------ src/librustc_lint/types.rs | 2 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/adt.rs | 5 +- src/librustc_trans/base.rs | 12 +- src/librustc_trans/common.rs | 6 +- src/librustc_trans/context.rs | 61 ++++++++-- src/librustc_trans/debuginfo/metadata.rs | 5 +- src/librustc_trans/glue.rs | 3 +- src/librustc_trans/mir/block.rs | 3 +- src/librustc_trans/mir/constant.rs | 6 +- src/librustc_trans/mir/lvalue.rs | 3 +- src/librustc_trans/mir/mod.rs | 3 +- src/librustc_trans/mir/operand.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/type_of.rs | 11 +- 17 files changed, 188 insertions(+), 80 deletions(-) diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index c9722adc9510..8dc298b9c2a1 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { let from = unpack_option_like(self.infcx.tcx.global_tcx(), from); match (&from.sty, sk_to) { (&ty::TyFnDef(..), SizeSkeleton::Known(size_to)) - if size_to == Pointer.size(&self.infcx.tcx.data_layout) => { + if size_to == Pointer.size(self.infcx) => { struct_span_err!(self.infcx.tcx.sess, span, E0591, "`{}` is zero-sized and can't be transmuted to `{}`", from, to) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 8d68eff92517..54e5de390908 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -202,6 +202,16 @@ impl TargetDataLayout { } } +pub trait HasDataLayout: Copy { + fn data_layout(&self) -> &TargetDataLayout; +} + +impl<'a> HasDataLayout for &'a TargetDataLayout { + fn data_layout(&self) -> &TargetDataLayout { + self + } +} + /// Endianness of the target, which must match cfg(target-endian). #[derive(Copy, Clone)] pub enum Endian { @@ -242,7 +252,9 @@ impl Size { Size::from_bytes((self.bytes() + mask) & !mask) } - pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option { + pub fn checked_add(self, offset: Size, cx: C) -> Option { + let dl = cx.data_layout(); + // Each Size is less than dl.obj_size_bound(), so the sum is // also less than 1 << 62 (and therefore can't overflow). let bytes = self.bytes() + offset.bytes(); @@ -254,7 +266,9 @@ impl Size { } } - pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option { + pub fn checked_mul(self, count: u64, cx: C) -> Option { + let dl = cx.data_layout(); + // Each Size is less than dl.obj_size_bound(), so the sum is // also less than 1 << 62 (and therefore can't overflow). match self.bytes().checked_mul(count) { @@ -354,7 +368,9 @@ impl Integer { } } - pub fn align(&self, dl: &TargetDataLayout)-> Align { + pub fn align(&self, cx: C) -> Align { + let dl = cx.data_layout(); + match *self { I1 => dl.i1_align, I8 => dl.i8_align, @@ -408,7 +424,9 @@ impl Integer { } /// Find the smallest integer with the given alignment. - pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option { + pub fn for_abi_align(cx: C, align: Align) -> Option { + let dl = cx.data_layout(); + let wanted = align.abi(); for &candidate in &[I8, I16, I32, I64] { let ty = Int(candidate); @@ -420,7 +438,9 @@ impl Integer { } /// Get the Integer type from an attr::IntType. - pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer { + pub fn from_attr(cx: C, ity: attr::IntType) -> Integer { + let dl = cx.data_layout(); + match ity { attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8, attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16, @@ -450,7 +470,7 @@ impl Integer { let min_default = I8; if let Some(ity) = repr.int { - let discr = Integer::from_attr(&tcx.data_layout, ity); + let discr = Integer::from_attr(tcx, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; if discr < fit { bug!("Integer::repr_discr: `#[repr]` hint too small for \ @@ -491,7 +511,9 @@ pub enum Primitive { } impl Primitive { - pub fn size(self, dl: &TargetDataLayout) -> Size { + pub fn size(self, cx: C) -> Size { + let dl = cx.data_layout(); + match self { Int(I1) | Int(I8) => Size::from_bits(8), Int(I16) => Size::from_bits(16), @@ -502,7 +524,9 @@ impl Primitive { } } - pub fn align(self, dl: &TargetDataLayout) -> Align { + pub fn align(self, cx: C) -> Align { + let dl = cx.data_layout(); + match self { Int(I1) => dl.i1_align, Int(I8) => dl.i8_align, @@ -682,8 +706,8 @@ impl<'a, 'gcx, 'tcx> Struct { } /// Determine whether a structure would be zero-sized, given its fields. - pub fn would_be_zero_sized(dl: &TargetDataLayout, fields: I) - -> Result> + fn would_be_zero_sized(dl: &TargetDataLayout, fields: I) + -> Result> where I: Iterator>> { for field in fields { let field = field?; @@ -831,7 +855,7 @@ pub struct Union { } impl<'a, 'gcx, 'tcx> Union { - pub fn new(dl: &TargetDataLayout, packed: bool) -> Union { + fn new(dl: &TargetDataLayout, packed: bool) -> Union { Union { align: if packed { dl.i8_align } else { dl.aggregate_align }, min_size: Size::from_bytes(0), @@ -840,10 +864,10 @@ impl<'a, 'gcx, 'tcx> Union { } /// Extend the Struct with more fields. - pub fn extend(&mut self, dl: &TargetDataLayout, - fields: I, - scapegoat: Ty<'gcx>) - -> Result<(), LayoutError<'gcx>> + fn extend(&mut self, dl: &TargetDataLayout, + fields: I, + scapegoat: Ty<'gcx>) + -> Result<(), LayoutError<'gcx>> where I: Iterator>> { for (index, field) in fields.enumerate() { let field = field?; @@ -1452,7 +1476,9 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn size(&self, dl: &TargetDataLayout) -> Size { + pub fn size(&self, cx: C) -> Size { + let dl = cx.data_layout(); + match *self { Scalar { value, .. } | RawNullablePointer { value, .. } => { value.size(dl) @@ -1494,7 +1520,9 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn align(&self, dl: &TargetDataLayout) -> Align { + pub fn align(&self, cx: C) -> Align { + let dl = cx.data_layout(); + match *self { Scalar { value, .. } | RawNullablePointer { value, .. } => { value.align(dl) @@ -1534,11 +1562,13 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn field_offset(&self, - dl: &TargetDataLayout, - i: usize, - variant_index: Option) - -> Size { + pub fn field_offset(&self, + cx: C, + i: usize, + variant_index: Option) + -> Size { + let dl = cx.data_layout(); + match *self { Scalar { .. } | CEnum { .. } | @@ -1617,7 +1647,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { // First try computing a static layout. let err = match ty.layout(infcx) { Ok(layout) => { - return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout))); + return Ok(SizeSkeleton::Known(layout.size(tcx))); } Err(err) => err }; @@ -1748,18 +1778,55 @@ impl<'tcx> Deref for TyLayout<'tcx> { } } -impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { - pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>) - -> Result> { - let ty = normalize_associated_type(infcx, ty); +pub trait HasTyCtxt<'tcx>: HasDataLayout { + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; +} + +impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.data_layout + } +} + +impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { + self.global_tcx() + } +} + +impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { + self.tcx.global_tcx() + } +} + +pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { + type TyLayout; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; +} + +impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { + type TyLayout = Result, LayoutError<'gcx>>; + + fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { + let ty = normalize_associated_type(self, ty); Ok(TyLayout { ty: ty, - layout: ty.layout(infcx)?, + layout: ty.layout(self)?, variant_index: None }) } +} +impl<'a, 'tcx> TyLayout<'tcx> { pub fn for_variant(&self, variant_index: usize) -> Self { TyLayout { variant_index: Some(variant_index), @@ -1767,8 +1834,8 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { } } - pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size { - self.layout.field_offset(dl, i, self.variant_index) + pub fn field_offset(&self, cx: C, i: usize) -> Size { + self.layout.field_offset(cx, i, self.variant_index) } pub fn field_count(&self) -> usize { @@ -1808,9 +1875,11 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { } } - pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> { - let ptr_field_type = |pointee: Ty<'gcx>| { - let slice = |element: Ty<'gcx>| { + pub fn field_type>(&self, cx: C, i: usize) -> Ty<'tcx> { + let tcx = cx.tcx(); + + let ptr_field_type = |pointee: Ty<'tcx>| { + let slice = |element: Ty<'tcx>| { assert!(i < 2); if i == 0 { tcx.mk_mut_ptr(element) @@ -1877,8 +1946,7 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> { } } - pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize) - -> Result> { - TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i)) + pub fn field>(&self, cx: C, i: usize) -> C::TyLayout { + cx.layout_of(self.field_type(cx, i)) } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 529afe0215e5..2318bb81affe 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -733,7 +733,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { }); if let Layout::General { ref variants, ref size, discr, .. } = *layout { - let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes(); + let discr_size = Primitive::Int(discr).size(cx.tcx).bytes(); debug!("enum `{}` is {} bytes large with layout:\n{:#?}", t, size.bytes(), layout); diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 550f337d9b1c..b26dd8eed787 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -35,13 +35,13 @@ use type_of; use rustc::hir; use rustc::ty::{self, Ty}; +use rustc::ty::layout::{Layout, LayoutTyper}; use libc::c_uint; use std::cmp; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; -use rustc::ty::layout::Layout; #[derive(Clone, Copy, PartialEq, Debug)] enum ArgKind { diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index fb7ddd2bf420..b15acfb591ca 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -46,8 +46,8 @@ use super::Disr; use std; use llvm::{ValueRef, True, IntEQ, IntNE}; -use rustc::ty::layout; use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, LayoutTyper}; use common::*; use builder::Builder; use base; @@ -246,9 +246,8 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type { assert_eq!(size%align, 0); assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align); let align_units = size/align; - let dl = &cx.tcx().data_layout; let layout_align = layout::Align::from_bytes(align, align).unwrap(); - if let Some(ity) = layout::Integer::for_abi_align(dl, layout_align) { + if let Some(ity) = layout::Integer::for_abi_align(cx, layout_align) { Type::array(&Type::from_integer(cx, ity), align_units) } else { Type::array(&Type::vector(&Type::i32(cx), align/4), diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 0b6d9cfd96fa..574b345218be 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1295,8 +1295,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // (delay format until we actually need it) let record = |kind, opt_discr_size, variants| { let type_desc = format!("{:?}", ty); - let overall_size = layout.size(&tcx.data_layout); - let align = layout.align(&tcx.data_layout); + let overall_size = layout.size(tcx); + let align = layout.align(tcx); tcx.sess.code_stats.borrow_mut().record_type_size(kind, type_desc, align, @@ -1332,8 +1332,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { session::FieldInfo { name: field_name.to_string(), offset: offset.bytes(), - size: field_layout.size(&tcx.data_layout).bytes(), - align: field_layout.align(&tcx.data_layout).abi(), + size: field_layout.size(tcx).bytes(), + align: field_layout.align(tcx).abi(), } } } @@ -1343,8 +1343,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { session::VariantInfo { name: Some(name.to_string()), kind: session::SizeKind::Exact, - align: value.align(&tcx.data_layout).abi(), - size: value.size(&tcx.data_layout).bytes(), + align: value.align(tcx).abi(), + size: value.size(tcx).bytes(), fields: vec![], } }; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index cd9635363685..5d58c9353892 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -27,7 +27,7 @@ use monomorphize; use type_::Type; use value::Value; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::ty::subst::{Subst, Substs}; use rustc::hir; @@ -63,7 +63,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - Layout::UntaggedUnion { .. } | Layout::RawNullablePointer { .. } | Layout::StructWrappedNullablePointer { .. } => { - !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0 + !layout.is_unsized() && layout.size(ccx).bytes() == 0 } } } @@ -126,7 +126,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) /// Identify types which have size zero at runtime. pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { let layout = ccx.layout_of(ty); - !layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0 + !layout.is_unsized() && layout.size(ccx).bytes() == 0 } /* diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 3649216eaa85..98fbb64fd554 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -28,6 +28,7 @@ use type_::Type; use rustc_data_structures::base_n; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{LayoutTyper, TyLayout}; use session::config::NoDebugInfo; use session::Session; use session::config; @@ -828,18 +829,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { TypeOfDepthLock(self.local()) } - pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> { - self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { - ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| { - match e { - ty::layout::LayoutError::SizeOverflow(_) => - self.sess().fatal(&e.to_string()), - _ => bug!("failed to get layout for `{}`: {}", ty, e) - } - }) - }) - } - pub fn check_overflow(&self) -> bool { self.shared.check_overflow } @@ -951,6 +940,54 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } } +impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> { + fn data_layout(&self) -> &ty::layout::TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } +} + +impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> { + fn data_layout(&self) -> &ty::layout::TargetDataLayout { + &self.shared.tcx.data_layout + } +} + +impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.shared.tcx + } +} + +impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { + type TyLayout = TyLayout<'tcx>; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { + infcx.layout_of(ty).unwrap_or_else(|e| { + match e { + ty::layout::LayoutError::SizeOverflow(_) => + self.sess().fatal(&e.to_string()), + _ => bug!("failed to get layout for `{}`: {}", ty, e) + } + }) + }) + } +} + +impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { + type TyLayout = TyLayout<'tcx>; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + self.shared.layout_of(ty) + } +} + pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index f1e1a3bb2213..ccb693aa41f4 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -35,7 +35,8 @@ use rustc_data_structures::ToHex; use {type_of, machine, monomorphize}; use common::{self, CrateContext}; use type_::Type; -use rustc::ty::{self, AdtKind, Ty, layout}; +use rustc::ty::{self, AdtKind, Ty}; +use rustc::ty::layout::{self, LayoutTyper}; use session::config; use util::nodemap::FxHashMap; use util::common::path2cstr; @@ -900,7 +901,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { let offsets = match *layout { layout::Univariant { ref variant, .. } => &variant.offsets, layout::Vector { element, count } => { - let element_size = element.size(&cx.tcx().data_layout).bytes(); + let element_size = element.size(cx).bytes(); tmp = (0..count). map(|i| layout::Size::from_bytes(i*element_size)) .collect::>(); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index c2aa6c829415..59876a7f2a20 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -18,6 +18,7 @@ use llvm; use llvm::{ValueRef}; use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::LayoutTyper; use common::*; use meth; use monomorphize; @@ -47,7 +48,7 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx> if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { let layout = t.layout(&infcx).unwrap(); - if layout.size(&scx.tcx().data_layout).bytes() == 0 { + if layout.size(scx).bytes() == 0 { // `Box` does not allocate. false } else { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 84ae8143b301..18893ce4ea9a 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -12,7 +12,8 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err}; use rustc::middle::lang_items; use rustc::middle::const_val::ConstInt; -use rustc::ty::{self, layout, TypeFoldable}; +use rustc::ty::{self, TypeFoldable}; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; use abi::{Abi, FnType, ArgType}; use base::{self, Lifetime}; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index bd58178b0742..4d5b691c86eb 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -18,7 +18,8 @@ use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::mir; use rustc::mir::tcx::LvalueTy; -use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::subst::{Kind, Substs, Subst}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; @@ -979,7 +980,6 @@ fn trans_const<'a, 'tcx>( vals: &[ValueRef] ) -> ValueRef { let l = ccx.layout_of(t); - let dl = &ccx.tcx().data_layout; let variant_index = match *kind { mir::AggregateKind::Adt(_, index, _, _) => index, _ => 0, @@ -1002,7 +1002,7 @@ fn trans_const<'a, 'tcx>( let mut vals_with_discr = vec![lldiscr]; vals_with_discr.extend_from_slice(vals); let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]); - let needed_padding = l.size(dl).bytes() - variant.stride().bytes(); + let needed_padding = l.size(ccx).bytes() - variant.stride().bytes(); if needed_padding > 0 { contents.push(padding(ccx, needed_padding)); } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index dd8c1d0e1f03..fc889604ab88 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -9,7 +9,8 @@ // except according to those terms. use llvm::ValueRef; -use rustc::ty::{self, layout, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 21bbbea77d44..cc957a4d2587 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,7 +11,8 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, layout}; +use rustc::ty; +use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index da24c03fdc2a..771a88238b2b 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -10,7 +10,7 @@ use llvm::ValueRef; use rustc::ty::{self, Ty}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 12633720ef87..8f7cb914c473 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -11,7 +11,7 @@ use llvm::{self, ValueRef}; use rustc::ty::{self, Ty}; use rustc::ty::cast::{CastTy, IntTy}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::mir::tcx::LvalueTy; use rustc::mir; use middle::lang_items::ExchangeMallocFnLangItem; diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b195429711d1..c459191561dd 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -13,6 +13,7 @@ use adt; use common::*; use machine; use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::layout::LayoutTyper; use trans_item::DefPathBasedNames; use type_::Type; @@ -117,14 +118,14 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ return llsizingty; } - let r = layout.size(&cx.tcx().data_layout).bytes(); + let r = layout.size(cx).bytes(); let l = machine::llsize_of_alloc(cx, llsizingty); if r != l { bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", r, l, t, layout); } - let r = layout.align(&cx.tcx().data_layout).abi(); + let r = layout.align(cx).abi(); let l = machine::llalign_of_min(cx, llsizingty) as u64; if r != l { bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", @@ -324,13 +325,11 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> impl<'a, 'tcx> CrateContext<'a, 'tcx> { pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign { - let layout = self.layout_of(ty); - layout.align(&self.tcx().data_layout).abi() as machine::llalign + self.layout_of(ty).align(self).abi() as machine::llalign } pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize { - let layout = self.layout_of(ty); - layout.size(&self.tcx().data_layout).bytes() as machine::llsize + self.layout_of(ty).size(self).bytes() as machine::llsize } } From 2fed2a2395f3265eaa740ed5c555f4225c555ddf Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 8 Apr 2017 15:51:18 -0500 Subject: [PATCH 376/905] this code block is text not Rust code --- src/doc/unstable-book/src/linker-flavor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/linker-flavor.md b/src/doc/unstable-book/src/linker-flavor.md index 2e8511678349..39659602e015 100644 --- a/src/doc/unstable-book/src/linker-flavor.md +++ b/src/doc/unstable-book/src/linker-flavor.md @@ -36,7 +36,7 @@ $ xargo rustc --target thumbv7m-none-eabi -- \ Whereas the default is: -``` +``` text $ xargo rustc --target thumbv7m-none-eabi -- \ -C link-arg=-nostartfiles \ -Z print-link-args | tr ' ' '\n' From a6f7628ea28a74e09002e430609b6e6ce52fd0ba Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Sat, 8 Apr 2017 18:53:57 -0400 Subject: [PATCH 377/905] Use the existing path when removing the prefix fails. This allows the use of out-of-tree paths to be specified --- src/bootstrap/step.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 5560b5b0333c..74c9ae983737 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -137,7 +137,9 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { while let Some(krate) = list.pop() { let default = krate == name; let krate = &build.crates[krate]; - let path = krate.path.strip_prefix(&build.src).unwrap(); + let path = krate.path.strip_prefix(&build.src) + // This handles out of tree paths + .unwrap_or(&krate.path); ret.push((krate, path.to_str().unwrap(), default)); for dep in krate.deps.iter() { if visited.insert(dep) && dep != "build_helper" { From f0636b61c7f84962a609e831760db9d77f4f5e14 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 10 Mar 2017 06:25:57 +0200 Subject: [PATCH 378/905] rustc_trans: use ty::layout for ABI computation instead of LLVM types. --- src/librustc_trans/abi.rs | 591 +++++++++++++++++-------- src/librustc_trans/adt.rs | 24 +- src/librustc_trans/cabi_aarch64.rs | 178 +++----- src/librustc_trans/cabi_arm.rs | 155 ++----- src/librustc_trans/cabi_asmjs.rs | 35 +- src/librustc_trans/cabi_mips.rs | 90 +--- src/librustc_trans/cabi_mips64.rs | 90 +--- src/librustc_trans/cabi_msp430.rs | 21 +- src/librustc_trans/cabi_nvptx.rs | 21 +- src/librustc_trans/cabi_nvptx64.rs | 21 +- src/librustc_trans/cabi_powerpc.rs | 95 +--- src/librustc_trans/cabi_powerpc64.rs | 180 ++------ src/librustc_trans/cabi_s390x.rs | 148 ++----- src/librustc_trans/cabi_sparc.rs | 90 +--- src/librustc_trans/cabi_sparc64.rs | 189 +++----- src/librustc_trans/cabi_x86.rs | 37 +- src/librustc_trans/cabi_x86_64.rs | 536 +++++++++------------- src/librustc_trans/cabi_x86_win64.rs | 45 +- src/librustc_trans/mir/block.rs | 28 +- src/librustc_trans/mir/mod.rs | 19 +- src/librustc_trans/type_of.rs | 119 +---- src/test/codegen/function-arguments.rs | 4 +- 22 files changed, 1018 insertions(+), 1698 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index b26dd8eed787..7be80a757ca0 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace}; +use llvm::{self, ValueRef, AttributePlace}; use base; use builder::Builder; use common::{type_is_fat_ptr, C_uint}; @@ -29,16 +29,17 @@ use cabi_sparc; use cabi_sparc64; use cabi_nvptx; use cabi_nvptx64; -use machine::{llalign_of_min, llsize_of, llsize_of_alloc}; +use machine::llalign_of_min; use type_::Type; use type_of; use rustc::hir; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{Layout, LayoutTyper}; +use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size}; use libc::c_uint; use std::cmp; +use std::iter; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; @@ -132,33 +133,293 @@ impl ArgAttributes { } } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum RegKind { + Integer, + Float, + Vector +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Reg { + pub kind: RegKind, + pub size: Size, +} + +macro_rules! reg_ctor { + ($name:ident, $kind:ident, $bits:expr) => { + pub fn $name() -> Reg { + Reg { + kind: RegKind::$kind, + size: Size::from_bits($bits) + } + } + } +} + +impl Reg { + reg_ctor!(i8, Integer, 8); + reg_ctor!(i16, Integer, 16); + reg_ctor!(i32, Integer, 32); + reg_ctor!(i64, Integer, 64); + + reg_ctor!(f32, Float, 32); + reg_ctor!(f64, Float, 64); +} + +impl Reg { + fn llvm_type(&self, ccx: &CrateContext) -> Type { + match self.kind { + RegKind::Integer => Type::ix(ccx, self.size.bits()), + RegKind::Float => { + match self.size.bits() { + 32 => Type::f32(ccx), + 64 => Type::f64(ccx), + _ => bug!("unsupported float: {:?}", self) + } + } + RegKind::Vector => { + Type::vector(&Type::i8(ccx), self.size.bytes()) + } + } + } +} + +/// An argument passed entirely registers with the +/// same kind (e.g. HFA / HVA on PPC64 and AArch64). +#[derive(Copy, Clone)] +pub struct Uniform { + pub unit: Reg, + + /// The total size of the argument, which can be: + /// * equal to `unit.size` (one scalar/vector) + /// * a multiple of `unit.size` (an array of scalar/vectors) + /// * if `unit.kind` is `Integer`, the last element + /// can be shorter, i.e. `{ i64, i64, i32 }` for + /// 64-bit integers with a total size of 20 bytes + pub total: Size, +} + +impl From for Uniform { + fn from(unit: Reg) -> Uniform { + Uniform { + unit, + total: unit.size + } + } +} + +impl Uniform { + fn llvm_type(&self, ccx: &CrateContext) -> Type { + let llunit = self.unit.llvm_type(ccx); + + if self.total <= self.unit.size { + return llunit; + } + + let count = self.total.bytes() / self.unit.size.bytes(); + let rem_bytes = self.total.bytes() % self.unit.size.bytes(); + + if rem_bytes == 0 { + return Type::array(&llunit, count); + } + + // Only integers can be really split further. + assert_eq!(self.unit.kind, RegKind::Integer); + + let args: Vec<_> = (0..count).map(|_| llunit) + .chain(iter::once(Type::ix(ccx, rem_bytes * 8))) + .collect(); + + Type::struct_(ccx, &args, false) + } +} + +pub trait LayoutExt<'tcx> { + fn is_aggregate(&self) -> bool; + fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option; +} + +impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { + fn is_aggregate(&self) -> bool { + match *self.layout { + Layout::Scalar { .. } | + Layout::RawNullablePointer { .. } | + Layout::CEnum { .. } | + Layout::Vector { .. } => false, + + Layout::Array { .. } | + Layout::FatPointer { .. } | + Layout::Univariant { .. } | + Layout::UntaggedUnion { .. } | + Layout::General { .. } | + Layout::StructWrappedNullablePointer { .. } => true + } + } + + fn homogenous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option { + match *self.layout { + // The primitives for this algorithm. + Layout::Scalar { value, .. } | + Layout::RawNullablePointer { value, .. } => { + let kind = match value { + layout::Int(_) | + layout::Pointer => RegKind::Integer, + layout::F32 | + layout::F64 => RegKind::Float + }; + Some(Reg { + kind, + size: self.size(ccx) + }) + } + + Layout::CEnum { .. } => { + Some(Reg { + kind: RegKind::Integer, + size: self.size(ccx) + }) + } + + Layout::Vector { .. } => { + Some(Reg { + kind: RegKind::Integer, + size: self.size(ccx) + }) + } + + Layout::Array { count, .. } => { + if count > 0 { + self.field(ccx, 0).homogenous_aggregate(ccx) + } else { + None + } + } + + Layout::Univariant { ref variant, .. } => { + let mut unaligned_offset = Size::from_bytes(0); + let mut result = None; + + for i in 0..self.field_count() { + if unaligned_offset != variant.offsets[i] { + return None; + } + + let field = self.field(ccx, i); + match (result, field.homogenous_aggregate(ccx)) { + // The field itself must be a homogenous aggregate. + (_, None) => return None, + // If this is the first field, record the unit. + (None, Some(unit)) => { + result = Some(unit); + } + // For all following fields, the unit must be the same. + (Some(prev_unit), Some(unit)) => { + if prev_unit != unit { + return None; + } + } + } + + // Keep track of the offset (without padding). + let size = field.size(ccx); + match unaligned_offset.checked_add(size, ccx) { + Some(offset) => unaligned_offset = offset, + None => return None + } + } + + // There needs to be no padding. + if unaligned_offset != self.size(ccx) { + None + } else { + result + } + } + + Layout::UntaggedUnion { .. } => { + let mut max = Size::from_bytes(0); + let mut result = None; + + for i in 0..self.field_count() { + let field = self.field(ccx, i); + match (result, field.homogenous_aggregate(ccx)) { + // The field itself must be a homogenous aggregate. + (_, None) => return None, + // If this is the first field, record the unit. + (None, Some(unit)) => { + result = Some(unit); + } + // For all following fields, the unit must be the same. + (Some(prev_unit), Some(unit)) => { + if prev_unit != unit { + return None; + } + } + } + + // Keep track of the offset (without padding). + let size = field.size(ccx); + if size > max { + max = size; + } + } + + // There needs to be no padding. + if max != self.size(ccx) { + None + } else { + result + } + } + + // Rust-specific types, which we can ignore for C ABIs. + Layout::FatPointer { .. } | + Layout::General { .. } | + Layout::StructWrappedNullablePointer { .. } => None + } + } +} + +pub enum CastTarget { + Uniform(Uniform), + Pair(Reg, Reg) +} + +impl From for CastTarget { + fn from(unit: Reg) -> CastTarget { + CastTarget::Uniform(Uniform::from(unit)) + } +} + +impl From for CastTarget { + fn from(uniform: Uniform) -> CastTarget { + CastTarget::Uniform(uniform) + } +} + +impl CastTarget { + fn llvm_type(&self, ccx: &CrateContext) -> Type { + match *self { + CastTarget::Uniform(u) => u.llvm_type(ccx), + CastTarget::Pair(a, b) => { + Type::struct_(ccx, &[ + a.llvm_type(ccx), + b.llvm_type(ccx) + ], false) + } + } + } +} /// Information about how a specific C type /// should be passed to or returned from a function /// /// This is borrowed from clang's ABIInfo.h #[derive(Clone, Copy, Debug)] -pub struct ArgType { +pub struct ArgType<'tcx> { kind: ArgKind, - /// Original LLVM type - pub original_ty: Type, - /// Sizing LLVM type (pointers are opaque). - /// Unlike original_ty, this is guaranteed to be complete. - /// - /// For example, while we're computing the function pointer type in - /// `struct Foo(fn(Foo));`, `original_ty` is still LLVM's `%Foo = {}`. - /// The field type will likely end up being `void(%Foo)*`, but we cannot - /// use `%Foo` to compute properties (e.g. size and alignment) of `Foo`, - /// until `%Foo` is completed by having all of its field types inserted, - /// so `ty` holds the "sizing type" of `Foo`, which replaces all pointers - /// with opaque ones, resulting in `{i8*}` for `Foo`. - /// ABI-specific logic can then look at the size, alignment and fields of - /// `{i8*}` in order to determine how the argument will be passed. - /// Only later will `original_ty` aka `%Foo` be used in the LLVM function - /// pointer type, without ever having introspected it. - pub ty: Type, - /// Signedness for integer types, None for other types - pub signedness: Option, + pub layout: TyLayout<'tcx>, /// Coerced LLVM Type pub cast: Option, /// Dummy argument, which is emitted before the real argument @@ -167,26 +428,24 @@ pub struct ArgType { pub attrs: ArgAttributes } -impl ArgType { - fn new(original_ty: Type, ty: Type) -> ArgType { +impl<'a, 'tcx> ArgType<'tcx> { + fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> { ArgType { kind: ArgKind::Direct, - original_ty: original_ty, - ty: ty, - signedness: None, + layout: layout, cast: None, pad: None, attrs: ArgAttributes::default() } } - pub fn make_indirect(&mut self, ccx: &CrateContext) { + pub fn make_indirect(&mut self, ccx: &CrateContext<'a, 'tcx>) { assert_eq!(self.kind, ArgKind::Direct); // Wipe old attributes, likely not valid through indirection. self.attrs = ArgAttributes::default(); - let llarg_sz = llsize_of_alloc(ccx, self.ty); + let llarg_sz = self.layout.size(ccx).bytes(); // For non-immediate arguments the callee gets its own copy of // the value on the stack, so there are no aliases. It's also @@ -205,17 +464,44 @@ impl ArgType { pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness - if let Some(signed) = self.signedness { - if self.ty.int_width() < bits { - self.attrs.set(if signed { - ArgAttribute::SExt - } else { - ArgAttribute::ZExt - }); + let (i, signed) = match *self.layout { + Layout::Scalar { value, .. } => { + match value { + layout::Int(i) => { + if self.layout.ty.is_integral() { + (i, self.layout.ty.is_signed()) + } else { + return; + } + } + _ => return + } } + + // Rust enum types that map onto C enums also need to follow + // the target ABI zero-/sign-extension rules. + Layout::CEnum { discr, signed, .. } => (discr, signed), + + _ => return + }; + + if i.size().bits() < bits { + self.attrs.set(if signed { + ArgAttribute::SExt + } else { + ArgAttribute::ZExt + }); } } + pub fn cast_to>(&mut self, ccx: &CrateContext, target: T) { + self.cast = Some(target.into().llvm_type(ccx)); + } + + pub fn pad_with(&mut self, ccx: &CrateContext, reg: Reg) { + self.pad = Some(reg.llvm_type(ccx)); + } + pub fn is_indirect(&self) -> bool { self.kind == ArgKind::Indirect } @@ -224,18 +510,24 @@ impl ArgType { self.kind == ArgKind::Ignore } + /// Get the LLVM type for an lvalue of the original Rust type of + /// this argument/return, i.e. the result of `type_of::type_of`. + pub fn memory_ty(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { + type_of::type_of(ccx, self.layout.ty) + } + /// Store a direct/indirect value described by this ArgType into a /// lvalue 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. - pub fn store(&self, bcx: &Builder, mut val: ValueRef, dst: ValueRef) { + pub fn store(&self, bcx: &Builder<'a, 'tcx>, mut val: ValueRef, dst: ValueRef) { if self.is_ignore() { return; } let ccx = bcx.ccx; if self.is_indirect() { - let llsz = llsize_of(ccx, self.ty); - let llalign = llalign_of_min(ccx, self.ty); + let llsz = C_uint(ccx, self.layout.size(ccx).bytes()); + let llalign = self.layout.align(ccx).abi(); base::call_memcpy(bcx, dst, val, llsz, llalign as u32); } else if let Some(ty) = self.cast { // FIXME(eddyb): Figure out when the simpler Store is safe, clang @@ -243,8 +535,8 @@ impl ArgType { let can_store_through_cast_ptr = false; if can_store_through_cast_ptr { let cast_dst = bcx.pointercast(dst, ty.ptr_to()); - let llalign = llalign_of_min(ccx, self.ty); - bcx.store(val, cast_dst, Some(llalign)); + let llalign = self.layout.align(ccx).abi(); + bcx.store(val, cast_dst, Some(llalign as u32)); } else { // The actual return type is a struct, but the ABI // adaptation code has cast it into some scalar type. The @@ -271,21 +563,21 @@ impl ArgType { base::call_memcpy(bcx, bcx.pointercast(dst, Type::i8p(ccx)), bcx.pointercast(llscratch, Type::i8p(ccx)), - C_uint(ccx, llsize_of_alloc(ccx, self.ty)), - cmp::min(llalign_of_min(ccx, self.ty), - llalign_of_min(ccx, ty)) as u32); + C_uint(ccx, self.layout.size(ccx).bytes()), + cmp::min(self.layout.align(ccx).abi() as u32, + llalign_of_min(ccx, ty))); base::Lifetime::End.call(bcx, llscratch); } } else { - if self.original_ty == Type::i1(ccx) { + if self.layout.ty == ccx.tcx().types.bool { val = bcx.zext(val, Type::i8(ccx)); } bcx.store(val, dst, None); } } - pub fn store_fn_arg(&self, bcx: &Builder, idx: &mut usize, dst: ValueRef) { + pub fn store_fn_arg(&self, bcx: &Builder<'a, 'tcx>, idx: &mut usize, dst: ValueRef) { if self.pad.is_some() { *idx += 1; } @@ -304,30 +596,30 @@ impl ArgType { /// I will do my best to describe this structure, but these /// comments are reverse-engineered and may be inaccurate. -NDM #[derive(Clone, Debug)] -pub struct FnType { +pub struct FnType<'tcx> { /// The LLVM types of each argument. - pub args: Vec, + pub args: Vec>, /// LLVM return type. - pub ret: ArgType, + pub ret: ArgType<'tcx>, pub variadic: bool, pub cconv: llvm::CallConv } -impl FnType { - pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType { +impl<'a, 'tcx> FnType<'tcx> { + pub fn new(ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); fn_ty.adjust_for_abi(ccx, sig); fn_ty } - pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType { + pub fn new_vtable(ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); // Don't pass the vtable, it's not an argument of the virtual fn. fn_ty.args[1].ignore(); @@ -335,9 +627,9 @@ impl FnType { fn_ty } - fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType { + pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { use self::Abi::*; let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | @@ -394,23 +686,11 @@ impl FnType { }; let arg_of = |ty: Ty<'tcx>, is_return: bool| { + let mut arg = ArgType::new(ccx.layout_of(ty)); if ty.is_bool() { - let llty = Type::i1(ccx); - let mut arg = ArgType::new(llty, llty); arg.attrs.set(ArgAttribute::ZExt); - arg } else { - let mut arg = ArgType::new(type_of::type_of(ccx, ty), - type_of::sizing_type_of(ccx, ty)); - if ty.is_integral() { - arg.signedness = Some(ty.is_signed()); - } - // Rust enum types that map onto C enums also need to follow - // the target ABI zero-/sign-extension rules. - if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) { - arg.signedness = Some(signed); - } - if llsize_of_alloc(ccx, arg.ty) == 0 { + if arg.layout.size(ccx).bytes() == 0 { // 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. @@ -419,8 +699,8 @@ impl FnType { arg.ignore(); } } - arg } + arg }; let ret_ty = sig.output(); @@ -491,13 +771,9 @@ impl FnType { for ty in inputs.iter().chain(extra_args.iter()) { let mut arg = arg_of(ty, false); - if type_is_fat_ptr(ccx, ty) { - let original_tys = arg.original_ty.field_types(); - let sizing_tys = arg.ty.field_types(); - assert_eq!((original_tys.len(), sizing_tys.len()), (2, 2)); - - let mut data = ArgType::new(original_tys[0], sizing_tys[0]); - let mut info = ArgType::new(original_tys[1], sizing_tys[1]); + if let ty::layout::FatPointer { .. } = *arg.layout { + let mut data = ArgType::new(arg.layout.field(ccx, 0)); + let mut info = ArgType::new(arg.layout.field(ccx, 1)); if let Some(inner) = rust_ptr_attrs(ty, &mut data) { data.attrs.set(ArgAttribute::NonNull); @@ -527,43 +803,51 @@ impl FnType { } } - fn adjust_for_abi<'a, 'tcx>(&mut self, - ccx: &CrateContext<'a, 'tcx>, - sig: ty::FnSig<'tcx>) { + fn adjust_for_abi(&mut self, + ccx: &CrateContext<'a, 'tcx>, + sig: ty::FnSig<'tcx>) { let abi = sig.abi; if abi == Abi::Unadjusted { return } if abi == Abi::Rust || abi == Abi::RustCall || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType| { - let mut llty = arg.ty; - - // Replace newtypes with their inner-most type. - while llty.kind() == llvm::TypeKind::Struct { - let inner = llty.field_types(); - if inner.len() != 1 { - break; - } - llty = inner[0]; - } - - if !llty.is_aggregate() { - // Scalars and vectors, always immediate. - if llty != arg.ty { - // Needs a cast as we've unpacked a newtype. - arg.cast = Some(llty); - } + let fixup = |arg: &mut ArgType<'tcx>| { + if !arg.layout.is_aggregate() { return; } - let size = llsize_of_alloc(ccx, llty); - if size > llsize_of_alloc(ccx, ccx.int_type()) { + let size = arg.layout.size(ccx); + + if let Some(unit) = arg.layout.homogenous_aggregate(ccx) { + // Replace newtypes with their inner-most type. + if unit.size == size { + // Needs a cast as we've unpacked a newtype. + arg.cast_to(ccx, unit); + return; + } + + // Pairs of floats. + if unit.kind == RegKind::Float { + if unit.size.checked_mul(2, ccx) == Some(size) { + // FIXME(eddyb) This should be using Uniform instead of a pair, + // but the resulting [2 x float/double] breaks emscripten. + // See https://github.com/kripken/emscripten-fastcomp/issues/178. + arg.cast_to(ccx, CastTarget::Pair(unit, unit)); + return; + } + } + } + + if size > layout::Pointer.size(ccx) { arg.make_indirect(ccx); - } else if size > 0 { + } 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 = Some(Type::ix(ccx, size * 8)); + arg.cast_to(ccx, Reg { + kind: RegKind::Integer, + size + }); } }; // Fat pointers are returned by-value. @@ -599,14 +883,7 @@ impl FnType { cabi_x86_64::compute_abi_info(ccx, self); }, "aarch64" => cabi_aarch64::compute_abi_info(ccx, self), - "arm" => { - let flavor = if ccx.sess().target.target.target_os == "ios" { - cabi_arm::Flavor::Ios - } else { - cabi_arm::Flavor::General - }; - cabi_arm::compute_abi_info(ccx, self, flavor); - }, + "arm" => cabi_arm::compute_abi_info(ccx, self), "mips" => cabi_mips::compute_abi_info(ccx, self), "mips64" => cabi_mips64::compute_abi_info(ccx, self), "powerpc" => cabi_powerpc::compute_abi_info(ccx, self), @@ -627,16 +904,18 @@ impl FnType { } } - pub fn llvm_type(&self, ccx: &CrateContext) -> Type { + pub fn llvm_type(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { let mut llargument_tys = Vec::new(); let llreturn_ty = if self.ret.is_ignore() { Type::void(ccx) } else if self.ret.is_indirect() { - llargument_tys.push(self.ret.original_ty.ptr_to()); + llargument_tys.push(self.ret.memory_ty(ccx).ptr_to()); Type::void(ccx) } else { - self.ret.cast.unwrap_or(self.ret.original_ty) + self.ret.cast.unwrap_or_else(|| { + type_of::immediate_type_of(ccx, self.ret.layout.ty) + }) }; for arg in &self.args { @@ -649,9 +928,11 @@ impl FnType { } let llarg_ty = if arg.is_indirect() { - arg.original_ty.ptr_to() + arg.memory_ty(ccx).ptr_to() } else { - arg.cast.unwrap_or(arg.original_ty) + arg.cast.unwrap_or_else(|| { + type_of::immediate_type_of(ccx, arg.layout.ty) + }) }; llargument_tys.push(llarg_ty); @@ -699,72 +980,6 @@ impl FnType { } } -pub fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - -fn align(off: usize, ty: Type, pointer: usize) -> usize { - let a = ty_align(ty, pointer); - return align_up_to(off, a); -} - -pub fn ty_align(ty: Type, pointer: usize) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => pointer, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t, pointer))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt, pointer) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ty_align(elt, pointer) * len - } - _ => bug!("ty_align: unhandled type") - } -} - -pub fn ty_size(ty: Type, pointer: usize) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => pointer, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t, pointer)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| { - align(s, *t, pointer) + ty_size(*t, pointer) - }); - align(size, ty, pointer) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, pointer); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, pointer); - len * eltsz - }, - _ => bug!("ty_size: unhandled type") - } +pub fn align_up_to(off: u64, a: u64) -> u64 { + (off + a - 1) / a * a } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index b15acfb591ca..0fe180253b5b 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -95,15 +95,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { generic_type_of(cx, t, None, false, false) } - -// Pass dst=true if the type you are passing is a DST. Yes, we could figure -// this out, but if you call this on an unsized type without realising it, you -// are going to get the wrong type (it will not include the unsized parts of it). -pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, dst: bool) -> Type { - generic_type_of(cx, t, None, true, dst) -} - pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, name: &str) -> Type { generic_type_of(cx, t, Some(name), false, false) @@ -149,7 +140,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; let nnty = monomorphize::field_ty(cx.tcx(), substs, &def.variants[nndiscr as usize].fields[0]); - type_of::sizing_type_of(cx, nnty) + if let layout::Scalar { value: layout::Pointer, .. } = *cx.layout_of(nnty) { + Type::i8p(cx) + } else { + type_of::type_of(cx, nnty) + } } layout::StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => { let fields = compute_fields(cx, t, nndiscr as usize, false); @@ -181,10 +176,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } - layout::Vector { element, count } => { - let elem_ty = Type::from_primitive(cx, element); - Type::vector(&elem_ty, count) - } layout::UntaggedUnion { ref variants, .. }=> { // Use alignment-sized ints to fill all the union storage. let size = variants.stride().bytes(); @@ -258,11 +249,10 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type { fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec>, variant: &layout::Struct, - sizing: bool, dst: bool) -> Vec { + sizing: bool, _dst: bool) -> Vec { let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]); if sizing { - fields.filter(|ty| !dst || cx.shared().type_is_sized(*ty)) - .map(|ty| type_of::sizing_type_of(cx, ty)).collect() + bug!() } else { fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect() } diff --git a/src/librustc_trans/cabi_aarch64.rs b/src/librustc_trans/cabi_aarch64.rs index 59a84439950b..c8c5af714d92 100644 --- a/src/librustc_trans/cabi_aarch64.rs +++ b/src/librustc_trans/cabi_aarch64.rs @@ -8,163 +8,99 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{self, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; use context::CrateContext; -use type_::Type; -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) -} +fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) + -> Option { + arg.layout.homogenous_aggregate(ccx).and_then(|unit| { + let size = arg.layout.size(ccx); -fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { - fn check_array(ty: Type) -> Option<(Type, u64)> { - let len = ty.array_length() as u64; - if len == 0 { - return None - } - let elt = ty.element_type(); - - // if our element is an HFA/HVA, so are we; multiply members by our len - is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) - } - - fn check_struct(ty: Type) -> Option<(Type, u64)> { - let str_tys = ty.field_types(); - if str_tys.len() == 0 { - return None + // Ensure we have at most four uniquely addressable members. + if size > unit.size.checked_mul(4, ccx).unwrap() { + return None; } - let mut prev_base_ty = None; - let mut members = 0; - for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { - match (prev_base_ty, opt_homog_agg) { - // field isn't itself an HFA, so we aren't either - (_, None) => return None, + let valid_unit = match unit.kind { + RegKind::Integer => false, + RegKind::Float => true, + RegKind::Vector => size.bits() == 64 || size.bits() == 128 + }; - // first field - store its type and number of members - (None, Some((field_ty, field_members))) => { - prev_base_ty = Some(field_ty); - members = field_members; - }, - - // 2nd or later field - give up if it's a different type; otherwise incr. members - (Some(prev_ty), Some((field_ty, field_members))) => { - if prev_ty != field_ty { - return None; - } - members += field_members; - } - } - } - - // Because of previous checks, we know prev_base_ty is Some(...) because - // 1. str_tys has at least one element; and - // 2. prev_base_ty was filled in (or we would've returned early) - let (base_ty, members) = (prev_base_ty.unwrap(), members); - - // Ensure there is no padding. - if ty_size(ty) == ty_size(base_ty) * (members as usize) { - Some((base_ty, members)) - } else { - None - } - } - - let homog_agg = match ty.kind() { - Float => Some((ty, 1)), - Double => Some((ty, 1)), - Array => check_array(ty), - Struct => check_struct(ty), - Vector => match ty_size(ty) { - 4|8 => Some((ty, 1)), - _ => None - }, - _ => None - }; - - // Ensure we have at most four uniquely addressable members - homog_agg.and_then(|(base_ty, members)| { - if members > 0 && members <= 4 { - Some((base_ty, members)) + if valid_unit { + Some(Uniform { + unit, + total: size + }) } else { None } }) } -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { - ret.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, ret) { + ret.cast_to(ccx, uniform); return; } - let size = ty_size(ret.ty); - if size <= 16 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + Reg::i64() }; - ret.cast = Some(llty); + + ret.cast_to(ccx, Uniform { + unit, + total: size + }); return; } ret.make_indirect(ccx); } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { - arg.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, arg) { + arg.cast_to(ccx, uniform); return; } - let size = ty_size(arg.ty); - if size <= 16 { - let llty = if size == 0 { - Type::array(&Type::i64(ccx), 0) - } else if size == 1 { - Type::i8(ccx) - } else if size == 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) + let size = arg.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + Reg::i64() }; - arg.cast = Some(llty); + + arg.cast_to(ccx, Uniform { + unit, + total: size + }); return; } arg.make_indirect(ccx); } -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - } -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs index 85b26074bae6..7a91cad511d6 100644 --- a/src/librustc_trans/cabi_arm.rs +++ b/src/librustc_trans/cabi_arm.rs @@ -8,156 +8,53 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{self, align_up_to, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; -use std::cmp; - -pub enum Flavor { - General, - Ios -} - -type TyAlignFn = fn(ty: Type) -> usize; - -fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize { - let a = align_fn(ty); - return align_up_to(off, a); -} - -fn general_ty_align(ty: Type) -> usize { - abi::ty_align(ty, 4) -} - -// For more information see: -// ARMv7 -// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual -// /iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html -// ARMv6 -// https://developer.apple.com/library/ios/documentation/Xcode/Conceptual -// /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html -fn ios_ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => cmp::min(4, ((ty.int_width() as usize) + 7) / 8), - Pointer => 4, - Float => 4, - Double => 4, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ios_ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ios_ty_align(elt) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ios_ty_align(elt) * len - } - _ => bug!("ty_align: unhandled type") - } -} - -fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter() - .fold(0, |s, t| { - align(s, *t, align_fn) + ty_size(*t, align_fn) - }); - align(size, ty, align_fn) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, align_fn); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt, align_fn); - len * eltsz - } - _ => bug!("ty_size: unhandled type") - } -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); return; } - let size = ty_size(ret.ty, align_fn); - if size <= 4 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 32 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() } else { - Type::i32(ccx) + Reg::i32() }; - ret.cast = Some(llty); + ret.cast_to(ccx, Uniform { + unit, + total: size + }); return; } ret.make_indirect(ccx); } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; } - let align = align_fn(arg.ty); - let size = ty_size(arg.ty, align_fn); - let llty = if align <= 4 { - Type::array(&Type::i32(ccx), ((size + 3) / 4) as u64) - } else { - Type::array(&Type::i64(ccx), ((size + 7) / 8) as u64) - }; - arg.cast = Some(llty); + let align = arg.layout.align(ccx).abi(); + let total = arg.layout.size(ccx); + arg.cast_to(ccx, Uniform { + unit: if align <= 4 { Reg::i32() } else { Reg::i64() }, + total + }); } -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - } -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { - let align_fn = match flavor { - Flavor::General => general_ty_align as TyAlignFn, - Flavor::Ios => ios_ty_align as TyAlignFn, - }; - +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { - classify_ret_ty(ccx, &mut fty.ret, align_fn); + classify_ret_ty(ccx, &mut fty.ret); } for arg in &mut fty.args { if arg.is_ignore() { continue; } - classify_arg_ty(ccx, arg, align_fn); + classify_arg_ty(ccx, arg); } } diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_trans/cabi_asmjs.rs index f410627400c3..f05dda8bce21 100644 --- a/src/librustc_trans/cabi_asmjs.rs +++ b/src/librustc_trans/cabi_asmjs.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use llvm::{Struct, Array}; -use abi::{FnType, ArgType, ArgAttribute}; +use abi::{FnType, ArgType, ArgAttribute, LayoutExt, Uniform}; use context::CrateContext; // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128 @@ -19,31 +16,31 @@ use context::CrateContext; // See the https://github.com/kripken/emscripten-fastcomp-clang repository. // The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions. -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - match ret.ty.kind() { - Struct => { - let field_types = ret.ty.field_types(); - if field_types.len() == 1 { - ret.cast = Some(field_types[0]); - } else { - ret.make_indirect(ccx); +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() { + if let Some(unit) = ret.layout.homogenous_aggregate(ccx) { + let size = ret.layout.size(ccx); + if unit.size == size { + ret.cast_to(ccx, Uniform { + unit, + total: size + }); + return; } } - Array => { - ret.make_indirect(ccx); - } - _ => {} + + ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.is_aggregate() { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() { arg.make_indirect(ccx); arg.attrs.set(ArgAttribute::ByVal); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_trans/cabi_mips.rs index 25fe53e7ef40..b7b60859d4a0 100644 --- a/src/librustc_trans/cabi_mips.rs +++ b/src/librustc_trans/cabi_mips.rs @@ -8,94 +8,40 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use libc::c_uint; use std::cmp; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, ArgType, FnType}; +use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; -fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 4) -} - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 4) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i32(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i32()); + } } else { arg.extend_integer_width_to(32); } + + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - }; -} - -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); - let mut args = Vec::new(); - - let mut n = size / 32; - while n > 0 { - args.push(int_ty); - n -= 1; - } - - let r = size % 32; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); - } - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs index e6b500c88dc7..dff75e628de1 100644 --- a/src/librustc_trans/cabi_mips64.rs +++ b/src/librustc_trans/cabi_mips64.rs @@ -8,94 +8,40 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use libc::c_uint; use std::cmp; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, ArgType, FnType}; +use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; -fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 8) -} - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i64(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i64()); + } } else { arg.extend_integer_width_to(64); } + + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - }; -} - -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i64(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i64(ccx); - let mut args = Vec::new(); - - let mut n = size / 64; - while n > 0 { - args.push(int_ty); - n -= 1; - } - - let r = size % 64; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); - } - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_msp430.rs b/src/librustc_trans/cabi_msp430.rs index aa90bb7ab753..546bb5ad9b44 100644 --- a/src/librustc_trans/cabi_msp430.rs +++ b/src/librustc_trans/cabi_msp430.rs @@ -11,17 +11,8 @@ // Reference: MSP430 Embedded Application Binary Interface // http://www.ti.com/lit/an/slaa534/slaa534.pdf -#![allow(non_upper_case_globals)] - -use llvm::Struct; - -use abi::{self, ArgType, FnType}; +use abi::{ArgType, FnType, LayoutExt}; use context::CrateContext; -use type_::Type; - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 2) -} // 3.5 Structures or Unions Passed and Returned by Reference // @@ -29,23 +20,23 @@ fn ty_size(ty: Type) -> usize { // returned by reference. To pass a structure or union by reference, the caller // places its address in the appropriate location: either in a register or on // the stack, according to its position in the argument list. (..)" -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 { ret.make_indirect(ccx); } else { ret.extend_integer_width_to(16); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 { arg.make_indirect(ccx); } else { arg.extend_integer_width_to(16); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_nvptx.rs b/src/librustc_trans/cabi_nvptx.rs index 5ece19f764a8..3873752b2547 100644 --- a/src/librustc_trans/cabi_nvptx.rs +++ b/src/librustc_trans/cabi_nvptx.rs @@ -11,35 +11,26 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -#![allow(non_upper_case_globals)] - -use llvm::Struct; - -use abi::{self, ArgType, FnType}; +use abi::{ArgType, FnType, LayoutExt}; use context::CrateContext; -use type_::Type; -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 4) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 32 { ret.make_indirect(ccx); } else { ret.extend_integer_width_to(32); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 32 { arg.make_indirect(ccx); } else { arg.extend_integer_width_to(32); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_nvptx64.rs b/src/librustc_trans/cabi_nvptx64.rs index 880c6cfd7a8a..24bf4920c16c 100644 --- a/src/librustc_trans/cabi_nvptx64.rs +++ b/src/librustc_trans/cabi_nvptx64.rs @@ -11,35 +11,26 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -#![allow(non_upper_case_globals)] - -use llvm::Struct; - -use abi::{self, ArgType, FnType}; +use abi::{ArgType, FnType, LayoutExt}; use context::CrateContext; -use type_::Type; -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if ret.ty.kind() == Struct && ty_size(ret.ty) > 64 { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 64 { ret.make_indirect(ccx); } else { ret.extend_integer_width_to(64); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct && ty_size(arg.ty) > 64 { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 64 { arg.make_indirect(ccx); } else { arg.extend_integer_width_to(64); } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs index 4e1d7a933782..f951ac76391f 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_trans/cabi_powerpc.rs @@ -8,100 +8,41 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::c_uint; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, FnType, ArgType}; +use abi::{align_up_to, FnType, ArgType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; use std::cmp; -fn ty_align(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_align(ty, 4) - } -} - -fn ty_size(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_size(ty, 4) - } -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i32(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i32()); + } } else { arg.extend_integer_width_to(32); } + + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double => true, - _ => false - }; -} - -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); - let mut args = Vec::new(); - - let mut n = size / 32; - while n > 0 { - args.push(int_ty); - n -= 1; - } - - let r = size % 32; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); - } - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_trans/cabi_powerpc64.rs index cdc7c1fd1afb..c4f8d0b4b963 100644 --- a/src/librustc_trans/cabi_powerpc64.rs +++ b/src/librustc_trans/cabi_powerpc64.rs @@ -8,100 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: The PowerPC64 ABI needs to zero or sign extend function -// call parameters, but compute_abi_info() is passed LLVM types -// which have no sign information. -// +// FIXME: // Alignment of 128 bit types is not currently handled, this will // need to be fixed when PowerPC vector support is added. -use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array}; -use abi::{self, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; use context::CrateContext; -use type_::Type; -fn ty_size(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_size(ty, 8) - } -} +fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) + -> Option { + arg.layout.homogenous_aggregate(ccx).and_then(|unit| { + let size = arg.layout.size(ccx); -fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { - fn check_array(ty: Type) -> Option<(Type, u64)> { - let len = ty.array_length() as u64; - if len == 0 { - return None - } - let elt = ty.element_type(); - - // if our element is an HFA/HVA, so are we; multiply members by our len - is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) - } - - fn check_struct(ty: Type) -> Option<(Type, u64)> { - let str_tys = ty.field_types(); - if str_tys.len() == 0 { - return None + // Ensure we have at most eight uniquely addressable members. + if size > unit.size.checked_mul(8, ccx).unwrap() { + return None; } - let mut prev_base_ty = None; - let mut members = 0; - for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { - match (prev_base_ty, opt_homog_agg) { - // field isn't itself an HFA, so we aren't either - (_, None) => return None, + let valid_unit = match unit.kind { + RegKind::Integer => false, + RegKind::Float => true, + RegKind::Vector => size.bits() == 128 + }; - // first field - store its type and number of members - (None, Some((field_ty, field_members))) => { - prev_base_ty = Some(field_ty); - members = field_members; - }, - - // 2nd or later field - give up if it's a different type; otherwise incr. members - (Some(prev_ty), Some((field_ty, field_members))) => { - if prev_ty != field_ty { - return None; - } - members += field_members; - } - } - } - - // Because of previous checks, we know prev_base_ty is Some(...) because - // 1. str_tys has at least one element; and - // 2. prev_base_ty was filled in (or we would've returned early) - let (base_ty, members) = (prev_base_ty.unwrap(), members); - - // Ensure there is no padding. - if ty_size(ty) == ty_size(base_ty) * (members as usize) { - Some((base_ty, members)) - } else { - None - } - } - - let homog_agg = match ty.kind() { - Float => Some((ty, 1)), - Double => Some((ty, 1)), - Array => check_array(ty), - Struct => check_struct(ty), - _ => None - }; - - // Ensure we have at most eight uniquely addressable members - homog_agg.and_then(|(base_ty, members)| { - if members > 0 && members <= 8 { - Some((base_ty, members)) + if valid_unit { + Some(Uniform { + unit, + total: size + }) } else { None } }) } -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); return; } @@ -111,78 +53,52 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { ret.make_indirect(ccx); } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { - ret.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, ret) { + ret.cast_to(ccx, uniform); return; } - let size = ty_size(ret.ty); - if size <= 16 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) + Reg::i64() }; - ret.cast = Some(llty); + + ret.cast_to(ccx, Uniform { + unit, + total: size + }); return; } ret.make_indirect(ccx); } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { - arg.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, arg) { + arg.cast_to(ccx, uniform); return; } - arg.cast = Some(struct_ty(ccx, arg.ty)); + let total = arg.layout.size(ccx); + arg.cast_to(ccx, Uniform { + unit: Reg::i64(), + total + }); } -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double => true, - _ => false - } -} - -fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec { - let long_ty = Type::i64(ccx); - let mut args = Vec::new(); - - let mut n = size / 64; - while n > 0 { - args.push(long_ty); - n -= 1; - } - - let r = size % 64; - if r > 0 { - args.push(Type::ix(ccx, r as u64)); - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_long(ccx, size), false) -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_trans/cabi_s390x.rs index 5a666c6083d1..fedebea3f4c9 100644 --- a/src/librustc_trans/cabi_s390x.rs +++ b/src/librustc_trans/cabi_s390x.rs @@ -11,130 +11,60 @@ // FIXME: The assumes we're using the non-vector ABI, i.e. compiling // for a pre-z13 machine or using -mno-vx. -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{align_up_to, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg}; use context::CrateContext; -use type_::Type; -use std::cmp; +use rustc::ty::layout::{self, Layout, TyLayout}; -fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return align_up_to(off, a); -} - -fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - Vector => ty_size(ty), - _ => bug!("ty_align: unhandled type") - } -} - -fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - _ => bug!("ty_size: unhandled type") - } -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() && ret.layout.size(ccx).bits() <= 64 { ret.extend_integer_width_to(64); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if arg.ty.kind() == Struct { - fn is_single_fp_element(tys: &[Type]) -> bool { - if tys.len() != 1 { - return false; - } - match tys[0].kind() { - Float | Double => true, - Struct => is_single_fp_element(&tys[0].field_types()), - _ => false +fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + layout: TyLayout<'tcx>) -> bool { + match *layout { + Layout::Scalar { value: layout::F32, .. } | + Layout::Scalar { value: layout::F64, .. } => true, + Layout::Univariant { .. } => { + if layout.field_count() == 1 { + is_single_fp_element(ccx, layout.field(ccx, 0)) + } else { + false } } - - if is_single_fp_element(&arg.ty.field_types()) { - match ty_size(arg.ty) { - 4 => arg.cast = Some(Type::f32(ccx)), - 8 => arg.cast = Some(Type::f64(ccx)), - _ => arg.make_indirect(ccx) - } - } else { - match ty_size(arg.ty) { - 1 => arg.cast = Some(Type::i8(ccx)), - 2 => arg.cast = Some(Type::i16(ccx)), - 4 => arg.cast = Some(Type::i32(ccx)), - 8 => arg.cast = Some(Type::i64(ccx)), - _ => arg.make_indirect(ccx) - } - } - return; - } - - if is_reg_ty(arg.ty) { - arg.extend_integer_width_to(64); - } else { - arg.make_indirect(ccx); - } -} - -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double => ty_size(ty) <= 8, _ => false } } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + let size = arg.layout.size(ccx); + if !arg.layout.is_aggregate() && size.bits() <= 64 { + arg.extend_integer_width_to(64); + return; + } + + if is_single_fp_element(ccx, arg.layout) { + match size.bytes() { + 4 => arg.cast_to(ccx, Reg::f32()), + 8 => arg.cast_to(ccx, Reg::f64()), + _ => arg.make_indirect(ccx) + } + } else { + match size.bytes() { + 1 => arg.cast_to(ccx, Reg::i8()), + 2 => arg.cast_to(ccx, Reg::i16()), + 4 => arg.cast_to(ccx, Reg::i32()), + 8 => arg.cast_to(ccx, Reg::i64()), + _ => arg.make_indirect(ccx) + } + } +} + +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_sparc.rs b/src/librustc_trans/cabi_sparc.rs index 25fe53e7ef40..c17901e1adeb 100644 --- a/src/librustc_trans/cabi_sparc.rs +++ b/src/librustc_trans/cabi_sparc.rs @@ -8,94 +8,40 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_upper_case_globals)] - -use libc::c_uint; use std::cmp; -use llvm; -use llvm::{Integer, Pointer, Float, Double, Vector}; -use abi::{self, align_up_to, ArgType, FnType}; +use abi::{align_up_to, ArgType, FnType, LayoutExt, Reg, Uniform}; use context::CrateContext; -use type_::Type; -fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 4) -} - -fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 4) -} - -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(ccx); } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { - let orig_offset = *offset; - let size = ty_size(arg.ty) * 8; - let mut align = ty_align(arg.ty); - +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut u64) { + let size = arg.layout.size(ccx); + let mut align = arg.layout.align(ccx).abi(); align = cmp::min(cmp::max(align, 4), 8); - *offset = align_up_to(*offset, align); - *offset += align_up_to(size, align * 8) / 8; - if !is_reg_ty(arg.ty) { - arg.cast = Some(struct_ty(ccx, arg.ty)); - arg.pad = padding_ty(ccx, align, orig_offset); - } else { - arg.extend_integer_width_to(32); - } -} - -fn is_reg_ty(ty: Type) -> bool { - return match ty.kind() { - Integer - | Pointer - | Float - | Double - | Vector => true, - _ => false - }; -} - -fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { - if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) - } else { - None - } -} - -fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); - let mut args = Vec::new(); - - let mut n = size / 32; - while n > 0 { - args.push(int_ty); - n -= 1; - } - - let r = size % 32; - if r > 0 { - unsafe { - args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); + if arg.layout.is_aggregate() { + arg.cast_to(ccx, Uniform { + unit: Reg::i32(), + total: size + }); + if ((align - 1) & *offset) > 0 { + arg.pad_with(ccx, Reg::i32()); } + } else { + arg.extend_integer_width_to(32) } - args + *offset = align_up_to(*offset, align); + *offset += align_up_to(size.bytes(), align); } -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_int(ccx, size), false) -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_sparc64.rs b/src/librustc_trans/cabi_sparc64.rs index e675cca33d1b..b75fa97f948e 100644 --- a/src/librustc_trans/cabi_sparc64.rs +++ b/src/librustc_trans/cabi_sparc64.rs @@ -10,170 +10,89 @@ // FIXME: This needs an audit for correctness and completeness. -use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array}; -use abi::{self, FnType, ArgType}; +use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; use context::CrateContext; -use type_::Type; -fn ty_size(ty: Type) -> usize { - if ty.kind() == Vector { - bug!("ty_size: unhandled type") - } else { - abi::ty_size(ty, 8) - } -} +fn is_homogenous_aggregate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) + -> Option { + arg.layout.homogenous_aggregate(ccx).and_then(|unit| { + let size = arg.layout.size(ccx); -fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { - fn check_array(ty: Type) -> Option<(Type, u64)> { - let len = ty.array_length() as u64; - if len == 0 { - return None - } - let elt = ty.element_type(); - - // if our element is an HFA/HVA, so are we; multiply members by our len - is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) - } - - fn check_struct(ty: Type) -> Option<(Type, u64)> { - let str_tys = ty.field_types(); - if str_tys.len() == 0 { - return None + // Ensure we have at most eight uniquely addressable members. + if size > unit.size.checked_mul(8, ccx).unwrap() { + return None; } - let mut prev_base_ty = None; - let mut members = 0; - for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { - match (prev_base_ty, opt_homog_agg) { - // field isn't itself an HFA, so we aren't either - (_, None) => return None, + let valid_unit = match unit.kind { + RegKind::Integer => false, + RegKind::Float => true, + RegKind::Vector => size.bits() == 128 + }; - // first field - store its type and number of members - (None, Some((field_ty, field_members))) => { - prev_base_ty = Some(field_ty); - members = field_members; - }, - - // 2nd or later field - give up if it's a different type; otherwise incr. members - (Some(prev_ty), Some((field_ty, field_members))) => { - if prev_ty != field_ty { - return None; - } - members += field_members; - } - } - } - - // Because of previous checks, we know prev_base_ty is Some(...) because - // 1. str_tys has at least one element; and - // 2. prev_base_ty was filled in (or we would've returned early) - let (base_ty, members) = (prev_base_ty.unwrap(), members); - - // Ensure there is no padding. - if ty_size(ty) == ty_size(base_ty) * (members as usize) { - Some((base_ty, members)) - } else { - None - } - } - - let homog_agg = match ty.kind() { - Float => Some((ty, 1)), - Double => Some((ty, 1)), - Array => check_array(ty), - Struct => check_struct(ty), - _ => None - }; - - // Ensure we have at most eight uniquely addressable members - homog_agg.and_then(|(base_ty, members)| { - if members > 0 && members <= 8 { - Some((base_ty, members)) + if valid_unit { + Some(Uniform { + unit, + total: size + }) } else { None } }) } -fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { - if is_reg_ty(ret.ty) { +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); return; } + if let Some(uniform) = is_homogenous_aggregate(ccx, ret) { + ret.cast_to(ccx, uniform); + return; + } + let size = ret.layout.size(ccx); + let bits = size.bits(); + if bits <= 128 { + let unit = if bits <= 8 { + Reg::i8() + } else if bits <= 16 { + Reg::i16() + } else if bits <= 32 { + Reg::i32() + } else { + Reg::i64() + }; + + ret.cast_to(ccx, Uniform { + unit, + total: size + }); + return; + } + // don't return aggregates in registers ret.make_indirect(ccx); - - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) { - ret.cast = Some(Type::array(&base_ty, members)); - return; - } - let size = ty_size(ret.ty); - if size <= 16 { - let llty = if size <= 1 { - Type::i8(ccx) - } else if size <= 2 { - Type::i16(ccx) - } else if size <= 4 { - Type::i32(ccx) - } else if size <= 8 { - Type::i64(ccx) - } else { - Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) - }; - ret.cast = Some(llty); - return; - } } -fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { - if is_reg_ty(arg.ty) { +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; } - if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) { - arg.cast = Some(Type::array(&base_ty, members)); + if let Some(uniform) = is_homogenous_aggregate(ccx, arg) { + arg.cast_to(ccx, uniform); return; } - arg.cast = Some(struct_ty(ccx, arg.ty)); + let total = arg.layout.size(ccx); + arg.cast_to(ccx, Uniform { + unit: Reg::i64(), + total + }); } -fn is_reg_ty(ty: Type) -> bool { - match ty.kind() { - Integer - | Pointer - | Float - | Double => true, - _ => false - } -} - -fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec { - let long_ty = Type::i64(ccx); - let mut args = Vec::new(); - - let mut n = size / 64; - while n > 0 { - args.push(long_ty); - n -= 1; - } - - let r = size % 64; - if r > 0 { - args.push(Type::ix(ccx, r as u64)); - } - - args -} - -fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { - let size = ty_size(ty) * 8; - Type::struct_(ccx, &coerce_to_long(ccx, size), false) -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { if !fty.ret.is_ignore() { classify_ret_ty(ccx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs index fea005f3d77d..9f5520dabe33 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_trans/cabi_x86.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::*; -use abi::{ArgAttribute, FnType}; -use type_::Type; -use super::common::*; -use super::machine::*; +use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind}; +use common::CrateContext; #[derive(PartialEq)] pub enum Flavor { @@ -20,9 +17,11 @@ pub enum Flavor { Fastcall } -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + fty: &mut FnType<'tcx>, + flavor: Flavor) { if !fty.ret.is_ignore() { - if fty.ret.ty.kind() == Struct { + if fty.ret.layout.is_aggregate() { // Returning a structure. Most often, this will use // a hidden first argument. On some platforms, though, // small structs are returned as integers. @@ -33,11 +32,12 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { let t = &ccx.sess().target.target; if t.options.is_like_osx || t.options.is_like_windows || t.options.is_like_openbsd { - match llsize_of_alloc(ccx, fty.ret.ty) { - 1 => fty.ret.cast = Some(Type::i8(ccx)), - 2 => fty.ret.cast = Some(Type::i16(ccx)), - 4 => fty.ret.cast = Some(Type::i32(ccx)), - 8 => fty.ret.cast = Some(Type::i64(ccx)), + let size = fty.ret.layout.size(ccx); + match size.bytes() { + 1 => fty.ret.cast_to(ccx, Reg::i8()), + 2 => fty.ret.cast_to(ccx, Reg::i16()), + 4 => fty.ret.cast_to(ccx, Reg::i32()), + 8 => fty.ret.cast_to(ccx, Reg::i64()), _ => fty.ret.make_indirect(ccx) } } else { @@ -50,7 +50,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { for arg in &mut fty.args { if arg.is_ignore() { continue; } - if arg.ty.kind() == Struct { + if arg.layout.is_aggregate() { arg.make_indirect(ccx); arg.attrs.set(ArgAttribute::ByVal); } else { @@ -73,12 +73,15 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { for arg in &mut fty.args { if arg.is_ignore() || arg.is_indirect() { continue; } - if arg.ty.kind() == Float { + // At this point we know this must be a primitive of sorts. + let unit = arg.layout.homogenous_aggregate(ccx).unwrap(); + let size = arg.layout.size(ccx); + assert_eq!(unit.size, size); + if unit.kind == RegKind::Float { continue; } - let size = llbitsize_of_real(ccx, arg.ty); - let size_in_regs = (size + 31) / 32; + let size_in_regs = (size.bits() + 31) / 32; if size_in_regs == 0 { continue; @@ -90,7 +93,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) { free_regs -= size_in_regs; - if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) { + if size.bits() <= 32 && unit.kind == RegKind::Integer { arg.attrs.set(ArgAttribute::InReg); } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 7f2fdbf000b6..cbe170d85834 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -11,388 +11,250 @@ // The classification code for the x86_64 ABI is taken from the clay language // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp -#![allow(non_upper_case_globals)] -use self::RegClass::*; - -use llvm::{Integer, Pointer, Float, Double}; -use llvm::{Struct, Array, Vector}; -use abi::{self, ArgType, ArgAttribute, FnType}; +use abi::{ArgType, ArgAttribute, CastTarget, FnType, LayoutExt, Reg, RegKind}; use context::CrateContext; -use type_::Type; -#[derive(Clone, Copy, PartialEq)] -enum RegClass { - NoClass, +use rustc::ty::layout::{self, Layout, TyLayout, Size}; + +#[derive(Clone, Copy, PartialEq, Debug)] +enum Class { + None, Int, - SSEFs, - SSEFv, - SSEDs, - SSEDv, - SSEInt(/* bitwidth */ u64), - /// Data that can appear in the upper half of an SSE register. - SSEUp, - X87, - X87Up, - ComplexX87, - Memory + Sse, + SseUp } -trait TypeMethods { - fn is_reg_ty(&self) -> bool; -} +#[derive(Clone, Copy, Debug)] +struct Memory; -impl TypeMethods for Type { - fn is_reg_ty(&self) -> bool { - match self.kind() { - Integer | Pointer | Float | Double => true, - _ => false - } - } -} +// Currently supported vector size (AVX). +const LARGEST_VECTOR_SIZE: usize = 256; +const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64; -impl RegClass { - fn is_sse(&self) -> bool { - match *self { - SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true, - _ => false - } - } -} +fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>) + -> Result<[Class; MAX_EIGHTBYTES], Memory> { + fn unify(cls: &mut [Class], + off: u64, + c: Class) { + let i = (off / 8) as usize; + let to_write = match (cls[i], c) { + (Class::None, _) => c, + (_, Class::None) => return, -trait ClassList { - fn is_pass_byval(&self) -> bool; - fn is_ret_bysret(&self) -> bool; -} + (Class::Int, _) | + (_, Class::Int) => Class::Int, -impl ClassList for [RegClass] { - fn is_pass_byval(&self) -> bool { - if self.is_empty() { return false; } + (Class::Sse, _) | + (_, Class::Sse) => Class::Sse, - let class = self[0]; - class == Memory - || class == X87 - || class == ComplexX87 - } - - fn is_ret_bysret(&self) -> bool { - if self.is_empty() { return false; } - - self[0] == Memory - } -} - -fn classify_ty(ty: Type) -> Vec { - fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return (off + a - 1) / a * a; - } - - fn ty_align(ty: Type) -> usize { - abi::ty_align(ty, 8) - } - - fn ty_size(ty: Type) -> usize { - abi::ty_size(ty, 8) - } - - fn all_mem(cls: &mut [RegClass]) { - for elt in cls { - *elt = Memory; - } - } - - fn unify(cls: &mut [RegClass], - i: usize, - newv: RegClass) { - if cls[i] == newv { return } - - let to_write = match (cls[i], newv) { - (NoClass, _) => newv, - (_, NoClass) => return, - - (Memory, _) | - (_, Memory) => Memory, - - (Int, _) | - (_, Int) => Int, - - (X87, _) | - (X87Up, _) | - (ComplexX87, _) | - (_, X87) | - (_, X87Up) | - (_, ComplexX87) => Memory, - - (SSEFv, SSEUp) | - (SSEFs, SSEUp) | - (SSEDv, SSEUp) | - (SSEDs, SSEUp) | - (SSEInt(_), SSEUp) => return, - - (..) => newv + (Class::SseUp, Class::SseUp) => Class::SseUp }; cls[i] = to_write; } - fn classify_struct(tys: &[Type], - cls: &mut [RegClass], - i: usize, - off: usize, - packed: bool) { - let mut field_off = off; - for ty in tys { - if !packed { - field_off = align(field_off, *ty); + fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + layout: TyLayout<'tcx>, + cls: &mut [Class], + off: u64) + -> Result<(), Memory> { + if off % layout.align(ccx).abi() != 0 { + if layout.size(ccx).bytes() > 0 { + return Err(Memory); } - classify(*ty, cls, i, field_off); - field_off += ty_size(*ty); - } - } - - fn classify(ty: Type, - cls: &mut [RegClass], ix: usize, - off: usize) { - let t_align = ty_align(ty); - let t_size = ty_size(ty); - - let misalign = off % t_align; - if misalign != 0 { - let mut i = off / 8; - let e = (off + t_size + 7) / 8; - while i < e { - unify(cls, ix + i, Memory); - i += 1; - } - return; + return Ok(()); } - match ty.kind() { - Integer | - Pointer => { - unify(cls, ix + off / 8, Int); - } - Float => { - if off % 8 == 4 { - unify(cls, ix + off / 8, SSEFv); - } else { - unify(cls, ix + off / 8, SSEFs); - } - } - Double => { - unify(cls, ix + off / 8, SSEDs); - } - Struct => { - classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed()); - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - let mut i = 0; - while i < len { - classify(elt, cls, ix, off + i * eltsz); - i += 1; - } - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - let mut reg = match elt.kind() { - Integer => SSEInt(elt.int_width()), - Float => SSEFv, - Double => SSEDv, - _ => bug!("classify: unhandled vector element type") + match *layout { + Layout::Scalar { value, .. } | + Layout::RawNullablePointer { value, .. } => { + let reg = match value { + layout::Int(_) | + layout::Pointer => Class::Int, + layout::F32 | + layout::F64 => Class::Sse }; + unify(cls, off, reg); + } - let mut i = 0; - while i < len { - unify(cls, ix + (off + i * eltsz) / 8, reg); + Layout::CEnum { .. } => { + unify(cls, off, Class::Int); + } - // everything after the first one is the upper - // half of a register. - reg = SSEUp; - i += 1; + Layout::Vector { element, count } => { + unify(cls, off, Class::Sse); + + // everything after the first one is the upper + // half of a register. + let eltsz = element.size(ccx).bytes(); + for i in 1..count { + unify(cls, off + i * eltsz, Class::SseUp); } } - _ => bug!("classify: unhandled type") - } - } - fn fixup(ty: Type, cls: &mut [RegClass]) { - let mut i = 0; - let ty_kind = ty.kind(); - let e = cls.len(); - if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) { - if cls[i].is_sse() { - i += 1; - while i < e { - if cls[i] != SSEUp { - all_mem(cls); - return; + Layout::Array { count, .. } => { + if count > 0 { + let elt = layout.field(ccx, 0); + let eltsz = elt.size(ccx).bytes(); + for i in 0..count { + classify(ccx, elt, cls, off + i * eltsz)?; } - i += 1; - } - } else { - all_mem(cls); - return - } - } else { - while i < e { - if cls[i] == Memory { - all_mem(cls); - return; - } - if cls[i] == X87Up { - // for darwin - // cls[i] = SSEDs; - all_mem(cls); - return; - } - if cls[i] == SSEUp { - cls[i] = SSEDv; - } else if cls[i].is_sse() { - i += 1; - while i != e && cls[i] == SSEUp { i += 1; } - } else if cls[i] == X87 { - i += 1; - while i != e && cls[i] == X87Up { i += 1; } - } else { - i += 1; } } + + Layout::Univariant { ref variant, .. } => { + for i in 0..layout.field_count() { + let field_off = off + variant.offsets[i].bytes(); + classify(ccx, layout.field(ccx, i), cls, field_off)?; + } + } + + Layout::UntaggedUnion { .. } => { + for i in 0..layout.field_count() { + classify(ccx, layout.field(ccx, i), cls, off)?; + } + } + + Layout::FatPointer { .. } | + Layout::General { .. } | + Layout::StructWrappedNullablePointer { .. } => return Err(Memory) } + + Ok(()) } - let words = (ty_size(ty) + 7) / 8; - let mut cls = vec![NoClass; words]; - if words > 4 { - all_mem(&mut cls); - return cls; - } - classify(ty, &mut cls, 0, 0); - fixup(ty, &mut cls); - return cls; -} - -fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type { - fn llvec_len(cls: &[RegClass]) -> usize { - let mut len = 1; - for c in cls { - if *c != SSEUp { - break; - } - len += 1; - } - return len; + let n = ((arg.layout.size(ccx).bytes() + 7) / 8) as usize; + if n > MAX_EIGHTBYTES { + return Err(Memory); } - let mut tys = Vec::new(); - let mut i = 0; - let e = cls.len(); - while i < e { - match cls[i] { - Int => { - tys.push(Type::i64(ccx)); - } - SSEFv | SSEDv | SSEInt(_) => { - let (elts_per_word, elt_ty) = match cls[i] { - SSEFv => (2, Type::f32(ccx)), - SSEDv => (1, Type::f64(ccx)), - SSEInt(bits) => { - assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64, - "llreg_ty: unsupported SSEInt width {}", bits); - (64 / bits, Type::ix(ccx, bits)) - } - _ => bug!(), - }; - let vec_len = llvec_len(&cls[i + 1..]); - let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word); - tys.push(vec_ty); - i += vec_len; - continue; - } - SSEFs => { - tys.push(Type::f32(ccx)); - } - SSEDs => { - tys.push(Type::f64(ccx)); - } - _ => bug!("llregtype: unhandled class") + let mut cls = [Class::None; MAX_EIGHTBYTES]; + classify(ccx, arg.layout, &mut cls, 0)?; + if n > 2 { + if cls[0] != Class::Sse { + return Err(Memory); + } + if cls[1..n].iter().any(|&c| c != Class::SseUp) { + return Err(Memory); } - i += 1; - } - if tys.len() == 1 && tys[0].kind() == Vector { - // if the type contains only a vector, pass it as that vector. - tys[0] } else { - Type::struct_(ccx, &tys, false) - } -} - -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { - fn x86_64_ty(ccx: &CrateContext, - arg: &mut ArgType, - is_mem_cls: F, - ind_attr: Option) - where F: FnOnce(&[RegClass]) -> bool - { - if !arg.ty.is_reg_ty() { - let cls = classify_ty(arg.ty); - if is_mem_cls(&cls) { - arg.make_indirect(ccx); - if let Some(attr) = ind_attr { - arg.attrs.set(attr); - } + let mut i = 0; + while i < n { + if cls[i] == Class::SseUp { + cls[i] = Class::Sse; + } else if cls[i] == Class::Sse { + i += 1; + while i != n && cls[i] == Class::SseUp { i += 1; } } else { - arg.cast = Some(llreg_ty(ccx, &cls)); + i += 1; } - } else { - arg.extend_integer_width_to(32); } } + Ok(cls) +} + +fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option { + if *i >= cls.len() { + return None; + } + + match cls[*i] { + Class::None => None, + Class::Int => { + *i += 1; + Some(match size { + 1 => Reg::i8(), + 2 => Reg::i16(), + 3 | + 4 => Reg::i32(), + _ => Reg::i64() + }) + } + Class::Sse => { + let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count(); + *i += vec_len; + Some(match size { + 4 => Reg::f32(), + 8 => Reg::f64(), + _ => { + Reg { + kind: RegKind::Vector, + size: Size::from_bytes(vec_len as u64 * 8) + } + } + }) + } + c => bug!("reg_component: unhandled class {:?}", c) + } +} + +fn cast_target(cls: &[Class], size: u64) -> CastTarget { + let mut i = 0; + let lo = reg_component(cls, &mut i, size).unwrap(); + let offset = i as u64 * 8; + let target = if size <= offset { + CastTarget::from(lo) + } else { + let hi = reg_component(cls, &mut i, size - offset).unwrap(); + CastTarget::Pair(lo, hi) + }; + assert_eq!(reg_component(cls, &mut i, 0), None); + target +} + +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9 let mut sse_regs = 8; // XMM0-7 - if !fty.ret.is_ignore() { - x86_64_ty(ccx, &mut fty.ret, |cls| { - if cls.is_ret_bysret() { - // `sret` parameter thus one less register available - int_regs -= 1; - true - } else { - false + let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| { + let cls = classify_arg(ccx, arg); + + let mut needed_int = 0; + let mut needed_sse = 0; + let in_mem = match cls { + Err(Memory) => true, + Ok(ref cls) if is_arg => { + for &c in cls { + match c { + Class::Int => needed_int += 1, + Class::Sse => needed_sse += 1, + _ => {} + } + } + arg.layout.is_aggregate() && + (int_regs < needed_int || sse_regs < needed_sse) } - }, None); + Ok(_) => false + }; + + if in_mem { + // `sret` / `byval` parameter thus one less integer register available + int_regs -= 1; + + arg.make_indirect(ccx); + if is_arg { + arg.attrs.set(ArgAttribute::ByVal); + } + } else { + // split into sized chunks passed individually + int_regs -= needed_int; + sse_regs -= needed_sse; + + if arg.layout.is_aggregate() { + let size = arg.layout.size(ccx).bytes(); + arg.cast_to(ccx, cast_target(cls.as_ref().unwrap(), size)) + } else { + arg.extend_integer_width_to(32); + } + } + }; + + if !fty.ret.is_ignore() { + x86_64_ty(&mut fty.ret, false); } for arg in &mut fty.args { if arg.is_ignore() { continue; } - x86_64_ty(ccx, arg, |cls| { - let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize; - let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize; - let in_mem = cls.is_pass_byval() || - int_regs < needed_int || - sse_regs < needed_sse; - if in_mem { - // `byval` parameter thus one less integer register available - int_regs -= 1; - } else { - // split into sized chunks passed individually - int_regs -= needed_int; - sse_regs -= needed_sse; - } - in_mem - }, Some(ArgAttribute::ByVal)); - - // An integer, pointer, double or float parameter - // thus the above closure passed to `x86_64_ty` won't - // get called. - match arg.ty.kind() { - Integer | Pointer => int_regs -= 1, - Double | Float => sse_regs -= 1, - _ => {} - } + x86_64_ty(arg, true); } } diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs index a849f3824738..39e728d4e4f9 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_trans/cabi_x86_win64.rs @@ -8,30 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::*; -use super::common::*; -use super::machine::*; -use abi::{ArgType, FnType}; -use type_::Type; +use abi::{ArgType, FnType, LayoutExt, Reg}; +use common::CrateContext; + +use rustc::ty::layout::Layout; // Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx -pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { - let fixup = |a: &mut ArgType| { - match a.ty.kind() { - Struct => match llsize_of_alloc(ccx, a.ty) { - 1 => a.cast = Some(Type::i8(ccx)), - 2 => a.cast = Some(Type::i16(ccx)), - 4 => a.cast = Some(Type::i32(ccx)), - 8 => a.cast = Some(Type::i64(ccx)), - _ => a.make_indirect(ccx) - }, - Integer => match llsize_of_alloc(ccx, a.ty) { - 1 ... 8 => a.extend_integer_width_to(32), - 16 => a.make_indirect(ccx), - _ => bug!(), - }, - _ => (), +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { + let fixup = |a: &mut ArgType<'tcx>| { + let size = a.layout.size(ccx); + if a.layout.is_aggregate() { + match size.bits() { + 8 => a.cast_to(ccx, Reg::i8()), + 16 => a.cast_to(ccx, Reg::i16()), + 32 => a.cast_to(ccx, Reg::i32()), + 64 => a.cast_to(ccx, Reg::i64()), + _ => a.make_indirect(ccx) + }; + } else { + if let Layout::Vector { .. } = *a.layout { + // FIXME(eddyb) there should be a size cap here + // (probably what clang calls "illegal vectors"). + } else if size.bytes() > 8 { + a.make_indirect(ccx); + } else { + a.extend_integer_width_to(32); + } } }; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 18893ce4ea9a..caec4789eddc 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let llslot = match op.val { Immediate(_) | Pair(..) => { - let llscratch = bcx.alloca(ret.original_ty, "ret"); + let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret"); self.store_operand(&bcx, llscratch, None, op); llscratch } @@ -190,7 +190,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let load = bcx.load( bcx.pointercast(llslot, cast_ty.ptr_to()), - Some(llalign_of_min(bcx.ccx, ret.ty))); + Some(ret.layout.align(bcx.ccx).abi() as u32)); load } else { let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER)); @@ -516,7 +516,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { (llargs[0], &llargs[1..]) } ReturnDest::Nothing => { - (C_undef(fn_ty.ret.original_ty.ptr_to()), &llargs[..]) + (C_undef(fn_ty.ret.memory_ty(bcx.ccx).ptr_to()), &llargs[..]) } ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => (dst, &llargs[..]), @@ -535,7 +535,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Ref(dst, Alignment::AbiAligned), ty: sig.output(), }; - self.store_return(&bcx, ret_dest, fn_ty.ret, op); + self.store_return(&bcx, ret_dest, &fn_ty.ret, op); } if let Some((_, target)) = *destination { @@ -574,7 +574,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Immediate(invokeret), ty: sig.output(), }; - self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op); + self.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op); } } else { let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle); @@ -584,7 +584,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { val: Immediate(llret), ty: sig.output(), }; - self.store_return(&bcx, ret_dest, fn_ty.ret, op); + self.store_return(&bcx, ret_dest, &fn_ty.ret, op); funclet_br(self, bcx, target); } else { bcx.unreachable(); @@ -598,7 +598,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx: &Builder<'a, 'tcx>, op: OperandRef<'tcx>, llargs: &mut Vec, - fn_ty: &FnType, + fn_ty: &FnType<'tcx>, next_idx: &mut usize, llfn: &mut Option, def: &Option>) { @@ -641,7 +641,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => { if arg.is_indirect() || arg.cast.is_some() { - let llscratch = bcx.alloca(arg.original_ty, "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); self.store_operand(bcx, llscratch, None, op); (llscratch, Alignment::AbiAligned, true) } else { @@ -653,7 +653,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't // have scary latent bugs around. - let llscratch = bcx.alloca(arg.original_ty, "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1)); (llscratch, Alignment::AbiAligned, true) } @@ -662,13 +662,13 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { if by_ref && !arg.is_indirect() { // Have to load the argument, maybe while casting it. - if arg.original_ty == Type::i1(bcx.ccx) { + if arg.layout.ty == bcx.tcx().types.bool { // We store bools as i8 so we need to truncate to i1. llval = bcx.load_range_assert(llval, 0, 2, llvm::False, None); - llval = bcx.trunc(llval, arg.original_ty); + llval = bcx.trunc(llval, Type::i1(bcx.ccx)); } else if let Some(ty) = arg.cast { llval = bcx.load(bcx.pointercast(llval, ty.ptr_to()), - align.min_with(llalign_of_min(bcx.ccx, arg.ty))); + align.min_with(arg.layout.align(bcx.ccx).abi() as u32)); } else { llval = bcx.load(llval, align.to_align()); } @@ -681,7 +681,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx: &Builder<'a, 'tcx>, operand: &mir::Operand<'tcx>, llargs: &mut Vec, - fn_ty: &FnType, + fn_ty: &FnType<'tcx>, next_idx: &mut usize, llfn: &mut Option, def: &Option>) { @@ -920,7 +920,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { fn store_return(&mut self, bcx: &Builder<'a, 'tcx>, dest: ReturnDest, - ret_ty: ArgType, + ret_ty: &ArgType<'tcx>, op: OperandRef<'tcx>) { use self::ReturnDest::*; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index cc957a4d2587..c8d15d28708f 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -53,7 +53,7 @@ pub struct MirContext<'a, 'tcx:'a> { ccx: &'a CrateContext<'a, 'tcx>, - fn_ty: FnType, + fn_ty: FnType<'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 @@ -455,6 +455,23 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, assert_eq!((meta.cast, meta.pad), (None, None)); let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint); llarg_idx += 1; + + // FIXME(eddyb) As we can't perfectly represent the data and/or + // vtable pointer in a fat pointers in Rust's typesystem, and + // because we split fat pointers into two ArgType's, they're + // not the right type so we have to cast them for now. + let pointee = match arg_ty.sty { + ty::TyRef(_, ty::TypeAndMut{ty, ..}) | + ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => ty, + ty::TyAdt(def, _) if def.is_box() => arg_ty.boxed_ty(), + _ => bug!() + }; + let data_llty = type_of::in_memory_type_of(bcx.ccx, pointee); + let meta_llty = type_of::unsized_info_ty(bcx.ccx, pointee); + + let llarg = bcx.pointercast(llarg, data_llty.ptr_to()); + let llmeta = bcx.pointercast(llmeta, meta_llty); + OperandValue::Pair(llarg, llmeta) } else { OperandValue::Immediate(llarg) diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index c459191561dd..d4ab6b078285 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -19,122 +19,6 @@ use type_::Type; use syntax::ast; - -// A "sizing type" is an LLVM type, the size and alignment of which are -// guaranteed to be equivalent to what you would get out of `type_of()`. It's -// useful because: -// -// (1) It may be cheaper to compute the sizing type than the full type if all -// you're interested in is the size and/or alignment; -// -// (2) It won't make any recursive calls to determine the structure of the -// type behind pointers. This can help prevent infinite loops for -// recursive types. For example, enum types rely on this behavior. - -pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - if let Some(t) = cx.llsizingtypes().borrow().get(&t).cloned() { - return t; - } - - debug!("sizing_type_of {:?}", t); - let _recursion_lock = cx.enter_type_of(t); - - let ptr_sizing_ty = |ty: Ty<'tcx>| { - if cx.shared().type_is_sized(ty) { - Type::i8p(cx) - } else { - Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false) - } - }; - let llsizingty = match t.sty { - _ if !cx.shared().type_is_sized(t) => { - Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false) - } - - ty::TyBool => Type::bool(cx), - ty::TyChar => Type::char(cx), - ty::TyInt(t) => Type::int_from_ty(cx, t), - ty::TyUint(t) => Type::uint_from_ty(cx, t), - ty::TyFloat(t) => Type::float_from_ty(cx, t), - ty::TyNever => Type::nil(cx), - - ty::TyRef(_, ty::TypeAndMut{ty, ..}) | - ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { - ptr_sizing_ty(ty) - } - ty::TyAdt(def, _) if def.is_box() => { - ptr_sizing_ty(t.boxed_ty()) - } - - ty::TyFnDef(..) => Type::nil(cx), - ty::TyFnPtr(_) => Type::i8p(cx), - - ty::TyArray(ty, size) => { - let llty = sizing_type_of(cx, ty); - let size = size as u64; - Type::array(&llty, size) - } - - ty::TyTuple(ref tys, _) if tys.is_empty() => { - Type::nil(cx) - } - - ty::TyAdt(..) if t.is_simd() => { - let e = t.simd_type(cx.tcx()); - if !e.is_machine() { - cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - t, e)) - } - let llet = type_of(cx, e); - let n = t.simd_size(cx.tcx()) as u64; - Type::vector(&llet, n) - } - - ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => { - adt::sizing_type_of(cx, t, false) - } - - ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | - ty::TyAnon(..) | ty::TyError => { - bug!("fictitious type {:?} in sizing_type_of()", t) - } - ty::TySlice(_) | ty::TyDynamic(..) | ty::TyStr => bug!() - }; - - debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty); - - cx.llsizingtypes().borrow_mut().insert(t, llsizingty); - - // FIXME(eddyb) Temporary sanity check for ty::layout. - let layout = cx.layout_of(t); - if !cx.shared().type_is_sized(t) { - if !layout.is_unsized() { - bug!("layout should be unsized for type `{}` / {:#?}", - t, layout); - } - - // Unsized types get turned into a fat pointer for LLVM. - return llsizingty; - } - - let r = layout.size(cx).bytes(); - let l = machine::llsize_of_alloc(cx, llsizingty); - if r != l { - bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", - r, l, t, layout); - } - - let r = layout.align(cx).abi(); - let l = machine::llalign_of_min(cx, llsizingty) as u64; - if r != l { - bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}", - r, l, t, layout); - } - - llsizingty -} - pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { match ty.sty { ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) | @@ -148,7 +32,7 @@ pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> } } -fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { +pub fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { let unsized_part = ccx.tcx().struct_tail(ty); match unsized_part.sty { ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => { @@ -197,7 +81,6 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. /// For the LLVM type of a value as a whole, see `type_of`. -/// NB: If you update this, be sure to update `sizing_type_of()` as well. pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { // Check the cache. if let Some(&llty) = cx.lltypes().borrow().get(&t) { diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index 76313b158ab1..bc84ac49da98 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -121,13 +121,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) { fn str(_: &[u8]) { } -// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly) +// CHECK: @trait_borrow({}* nonnull, {}* noalias nonnull readonly) // FIXME #25759 This should also have `nocapture` #[no_mangle] fn trait_borrow(_: &Drop) { } -// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly) +// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly) #[no_mangle] fn trait_box(_: Box) { } From f6e566185eaa4675cf2791ee69e63eb20ea01edb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 23:35:09 +0200 Subject: [PATCH 379/905] Implement Manually Drop --- src/libcore/mem.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f5cf3724d071..f4a19af02a66 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -736,3 +736,99 @@ pub fn discriminant(v: &T) -> Discriminant { } } + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// # #![feature(manually_drop)] +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +#[unstable(feature = "manually_drop", issue = "40673")] +#[allow(unions_with_drop_fields)] +pub union ManuallyDrop{ value: T } + +impl ManuallyDrop { + /// Wrap a value to be manually dropped. + #[unstable(feature = "manually_drop", issue = "40673")] + pub fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value: value } + } + + /// Extract the value from the ManuallyDrop container. + #[unstable(feature = "manually_drop", issue = "40673")] + pub fn into_inner(self) -> T { + unsafe { + self.value + } + } + + /// Manually drops the contained value. + /// + /// # Unsafety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + #[unstable(feature = "manually_drop", issue = "40673")] + pub unsafe fn drop(slot: &mut ManuallyDrop) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::Deref for ManuallyDrop { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::DerefMut for ManuallyDrop { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::fmt::Debug for ManuallyDrop { + fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { + unsafe { + fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() + } + } +} From 38713126dd8502e283aa8ec7c6b678a4c43f8c3b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 22 Mar 2017 19:11:51 +0200 Subject: [PATCH 380/905] Move away from the ad-hoc NoDrop unions --- src/libcollections/lib.rs | 1 + src/libcollections/slice.rs | 12 ++------ src/libcore/slice/sort.rs | 30 ++++++++---------- src/librustc_data_structures/array_vec.rs | 37 +++++------------------ src/librustc_data_structures/lib.rs | 1 + 5 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f..b474bd5d91af 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -44,6 +44,7 @@ #![feature(heap_api)] #![feature(inclusive_range)] #![feature(lang_items)] +#![feature(manually_drop)] #![feature(nonzero)] #![feature(pattern)] #![feature(placement_in)] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6cff315a6ccd..3069adb12e92 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1558,7 +1558,7 @@ fn insert_head(v: &mut [T], is_less: &mut F) // performance than with the 2nd method. // // All methods were benchmarked, and the 3rd showed best results. So we chose that one. - let mut tmp = NoDrop { value: ptr::read(&v[0]) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0])); // Intermediate state of the insertion process is always tracked by `hole`, which // serves two purposes: @@ -1571,13 +1571,13 @@ fn insert_head(v: &mut [T], is_less: &mut F) // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it // initially held exactly once. let mut hole = InsertionHole { - src: &mut tmp.value, + src: &mut *tmp, dest: &mut v[1], }; ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); for i in 2..v.len() { - if !is_less(&v[i], &tmp.value) { + if !is_less(&v[i], &*tmp) { break; } ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); @@ -1587,12 +1587,6 @@ fn insert_head(v: &mut [T], is_less: &mut F) } } - // Holds a value, but never drops it. - #[allow(unions_with_drop_fields)] - union NoDrop { - value: T - } - // When dropped, copies from `src` into `dest`. struct InsertionHole { src: *mut T, diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 7065fdb79fc4..6f9f2915dfe1 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -20,12 +20,6 @@ use cmp; use mem; use ptr; -/// Holds a value, but never drops it. -#[allow(unions_with_drop_fields)] -union NoDrop { - value: T -} - /// When dropped, copies from `src` into `dest`. struct CopyOnDrop { src: *mut T, @@ -49,15 +43,15 @@ fn shift_head(v: &mut [T], is_less: &mut F) // Read the first element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(1), }; ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1); for i in 2..len { - if !is_less(v.get_unchecked(i), &tmp.value) { + if !is_less(v.get_unchecked(i), &*tmp) { break; } @@ -81,15 +75,15 @@ fn shift_tail(v: &mut [T], is_less: &mut F) // Read the last element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(len - 2), }; ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1); for i in (0..len-2).rev() { - if !is_less(&tmp.value, v.get_unchecked(i)) { + if !is_less(&*tmp, v.get_unchecked(i)) { break; } @@ -403,12 +397,12 @@ fn partition(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Find the first pair of out-of-order elements. let mut l = 0; @@ -452,12 +446,12 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Now partition the slice. let mut l = 0; diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 29fbcb70756b..adb221972260 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -20,10 +20,11 @@ use std::fmt; use std::mem; use std::collections::range::RangeArgument; use std::collections::Bound::{Excluded, Included, Unbounded}; +use std::mem::ManuallyDrop; pub unsafe trait Array { type Element; - type PartialStorage: Default + Unsize<[ManuallyDrop]>; + type PartialStorage: Unsize<[ManuallyDrop]>; const LEN: usize; } @@ -66,7 +67,7 @@ impl ArrayVec { pub fn new() -> Self { ArrayVec { count: 0, - values: Default::default(), + values: unsafe { ::std::mem::uninitialized() }, } } @@ -81,7 +82,7 @@ impl ArrayVec { /// Panics when the stack vector is full. pub fn push(&mut self, el: A::Element) { let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count] = ManuallyDrop { value: el }; + arr[self.count] = ManuallyDrop::new(el); self.count += 1; } @@ -90,8 +91,8 @@ impl ArrayVec { let arr = &mut self.values as &mut [ManuallyDrop<_>]; self.count -= 1; unsafe { - let value = ptr::read(&arr[self.count]); - Some(value.value) + let value = ptr::read(&*arr[self.count]); + Some(value) } } else { None @@ -210,7 +211,7 @@ impl Iterator for Iter { fn next(&mut self) -> Option { let arr = &self.store as &[ManuallyDrop<_>]; unsafe { - self.indices.next().map(|i| ptr::read(&arr[i]).value) + self.indices.next().map(|i| ptr::read(&*arr[i])) } } @@ -233,7 +234,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value }) + self.iter.next().map(|elt| unsafe { ptr::read(&**elt) }) } fn size_hint(&self) -> (usize, Option) { @@ -295,25 +296,3 @@ impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { self.iter_mut() } } - -// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. -#[allow(unions_with_drop_fields)] -pub union ManuallyDrop { - value: T, - #[allow(dead_code)] - empty: (), -} - -impl ManuallyDrop { - fn new() -> ManuallyDrop { - ManuallyDrop { - empty: () - } - } -} - -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop::new() - } -} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index c1735b4a4ec9..72c533a74618 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -39,6 +39,7 @@ #![feature(conservative_impl_trait)] #![feature(discriminant_value)] #![feature(specialization)] +#![feature(manually_drop)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] From c94b3f1266779c595e28111e39f47e5e14a34ef2 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:13:31 +0300 Subject: [PATCH 381/905] Replace the `forget` intrinsic with ManuallyDrop less intrinsics = better life --- src/libcore/intrinsics.rs | 3 --- src/libcore/mem.rs | 7 ++++++- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 1 - 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e0a4707ff665..b02876315851 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -691,9 +691,6 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; - /// Moves a value out of scope without running drop glue. - pub fn forget(_: T) -> (); - /// 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, diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f4a19af02a66..52ccaa417bc5 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -171,7 +171,7 @@ pub use intrinsics::transmute; #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { - unsafe { intrinsics::forget(t) } + ManuallyDrop::new(t); } /// Returns the size of a type in bytes. @@ -780,12 +780,14 @@ pub union ManuallyDrop{ value: T } impl ManuallyDrop { /// Wrap a value to be manually dropped. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub fn new(value: T) -> ManuallyDrop { ManuallyDrop { value: value } } /// Extract the value from the ManuallyDrop container. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub fn into_inner(self) -> T { unsafe { self.value @@ -800,6 +802,7 @@ impl ManuallyDrop { /// now represents uninitialized data. It is up to the user of this method to ensure the /// uninitialized data is not actually used. #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] pub unsafe fn drop(slot: &mut ManuallyDrop) { ptr::drop_in_place(&mut slot.value) } @@ -808,6 +811,7 @@ impl ManuallyDrop { #[unstable(feature = "manually_drop", issue = "40673")] impl ::ops::Deref for ManuallyDrop { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { unsafe { &self.value @@ -817,6 +821,7 @@ impl ::ops::Deref for ManuallyDrop { #[unstable(feature = "manually_drop", issue = "40673")] impl ::ops::DerefMut for ManuallyDrop { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut self.value diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5e7d612d17f8..0cbc103994ad 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -188,7 +188,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, C_nil(ccx) } // Effectively no-ops - "uninit" | "forget" => { + "uninit" => { C_nil(ccx) } "needs_drop" => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 2861fd288326..cd58fcd4806d 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -124,7 +124,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), - "forget" => (1, vec![ param(0) ], tcx.mk_nil()), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, From 486345551c09612aa87155304a20e6b8de492939 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:15:59 +0300 Subject: [PATCH 382/905] into_inner to associated function --- src/libcore/mem.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 52ccaa417bc5..7be927b28ed7 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -779,6 +779,14 @@ pub union ManuallyDrop{ value: T } impl ManuallyDrop { /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` #[unstable(feature = "manually_drop", issue = "40673")] #[inline] pub fn new(value: T) -> ManuallyDrop { @@ -786,11 +794,20 @@ impl ManuallyDrop { } /// Extract the value from the ManuallyDrop container. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); + /// ``` #[unstable(feature = "manually_drop", issue = "40673")] #[inline] - pub fn into_inner(self) -> T { + pub fn into_inner(slot: ManuallyDrop) -> T { unsafe { - self.value + slot.value } } From c337b99f4cb0968481a03195d25358b484d7db22 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 2 Apr 2017 11:16:17 +0300 Subject: [PATCH 383/905] Fix test failures --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/manually-drop.md | 0 src/test/compile-fail/forget-init-unsafe.rs | 3 +-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/doc/unstable-book/src/manually-drop.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index d86766bac02a..90499f3ce859 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -113,6 +113,7 @@ - [loop_break_value](loop-break-value.md) - [macro_reexport](macro-reexport.md) - [main](main.md) +- [manually_drop](manually-drop.md) - [map_entry_recover_keys](map-entry-recover-keys.md) - [mpsc_select](mpsc-select.md) - [n16](n16.md) diff --git a/src/doc/unstable-book/src/manually-drop.md b/src/doc/unstable-book/src/manually-drop.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/compile-fail/forget-init-unsafe.rs b/src/test/compile-fail/forget-init-unsafe.rs index 521f122f8af0..48c9fda31e8c 100644 --- a/src/test/compile-fail/forget-init-unsafe.rs +++ b/src/test/compile-fail/forget-init-unsafe.rs @@ -10,10 +10,9 @@ #![feature(core_intrinsics)] -use std::intrinsics::{init, forget}; +use std::intrinsics::{init}; // Test that the `forget` and `init` intrinsics are really unsafe pub fn main() { let stuff = init::(); //~ ERROR call to unsafe function requires unsafe - forget(stuff); //~ ERROR call to unsafe function requires unsafe } From 63a291febac3ba2cb48787fed24388c2817ef4a2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 9 Apr 2017 12:00:34 -0400 Subject: [PATCH 384/905] Fix rustdoc infinitely recursing when an external crate reexports itself Previously, rustdoc's LibEmbargoVisitor unconditionally visited the child modules of an external crate. If a module re-exported its parent via 'pub use super::*', rustdoc would re-walk the parent, leading to infinite recursion. This commit makes LibEmbargoVisitor store already visited modules in an FxHashSet, ensuring that each module is only walked once. Fixes #40936 --- src/librustdoc/visit_lib.rs | 8 ++++++++ src/test/rustdoc/auxiliary/issue-40936.rs | 15 +++++++++++++++ src/test/rustdoc/issue-40936.rs | 16 ++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/issue-40936.rs create mode 100644 src/test/rustdoc/issue-40936.rs diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 852c98eb2fd5..40a6ffe9505f 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -13,6 +13,7 @@ use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty::Visibility; +use rustc::util::nodemap::FxHashSet; use std::cell::RefMut; @@ -29,6 +30,8 @@ pub struct LibEmbargoVisitor<'a, 'b: 'a, 'tcx: 'b> { access_levels: RefMut<'a, AccessLevels>, // Previous accessibility level, None means unreachable prev_level: Option, + // Keeps track of already visited modules, in case a module re-exports its parent + visited_mods: FxHashSet, } impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { @@ -38,6 +41,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { cstore: &*cx.sess().cstore, access_levels: cx.access_levels.borrow_mut(), prev_level: Some(AccessLevel::Public), + visited_mods: FxHashSet() } } @@ -62,6 +66,10 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { } pub fn visit_mod(&mut self, def_id: DefId) { + if !self.visited_mods.insert(def_id) { + return; + } + for item in self.cstore.item_children(def_id) { self.visit_item(item.def); } diff --git a/src/test/rustdoc/auxiliary/issue-40936.rs b/src/test/rustdoc/auxiliary/issue-40936.rs new file mode 100644 index 000000000000..54cc18cca23a --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-40936.rs @@ -0,0 +1,15 @@ +// 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. + +pub mod outermod { + pub mod innermod { + pub use super::*; + } +} diff --git a/src/test/rustdoc/issue-40936.rs b/src/test/rustdoc/issue-40936.rs new file mode 100644 index 000000000000..3e02eec1b9c3 --- /dev/null +++ b/src/test/rustdoc/issue-40936.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. + +// aux-build:issue-40936.rs +// build-aux-docs + +#![crate_name = "foo"] + +extern crate issue_40936; From d4aecf52dba643bf938a572d506995c5cad4602e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 9 Apr 2017 18:31:59 +0200 Subject: [PATCH 385/905] Fix block code headers parsing --- src/librustdoc/html/markdown.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1e687d63f587..dca873a85d81 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -471,20 +471,26 @@ impl LangString { for token in tokens { match token { "" => {}, - "should_panic" => { data.should_panic = true; seen_rust_tags = true; }, - "no_run" => { data.no_run = true; seen_rust_tags = true; }, - "ignore" => { data.ignore = true; seen_rust_tags = true; }, - "rust" => { data.rust = true; seen_rust_tags = true; }, - "test_harness" => { data.test_harness = true; seen_rust_tags = true; }, + "should_panic" => { + data.should_panic = true; + seen_rust_tags = seen_other_tags == false; + } + "no_run" => { data.no_run = true; seen_rust_tags = seen_other_tags == false; } + "ignore" => { data.ignore = true; seen_rust_tags = seen_other_tags == false; } + "rust" => { data.rust = true; seen_rust_tags = true; } + "test_harness" => { + data.test_harness = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + } "compile_fail" if allow_compile_fail => { data.compile_fail = true; - seen_rust_tags = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; data.no_run = true; } x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => { if let Ok(_) = x[1..].parse::() { data.error_codes.push(x.to_owned()); - seen_rust_tags = true; + seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; } else { seen_other_tags = true; } @@ -670,9 +676,10 @@ mod tests { t("test_harness", false, false, false, true, true, false, Vec::new()); t("compile_fail", false, true, false, true, false, true, Vec::new()); t("{.no_run .example}", false, true, false, true, false, false, Vec::new()); - t("{.sh .should_panic}", true, false, false, true, false, false, Vec::new()); + t("{.sh .should_panic}", true, false, false, false, false, false, Vec::new()); t("{.example .rust}", false, false, false, true, false, false, Vec::new()); t("{.test_harness .rust}", false, false, false, true, true, false, Vec::new()); + t("text, no_run", false, true, false, false, false, false, Vec::new()); } #[test] From f789d896cbb8b5622d07cf45261b11ebfee73e37 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 19 Mar 2017 11:46:56 -0400 Subject: [PATCH 386/905] Print tidy errors to stderr, prefix with 'tidy error: ', handle 'bad' state. --- src/tools/tidy/src/bins.rs | 3 +-- src/tools/tidy/src/cargo.rs | 5 ++--- src/tools/tidy/src/errors.rs | 5 ++--- src/tools/tidy/src/features.rs | 9 +++------ src/tools/tidy/src/main.rs | 9 +++++++++ src/tools/tidy/src/pal.rs | 3 +-- src/tools/tidy/src/style.rs | 6 ++---- src/tools/tidy/src/unstable_book.rs | 31 +++++++++++++---------------- 8 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index ef93b0858b02..11d5dbe736e8 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -62,8 +62,7 @@ pub fn check(path: &Path, bad: &mut bool) { }); let path_bytes = rel_path.as_os_str().as_bytes(); if output.status.success() && output.stdout.starts_with(path_bytes) { - println!("binary checked into source: {}", file.display()); - *bad = true; + tidy_error!(bad, "binary checked into source: {}", file.display()); } } }) diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index 053f0bbe3b81..c8c6cb0ee6b4 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -100,9 +100,8 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { } if !librs.contains(&format!("extern crate {}", krate)) { - println!("{} doesn't have `extern crate {}`, but Cargo.toml \ - depends on it", libfile.display(), krate); - *bad = true; + tidy_error!(bad, "{} doesn't have `extern crate {}`, but Cargo.toml \ + depends on it", libfile.display(), krate); } } } diff --git a/src/tools/tidy/src/errors.rs b/src/tools/tidy/src/errors.rs index 3a70e54ff974..5bf7c894cda6 100644 --- a/src/tools/tidy/src/errors.rs +++ b/src/tools/tidy/src/errors.rs @@ -79,11 +79,10 @@ pub fn check(path: &Path, bad: &mut bool) { continue } - println!("duplicate error code: {}", code); + tidy_error!(bad, "duplicate error code: {}", code); for &(ref file, line_num, ref line) in entries.iter() { - println!("{}:{}: {}", file.display(), line_num, line); + tidy_error!(bad, "{}:{}: {}", file.display(), line_num, line); } - *bad = true; } if !*bad { diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index e1fdc19c27d2..ad0d2fa0b363 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -77,8 +77,7 @@ pub fn check(path: &Path, bad: &mut bool) { for (i, line) in contents.lines().enumerate() { let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; + tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; let gate_test_str = "gate-test-"; @@ -126,8 +125,7 @@ pub fn check(path: &Path, bad: &mut bool) { } if gate_untested.len() > 0 { - println!("Found {} features without a gate test.", gate_untested.len()); - *bad = true; + tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len()); } if *bad { @@ -221,8 +219,7 @@ pub fn collect_lib_features(base_src_path: &Path, for (i, line) in contents.lines().enumerate() { let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; + tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; let level = if line.contains("[unstable(") { Status::Unstable diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index d0e8cf9c343d..dee37341051e 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -34,6 +34,15 @@ macro_rules! t { }) } +macro_rules! tidy_error { + ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ + use std::io::Write; + *$bad = true; + write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr"); + writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr"); + }); +} + mod bins; mod style; mod errors; diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 3808c05c6b93..cb323bd1d28c 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -126,8 +126,7 @@ fn check_cfgs(contents: &mut String, file: &Path, Ok(_) => unreachable!(), Err(i) => i + 1 }; - println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg); - *bad = true; + tidy_error!(bad, "{}:{}: platform-specific cfg: {}", file.display(), line, cfg); }; for (idx, cfg) in cfgs.into_iter() { diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2233f8c35297..081390eb93ca 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -112,8 +112,7 @@ pub fn check(path: &Path, bad: &mut bool) { let skip_length = contents.contains("ignore-tidy-linelength"); for (i, line) in contents.split("\n").enumerate() { let mut err = |msg: &str| { - println!("{}:{}: {}", file.display(), i + 1, msg); - *bad = true; + tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; if !skip_length && line.chars().count() > COLS && !long_line_is_ok(line) { @@ -138,8 +137,7 @@ pub fn check(path: &Path, bad: &mut bool) { } } if !licenseck(file, &contents) { - println!("{}: incorrect license", file.display()); - *bad = true; + tidy_error!(bad, "{}: incorrect license", file.display()); } }) } diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index c10e31077944..2d3d9e80257f 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -10,7 +10,7 @@ use std::collections::HashSet; use std::fs; -use std::io::{self, BufRead, Write}; +use std::io::{self, BufRead}; use std::path; use features::{collect_lang_features, collect_lib_features, Status}; @@ -110,29 +110,26 @@ pub fn check(path: &path::Path, bad: &mut bool) { // Check for Unstable Book section names with no corresponding SUMMARY.md link for feature_name in &unstable_book_section_file_names - &unstable_book_links { - *bad = true; - writeln!(io::stderr(), - "The Unstable Book section '{}' needs to have a link in SUMMARY.md", - feature_name) - .expect("could not write to stderr") + tidy_error!( + bad, + "The Unstable Book section '{}' needs to have a link in SUMMARY.md", + feature_name); } // Check for unstable features that don't have Unstable Book sections for feature_name in &unstable_feature_names - &unstable_book_section_file_names { - *bad = true; - writeln!(io::stderr(), - "Unstable feature '{}' needs to have a section in The Unstable Book", - feature_name) - .expect("could not write to stderr") + tidy_error!( + bad, + "Unstable feature '{}' needs to have a section in The Unstable Book", + feature_name); } // Check for Unstable Book sections that don't have a corresponding unstable feature for feature_name in &unstable_book_section_file_names - &unstable_feature_names { - *bad = true; - writeln!(io::stderr(), - "The Unstable Book has a section '{}' which doesn't correspond \ - to an unstable feature", - feature_name) - .expect("could not write to stderr") + tidy_error!( + bad, + "The Unstable Book has a section '{}' which doesn't correspond \ + to an unstable feature", + feature_name) } } From 7da12c8541c1977757f8f0e2368d3e5ef817de84 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Mar 2017 13:06:53 +1300 Subject: [PATCH 387/905] Add the RLS as a submodule --- .gitmodules | 4 ++++ rls | 1 + 2 files changed, 5 insertions(+) create mode 160000 rls diff --git a/.gitmodules b/.gitmodules index 3533f0df5d1c..4f29cef85700 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,3 +26,7 @@ [submodule "book"] path = src/doc/book url = https://github.com/rust-lang/book.git +[submodule "rls"] + path = rls + url = https://github.com/rust-lang-nursery/rls.git + diff --git a/rls b/rls new file mode 160000 index 000000000000..e24fc84bfc4b --- /dev/null +++ b/rls @@ -0,0 +1 @@ +Subproject commit e24fc84bfc4b3360a3d65d9adeab0f701140094d From c55325e0f7252d67bda60695497751b63f51931d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 17 Mar 2017 09:52:12 +1300 Subject: [PATCH 388/905] Build an RLS package as part of the dist target --- src/bootstrap/dist.rs | 93 ++++++++++++++++++++++++++++++++++++++++++- src/bootstrap/lib.rs | 15 +++++++ src/bootstrap/step.rs | 11 +++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6472b1a928ca..d2c9e248e03a 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -393,6 +393,7 @@ pub fn rust_src(build: &Build) { "man", "src", "cargo", + "rls", ]; let filter_fn = move |path: &Path| { @@ -593,6 +594,43 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { build.run(&mut cmd); } +pub fn rls(build: &Build, stage: u32, target: &str) { + println!("Dist RLS stage{} ({})", stage, target); + let compiler = Compiler::new(stage, &build.config.build); + + let src = build.src.join("rls"); + let release_num = build.rls_release_num(); + let name = format!("rls-{}", build.package_vers(&release_num)); + + let tmp = tmpdir(build); + let image = tmp.join("rls-image"); + drop(fs::remove_dir_all(&image)); + t!(fs::create_dir_all(&image)); + + // Prepare the image directory + let rls = build.cargo_out(&compiler, Mode::Tool, target) + .join(exe("rls", target)); + install(&rls, &image.join("bin"), 0o755); + let doc = image.join("share/doc/rls"); + install(&src.join("README.md"), &doc, 0o644); + install(&src.join("LICENSE-MIT"), &doc, 0o644); + install(&src.join("LICENSE-APACHE"), &doc, 0o644); + + // Generate the installer tarball + let mut cmd = Command::new("sh"); + cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=RLS-ready-to-serve.") + .arg(format!("--image-dir={}", sanitize_sh(&image))) + .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build)))) + .arg(format!("--output-dir={}", sanitize_sh(&distdir(build)))) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--component-name=rls") + .arg("--legacy-manifest-dirs=rustlib,cargo"); + build.run(&mut cmd); +} + /// Creates a combined installer for the specified target in the provided stage. pub fn extended(build: &Build, stage: u32, target: &str) { println!("Dist extended stage{} ({})", stage, target); @@ -604,6 +642,11 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let cargo_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "cargo"), target)); + let rls_installer = dist.join(format!("{}.tar.gz", + pkgname(build, "rls"))); + let analysis_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rust-analysis"), + target)); let docs_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rust-docs"), target)); @@ -631,9 +674,11 @@ pub fn extended(build: &Build, stage: u32, target: &str) { // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. - let mut input_tarballs = format!("{},{},{},{}", + let mut input_tarballs = format!("{},{},{},{},{},{}", sanitize_sh(&rustc_installer), sanitize_sh(&cargo_installer), + sanitize_sh(&rls_installer), + sanitize_sh(&analysis_installer), sanitize_sh(&docs_installer), sanitize_sh(&std_installer)); if target.contains("pc-windows-gnu") { @@ -675,6 +720,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&pkg); t!(fs::create_dir_all(pkg.join("rustc"))); t!(fs::create_dir_all(pkg.join("cargo"))); + t!(fs::create_dir_all(pkg.join("rls"))); + t!(fs::create_dir_all(pkg.join("rust-analysis"))); t!(fs::create_dir_all(pkg.join("rust-docs"))); t!(fs::create_dir_all(pkg.join("rust-std"))); @@ -682,6 +729,10 @@ pub fn extended(build: &Build, stage: u32, target: &str) { &pkg.join("rustc")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)), &pkg.join("cargo")); + cp_r(&work.join(pkgname(build, "rls")), + &pkg.join("rls")); + cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)), + &pkg.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)), &pkg.join("rust-docs")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)), @@ -689,6 +740,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755); + install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755); + install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755); @@ -702,6 +755,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { }; pkgbuild("rustc"); pkgbuild("cargo"); + pkgbuild("rls"); + pkgbuild("rust-analysis"); pkgbuild("rust-docs"); pkgbuild("rust-std"); @@ -727,6 +782,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&exe); t!(fs::create_dir_all(exe.join("rustc"))); t!(fs::create_dir_all(exe.join("cargo"))); + t!(fs::create_dir_all(exe.join("rls"))); + t!(fs::create_dir_all(exe.join("rust-analysis"))); t!(fs::create_dir_all(exe.join("rust-docs"))); t!(fs::create_dir_all(exe.join("rust-std"))); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)) @@ -735,6 +792,12 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)) .join("cargo"), &exe.join("cargo")); + cp_r(&work.join(pkgname(build, "rls")) + .join("rls"), + &exe.join("rls")); + cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)) + .join("rust-analysis"), + &exe.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)) .join("rust-docs"), &exe.join("rust-docs")); @@ -744,6 +807,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { t!(fs::remove_file(exe.join("rustc/manifest.in"))); t!(fs::remove_file(exe.join("cargo/manifest.in"))); + t!(fs::remove_file(exe.join("rls/manifest.in"))); + t!(fs::remove_file(exe.join("rust-analysis/manifest.in"))); t!(fs::remove_file(exe.join("rust-docs/manifest.in"))); t!(fs::remove_file(exe.join("rust-std/manifest.in"))); @@ -800,6 +865,26 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-var").arg("var.DocsDir") .arg("-out").arg(exe.join("DocsGroup.wxs")) .arg("-t").arg(etc.join("msi/squash-components.xsl"))); + build.run(Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rls") + .args(&heat_flags) + .arg("-cg").arg("RlsGroup") + .arg("-dr").arg("Rls") + .arg("-var").arg("var.RlsDir") + .arg("-out").arg(exe.join("RlsGroup.wxs")) + .arg("-t").arg(etc.join("msi/squash-components.xsl"))); + build.run(Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rust-analysis") + .args(&heat_flags) + .arg("-cg").arg("AnalysisGroup") + .arg("-dr").arg("Analysis") + .arg("-var").arg("var.AnalysisDir") + .arg("-out").arg(exe.join("AnalysisGroup.wxs")) + .arg("-t").arg(etc.join("msi/squash-components.xsl"))); build.run(Command::new(&heat) .current_dir(&exe) .arg("dir") @@ -840,6 +925,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-nologo") .arg("-dRustcDir=rustc") .arg("-dDocsDir=rust-docs") + .arg("-dRlsDir=rls") + .arg("-dAnalysisDir=rust-analysis") .arg("-dCargoDir=cargo") .arg("-dStdDir=rust-std") .arg("-arch").arg(&arch) @@ -857,6 +944,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { candle(&etc.join("msi/rustwelcomedlg.wxs")); candle("RustcGroup.wxs".as_ref()); candle("DocsGroup.wxs".as_ref()); + candle("RlsGroup.wxs".as_ref()); + candle("AnalysisGroup.wxs".as_ref()); candle("CargoGroup.wxs".as_ref()); candle("StdGroup.wxs".as_ref()); @@ -879,6 +968,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("rustwelcomedlg.wixobj") .arg("RustcGroup.wixobj") .arg("DocsGroup.wixobj") + .arg("RlsGroup.wixobj") + .arg("AnalysisGroup.wixobj") .arg("CargoGroup.wixobj") .arg("StdGroup.wixobj") .current_dir(&exe); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8303a40bb696..81ab2b0d1cef 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1044,6 +1044,21 @@ impl Build { panic!("failed to find version in cargo's Cargo.toml") } + /// Returns the `a.b.c` version that the RLS is at. + fn rls_release_num(&self) -> String { + let mut toml = String::new(); + t!(t!(File::open(self.src.join("rls/Cargo.toml"))).read_to_string(&mut toml)); + for line in toml.lines() { + let prefix = "version = \""; + let suffix = "\""; + if line.starts_with(prefix) && line.ends_with(suffix) { + return line[prefix.len()..line.len() - suffix.len()].to_string() + } + } + + panic!("failed to find version in the RLS's Cargo.toml") + } + /// Returns whether unstable features should be enabled for the compiler /// we're building. fn unstable_features(&self) -> bool { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 5560b5b0333c..d1581576957d 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -570,6 +570,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .host(&build.config.build) }) .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); + rules.build("tool-rls", "rls") + .host(true) + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "rls")); // ======================================================================== // Documentation targets @@ -694,6 +698,11 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .default(true) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); + rules.dist("dist-rls", "rls") + .host(true) + .only_host_build(true) + .dep(|s| s.name("tool-rls")) + .run(move |s| dist::rls(build, s.stage, s.target)); rules.dist("install", "path/to/nowhere") .dep(|s| s.name("default:dist")) .run(move |s| install::install(build, s.stage, s.target)); @@ -711,6 +720,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|d| d.name("dist-mingw")) .dep(|d| d.name("dist-docs")) .dep(|d| d.name("dist-cargo")) + .dep(|d| d.name("dist-rls")) + .dep(|d| d.name("dist-analysis")) .run(move |s| dist::extended(build, s.stage, s.target)); rules.dist("dist-sign", "hash-and-sign") From 223b280f31622e6292653c5b5a0755657e514524 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 28 Mar 2017 08:00:46 +1300 Subject: [PATCH 389/905] Reviewer changes --- rls | 2 +- src/bootstrap/dist.rs | 59 ++++------------------------ src/bootstrap/lib.rs | 26 +++--------- src/tools/build-manifest/src/main.rs | 5 +++ 4 files changed, 19 insertions(+), 73 deletions(-) diff --git a/rls b/rls index e24fc84bfc4b..88fc39bd654c 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit e24fc84bfc4b3360a3d65d9adeab0f701140094d +Subproject commit 88fc39bd654c536b4f8f1cd1fc8245706f0284ec diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d2c9e248e03a..88a3441d4201 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -40,7 +40,7 @@ fn pkgname(build: &Build, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, build.cargo_package_vers()) } else { - assert!(component.starts_with("rust")); + assert!(component.starts_with("rust") || component == "rls"); format!("{}-{}", component, build.rust_package_vers()) } } @@ -540,7 +540,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { let src = build.src.join("cargo"); let etc = src.join("src/etc"); - let release_num = build.cargo_release_num(); + let release_num = build.release_num("cargo"); let name = pkgname(build, "cargo"); let version = build.cargo_info.version(build, &release_num); @@ -599,7 +599,7 @@ pub fn rls(build: &Build, stage: u32, target: &str) { let compiler = Compiler::new(stage, &build.config.build); let src = build.src.join("rls"); - let release_num = build.rls_release_num(); + let release_num = build.release_num("rls"); let name = format!("rls-{}", build.package_vers(&release_num)); let tmp = tmpdir(build); @@ -642,8 +642,9 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let cargo_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "cargo"), target)); - let rls_installer = dist.join(format!("{}.tar.gz", - pkgname(build, "rls"))); + let rls_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rls"), + target)); let analysis_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rust-analysis"), target)); @@ -720,8 +721,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&pkg); t!(fs::create_dir_all(pkg.join("rustc"))); t!(fs::create_dir_all(pkg.join("cargo"))); - t!(fs::create_dir_all(pkg.join("rls"))); - t!(fs::create_dir_all(pkg.join("rust-analysis"))); t!(fs::create_dir_all(pkg.join("rust-docs"))); t!(fs::create_dir_all(pkg.join("rust-std"))); @@ -729,10 +728,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { &pkg.join("rustc")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)), &pkg.join("cargo")); - cp_r(&work.join(pkgname(build, "rls")), - &pkg.join("rls")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)), - &pkg.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)), &pkg.join("rust-docs")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)), @@ -740,8 +735,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755); - install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755); install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755); @@ -755,8 +748,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { }; pkgbuild("rustc"); pkgbuild("cargo"); - pkgbuild("rls"); - pkgbuild("rust-analysis"); pkgbuild("rust-docs"); pkgbuild("rust-std"); @@ -782,8 +773,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let _ = fs::remove_dir_all(&exe); t!(fs::create_dir_all(exe.join("rustc"))); t!(fs::create_dir_all(exe.join("cargo"))); - t!(fs::create_dir_all(exe.join("rls"))); - t!(fs::create_dir_all(exe.join("rust-analysis"))); t!(fs::create_dir_all(exe.join("rust-docs"))); t!(fs::create_dir_all(exe.join("rust-std"))); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)) @@ -792,12 +781,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)) .join("cargo"), &exe.join("cargo")); - cp_r(&work.join(pkgname(build, "rls")) - .join("rls"), - &exe.join("rls")); - cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)) - .join("rust-analysis"), - &exe.join("rust-analysis")); cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)) .join("rust-docs"), &exe.join("rust-docs")); @@ -807,8 +790,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { t!(fs::remove_file(exe.join("rustc/manifest.in"))); t!(fs::remove_file(exe.join("cargo/manifest.in"))); - t!(fs::remove_file(exe.join("rls/manifest.in"))); - t!(fs::remove_file(exe.join("rust-analysis/manifest.in"))); t!(fs::remove_file(exe.join("rust-docs/manifest.in"))); t!(fs::remove_file(exe.join("rust-std/manifest.in"))); @@ -865,26 +846,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-var").arg("var.DocsDir") .arg("-out").arg(exe.join("DocsGroup.wxs")) .arg("-t").arg(etc.join("msi/squash-components.xsl"))); - build.run(Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rls") - .args(&heat_flags) - .arg("-cg").arg("RlsGroup") - .arg("-dr").arg("Rls") - .arg("-var").arg("var.RlsDir") - .arg("-out").arg(exe.join("RlsGroup.wxs")) - .arg("-t").arg(etc.join("msi/squash-components.xsl"))); - build.run(Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-analysis") - .args(&heat_flags) - .arg("-cg").arg("AnalysisGroup") - .arg("-dr").arg("Analysis") - .arg("-var").arg("var.AnalysisDir") - .arg("-out").arg(exe.join("AnalysisGroup.wxs")) - .arg("-t").arg(etc.join("msi/squash-components.xsl"))); build.run(Command::new(&heat) .current_dir(&exe) .arg("dir") @@ -925,8 +886,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("-nologo") .arg("-dRustcDir=rustc") .arg("-dDocsDir=rust-docs") - .arg("-dRlsDir=rls") - .arg("-dAnalysisDir=rust-analysis") .arg("-dCargoDir=cargo") .arg("-dStdDir=rust-std") .arg("-arch").arg(&arch) @@ -944,8 +903,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { candle(&etc.join("msi/rustwelcomedlg.wxs")); candle("RustcGroup.wxs".as_ref()); candle("DocsGroup.wxs".as_ref()); - candle("RlsGroup.wxs".as_ref()); - candle("AnalysisGroup.wxs".as_ref()); candle("CargoGroup.wxs".as_ref()); candle("StdGroup.wxs".as_ref()); @@ -968,8 +925,6 @@ pub fn extended(build: &Build, stage: u32, target: &str) { .arg("rustwelcomedlg.wixobj") .arg("RustcGroup.wixobj") .arg("DocsGroup.wixobj") - .arg("RlsGroup.wixobj") - .arg("AnalysisGroup.wixobj") .arg("CargoGroup.wixobj") .arg("StdGroup.wixobj") .current_dir(&exe); @@ -1037,7 +992,7 @@ pub fn hash_and_sign(build: &Build) { cmd.arg(distdir(build)); cmd.arg(today.trim()); cmd.arg(build.rust_package_vers()); - cmd.arg(build.package_vers(&build.cargo_release_num())); + cmd.arg(build.package_vers(&build.release_num("cargo"))); cmd.arg(addr); t!(fs::create_dir_all(distdir(build))); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 81ab2b0d1cef..f9981f76ad84 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1017,7 +1017,7 @@ impl Build { /// Returns the value of `package_vers` above for Cargo fn cargo_package_vers(&self) -> String { - self.package_vers(&self.cargo_release_num()) + self.package_vers(&self.release_num("cargo")) } /// Returns the `version` string associated with this compiler for Rust @@ -1029,10 +1029,11 @@ impl Build { self.rust_info.version(self, channel::CFG_RELEASE_NUM) } - /// Returns the `a.b.c` version that Cargo is at. - fn cargo_release_num(&self) -> String { + /// Returns the `a.b.c` version that the given package is at. + fn release_num(&self, package: &str) -> String { let mut toml = String::new(); - t!(t!(File::open(self.src.join("cargo/Cargo.toml"))).read_to_string(&mut toml)); + let toml_file_name = self.src.join(&format!("{}/Cargo.toml", package)); + t!(t!(File::open(toml_file_name)).read_to_string(&mut toml)); for line in toml.lines() { let prefix = "version = \""; let suffix = "\""; @@ -1041,22 +1042,7 @@ impl Build { } } - panic!("failed to find version in cargo's Cargo.toml") - } - - /// Returns the `a.b.c` version that the RLS is at. - fn rls_release_num(&self) -> String { - let mut toml = String::new(); - t!(t!(File::open(self.src.join("rls/Cargo.toml"))).read_to_string(&mut toml)); - for line in toml.lines() { - let prefix = "version = \""; - let suffix = "\""; - if line.starts_with(prefix) && line.ends_with(suffix) { - return line[prefix.len()..line.len() - suffix.len()].to_string() - } - } - - panic!("failed to find version in the RLS's Cargo.toml") + panic!("failed to find version in {}'s Cargo.toml", package) } /// Returns whether unstable features should be enabled for the compiler diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index adddd7b7e89b..eab2dc75af8d 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -225,6 +225,7 @@ impl Builder { self.package("rust-src", &mut manifest.pkg, &["*"]); if self.rust_release == "nightly" { + self.package("rls", &mut manifest.pkg, HOSTS); self.package("rust-analysis", &mut manifest.pkg, TARGETS); } @@ -277,6 +278,10 @@ impl Builder { pkg: "rust-analysis".to_string(), target: target.to_string(), }); + extensions.push(Component { + pkg: "rls".to_string(), + target: host.to_string(), + }); } } extensions.push(Component { From 5766d526a250c92792ec877a65003d43683c94e5 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 5 Apr 2017 11:34:14 +1200 Subject: [PATCH 390/905] Remove --enable-save-analysis configure flag --- cargo | 2 +- configure | 1 - rls | 2 +- src/bootstrap/config.rs | 4 ---- src/bootstrap/config.toml.example | 3 --- src/bootstrap/dist.rs | 8 +++----- src/bootstrap/install.rs | 5 ----- src/bootstrap/lib.rs | 2 +- src/ci/run.sh | 1 - 9 files changed, 6 insertions(+), 22 deletions(-) diff --git a/cargo b/cargo index 4729175045b4..4e95c6b41eca 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 +Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 diff --git a/configure b/configure index d6dded6dc5f7..35b376d5f27b 100755 --- a/configure +++ b/configure @@ -445,7 +445,6 @@ opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" opt codegen-tests 1 "run the src/test/codegen tests" -opt save-analysis 0 "save API analysis data" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" opt locked-deps 0 "force Cargo.lock to be up to date" diff --git a/rls b/rls index 88fc39bd654c..016cbc514cf4 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 88fc39bd654c536b4f8f1cd1fc8245706f0284ec +Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 52ebf401aefd..693114d01ad9 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -74,7 +74,6 @@ pub struct Config { pub rustc_default_ar: Option, pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, - pub rust_save_analysis: bool, pub rust_dist_src: bool, pub build: String, @@ -226,7 +225,6 @@ struct Rust { optimize_tests: Option, debuginfo_tests: Option, codegen_tests: Option, - save_analysis: Option, } /// TOML representation of how each build target is configured. @@ -352,7 +350,6 @@ impl Config { set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.codegen_tests, rust.codegen_tests); - set(&mut config.rust_save_analysis, rust.save_analysis); set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); @@ -460,7 +457,6 @@ impl Config { ("LOCAL_REBUILD", self.local_rebuild), ("NINJA", self.ninja), ("CODEGEN_TESTS", self.codegen_tests), - ("SAVE_ANALYSIS", self.rust_save_analysis), ("LOCKED_DEPS", self.locked_deps), ("VENDOR", self.vendor), ("FULL_BOOTSTRAP", self.full_bootstrap), diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 6b2cc6eb6474..fad79022043e 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -234,9 +234,6 @@ # saying that the FileCheck executable is missing, you may want to disable this. #codegen-tests = true -# Flag indicating whether the API analysis data should be saved. -#save-analysis = false - # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 88a3441d4201..e786d69555a1 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -315,15 +315,12 @@ pub fn rust_src_location(build: &Build) -> PathBuf { /// Creates a tarball of save-analysis metadata, if available. pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { - if !build.config.rust_save_analysis { - return - } - + assert!(build.config.extended); println!("Dist analysis"); if compiler.host != build.config.build { println!("\tskipping, not a build host"); - return + return; } // Package save-analysis from stage1 if not doing a full bootstrap, as the @@ -595,6 +592,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { } pub fn rls(build: &Build, stage: u32, target: &str) { + assert!(build.config.extended); println!("Dist RLS stage{} ({})", stage, target); let compiler = Compiler::new(stage, &build.config.build); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 25082e3a9d09..d508616e4b1c 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -55,11 +55,6 @@ pub fn install(build: &Build, stage: u32, host: &str) { &docdir, &libdir, &mandir, &empty_dir); } - if build.config.rust_save_analysis { - install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); - } - install_sh(&build, "rustc", "rustc", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); t!(fs::remove_dir_all(&empty_dir)); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f9981f76ad84..e91664ac8aba 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -545,7 +545,7 @@ impl Build { .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); } - if self.config.rust_save_analysis && compiler.is_final_stage(self) { + if self.config.extended && compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } diff --git a/src/ci/run.sh b/src/ci/run.sh index 6c6a49ada15d..c6510120b47a 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -42,7 +42,6 @@ fi if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=nightly" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-save-analysis" if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" From 4bc7f5b52c41ffd45aaf8f27e7ec667f549011c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 6 Apr 2017 12:18:18 -0700 Subject: [PATCH 391/905] Always show end line of multiline annotations ```rust error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | 20 | impl Iterator for Recurrence { | _________^ starting here... 21 | | //~^ ERROR E0046 22 | | //~| NOTE missing `Item` in implementation 23 | | //~| NOTE `Item` from trait: `type Item;` ... | 36 | | } 37 | | } | |_________^ ...ending here: missing `Item` in implementation | = note: `Item` from trait: `type Item;` ``` instead of ```rust error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | 20 | impl Iterator for Recurrence { | ^ missing `Item` in implementation | = note: `Item` from trait: `type Item;` ``` --- src/librustc_errors/emitter.rs | 196 +++++++++++------- src/librustc_errors/snippet.rs | 13 +- src/libsyntax/test_snippet.rs | 134 ++++++++++++ .../ui/span/impl-wrong-item-for-trait.stderr | 9 +- src/test/ui/span/issue-23729.stderr | 11 +- src/test/ui/span/issue-23827.stderr | 3 +- 6 files changed, 269 insertions(+), 97 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 367b85ac726d..a52628ceb47a 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -21,6 +21,8 @@ use std::io::prelude::*; use std::io; use std::rc::Rc; use term; +use std::collections::HashMap; +use std::cmp::min; /// Emitter trait for emitting errors. pub trait Emitter { @@ -156,15 +158,6 @@ impl EmitterWriter { } let lo = cm.lookup_char_pos(span_label.span.lo); let mut hi = cm.lookup_char_pos(span_label.span.hi); - let mut is_minimized = false; - - // If the span is long multi-line, simplify down to the span of one character - let max_multiline_span_length = 8; - if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length { - hi.line = lo.line; - hi.col = CharPos(lo.col.0 + 1); - is_minimized = true; - } // Watch out for "empty spans". If we get a span like 6..6, we // want to just display a `^` at 6, so convert that to @@ -175,16 +168,7 @@ impl EmitterWriter { hi.col = CharPos(lo.col.0 + 1); } - let mut ann = Annotation { - start_col: lo.col.0, - end_col: hi.col.0, - is_primary: span_label.is_primary, - label: span_label.label.clone(), - annotation_type: AnnotationType::Singleline, - }; - if is_minimized { - ann.annotation_type = AnnotationType::Minimized; - } else if lo.line != hi.line { + let ann_type = if lo.line != hi.line { let ml = MultilineAnnotation { depth: 1, line_start: lo.line, @@ -194,8 +178,17 @@ impl EmitterWriter { is_primary: span_label.is_primary, label: span_label.label.clone(), }; - ann.annotation_type = AnnotationType::Multiline(ml.clone()); - multiline_annotations.push((lo.file.clone(), ml)); + multiline_annotations.push((lo.file.clone(), ml.clone())); + AnnotationType::Multiline(ml) + } else { + AnnotationType::Singleline + }; + let ann = Annotation { + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + label: span_label.label.clone(), + annotation_type: ann_type, }; if !ann.is_multiline() { @@ -233,9 +226,15 @@ impl EmitterWriter { max_depth = ann.depth; } add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); - for line in ann.line_start + 1..ann.line_end { + let middle = min(ann.line_start + 4, ann.line_end); + for line in ann.line_start + 1..middle { add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); } + if middle < ann.line_end - 1 { + for line in ann.line_end - 1..ann.line_end { + add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + } + } add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end()); } for file_vec in output.iter_mut() { @@ -249,16 +248,11 @@ impl EmitterWriter { file: Rc, line: &Line, width_offset: usize, - multiline_depth: usize) { + code_offset: usize) -> Vec<(usize, Style)> { let source_string = file.get_line(line.line_index - 1) .unwrap_or(""); let line_offset = buffer.num_lines(); - let code_offset = if multiline_depth == 0 { - width_offset - } else { - width_offset + multiline_depth + 1 - }; // First create the source line we will highlight. buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); @@ -286,7 +280,7 @@ impl EmitterWriter { // previous borrow of `vec` occurs here // // For this reason, we group the lines into "highlight lines" - // and "annotations lines", where the highlight lines have the `~`. + // and "annotations lines", where the highlight lines have the `^`. // Sort the annotations by (start, end col) let mut annotations = line.annotations.clone(); @@ -410,25 +404,9 @@ impl EmitterWriter { // If there are no annotations or the only annotations on this line are // MultilineLine, then there's only code being shown, stop processing. if line.annotations.is_empty() || line.annotations.iter() - .filter(|a| { - // Set the multiline annotation vertical lines to the left of - // the code in this line. - if let AnnotationType::MultilineLine(depth) = a.annotation_type { - buffer.putc(line_offset, - width_offset + depth - 1, - '|', - if a.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }); - false - } else { - true - } - }).collect::>().len() == 0 + .filter(|a| !a.is_line()).collect::>().len() == 0 { - return; + return vec![]; } // Write the colunmn separator. @@ -483,8 +461,7 @@ impl EmitterWriter { } } - // Write the vertical lines for multiline spans and for labels that are - // on a different line as the underline. + // Write the vertical lines for labels that are on a different line as the underline. // // After this we will have: // @@ -492,7 +469,7 @@ impl EmitterWriter { // | __________ // | | | // | | - // 3 | | + // 3 | // 4 | | } // | |_ for &(pos, annotation) in &annotations_position { @@ -528,16 +505,6 @@ impl EmitterWriter { style); } } - AnnotationType::MultilineLine(depth) => { - // the first line will have already be filled when we checked - // wether there were any annotations for this line. - for p in line_offset + 1..line_offset + line_len + 2 { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); - } - } _ => (), } } @@ -548,11 +515,11 @@ impl EmitterWriter { // // 2 | fn foo() { // | __________ starting here... - // | | | - // | | something about `foo` - // 3 | | - // 4 | | } - // | |_ ...ending here: test + // | | + // | something about `foo` + // 3 | + // 4 | } + // | _ ...ending here: test for &(pos, annotation) in &annotations_position { let style = if annotation.is_primary { Style::LabelPrimary @@ -591,11 +558,11 @@ impl EmitterWriter { // // 2 | fn foo() { // | ____-_____^ starting here... - // | | | - // | | something about `foo` - // 3 | | - // 4 | | } - // | |_^ ...ending here: test + // | | + // | something about `foo` + // 3 | + // 4 | } + // | _^ ...ending here: test for &(_, annotation) in &annotations_position { let (underline, style) = if annotation.is_primary { ('^', Style::UnderlinePrimary) @@ -609,6 +576,20 @@ impl EmitterWriter { style); } } + annotations_position.iter().filter_map(|&(_, annotation)| { + match annotation.annotation_type { + AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { + let style = if annotation.is_primary { + Style::LabelPrimary + } else { + Style::LabelSecondary + }; + Some((p, style)) + }, + _ => None + } + + }).collect::>() } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { @@ -902,22 +883,64 @@ impl EmitterWriter { let buffer_msg_line_offset = buffer.num_lines(); draw_col_separator_no_space(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); + // Contains the vertical lines' positions for active multiline annotations + let mut multilines = HashMap::new(); + // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { - self.render_source_line(&mut buffer, - annotated_file.file.clone(), - &annotated_file.lines[line_idx], - 3 + max_line_num_len, - annotated_file.multiline_depth); + let previous_buffer_line = buffer.num_lines(); + let width_offset = 3 + max_line_num_len; + let code_offset = if annotated_file.multiline_depth == 0 { + width_offset + } else { + width_offset + annotated_file.multiline_depth + 1 + }; + + let depths = self.render_source_line(&mut buffer, + annotated_file.file.clone(), + &annotated_file.lines[line_idx], + width_offset, + code_offset); + + let mut to_add = HashMap::new(); + + for (depth, style) in depths { + if multilines.get(&depth).is_some() { + multilines.remove(&depth); + } else { + to_add.insert(depth, style); + } + } + + // Set the multiline annotation vertical lines to the left of + // the code in this line. + for (depth, style) in &multilines { + for line in previous_buffer_line..buffer.num_lines() { + draw_multiline_line(&mut buffer, + line, + width_offset, + *depth, + *style); + } + } // check to see if we need to print out or elide lines that come between - // this annotated line and the next one + // this annotated line and the next one. if line_idx < (annotated_file.lines.len() - 1) { let line_idx_delta = annotated_file.lines[line_idx + 1].line_index - annotated_file.lines[line_idx].line_index; if line_idx_delta > 2 { let last_buffer_line_num = buffer.num_lines(); buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber); + + // Set the multiline annotation vertical lines on `...` bridging line. + for (depth, style) in &multilines { + draw_multiline_line(&mut buffer, + last_buffer_line_num, + width_offset, + *depth, + *style); + } } else if line_idx_delta == 2 { let unannotated_line = annotated_file.file .get_line(annotated_file.lines[line_idx].line_index) @@ -932,11 +955,21 @@ impl EmitterWriter { Style::LineNumber); draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len); buffer.puts(last_buffer_line_num, - 3 + max_line_num_len, + code_offset, &unannotated_line, Style::Quotation); + + for (depth, style) in &multilines { + draw_multiline_line(&mut buffer, + last_buffer_line_num, + width_offset, + *depth, + *style); + } } } + + multilines.extend(&to_add); } } @@ -1085,6 +1118,15 @@ fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { buffer.puts(line, col, "= ", Style::LineNumber); } +fn draw_multiline_line(buffer: &mut StyledBuffer, + line: usize, + offset: usize, + depth: usize, + style: Style) +{ + buffer.putc(line, offset + depth - 1, '|', style); +} + fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclusive: bool) -> bool { let extra = if inclusive { 1 diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 5debbf4d37c2..9aa4682e1afc 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -97,9 +97,6 @@ pub enum AnnotationType { /// Annotation under a single line of code Singleline, - /// Annotation under the first character of a multiline span - Minimized, - /// Annotation enclosing the first and last character of a multiline span Multiline(MultilineAnnotation), @@ -118,6 +115,9 @@ pub enum AnnotationType { /// Annotation marking the last character of a fully shown multiline span MultilineEnd(usize), /// Line at the left enclosing the lines of a fully shown multiline span + // Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4 + // and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in + // `draw_multiline_line`. MultilineLine(usize), } @@ -144,13 +144,6 @@ pub struct Annotation { } impl Annotation { - pub fn is_minimized(&self) -> bool { - match self.annotation_type { - AnnotationType::Minimized => true, - _ => false, - } - } - /// Wether this annotation is a vertical line placeholder. pub fn is_line(&self) -> bool { if let AnnotationType::MultilineLine(_) = self.annotation_type { diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index c537a0ee1664..a74f59b004bb 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -932,3 +932,137 @@ error: foo "#); } + +#[test] +fn long_snippet() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | X1 Y1 Z1 + | |____^____- starting here... + | ||____| + | | ...ending here: `X` is a good letter +5 | | 1 +6 | | 2 +7 | | 3 +... | +15 | | X2 Y2 Z2 +16 | | X3 Y3 Z3 + | |___________- ...ending here: `Y` is a good letter too + +"#); +} + +#[test] +fn long_snippet_multiple_spans() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 +1 +2 +3 + X1 Y1 Z1 +4 +5 +6 + X2 Y2 Z2 +7 +8 +9 +10 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y3", + count: 1, + }, + label: "`Y` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z2", + count: 1, + }, + label: "`Z` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ starting here... +4 | | 1 +5 | | 2 +6 | | 3 +7 | | X1 Y1 Z1 + | |_________- starting here... +8 | || 4 +9 | || 5 +10 | || 6 +11 | || X2 Y2 Z2 + | ||__________- ...ending here: `Z` is a good letter too +... | +15 | | 10 +16 | | X3 Y3 Z3 + | |_______^ ...ending here: `Y` is a good letter + +"#); +} + diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 717f5ee200c7..367af12bb6b1 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -24,8 +24,7 @@ error[E0046]: not all trait items implemented, missing: `bar` 23 | | //~^ ERROR E0046 24 | | //~| NOTE missing `bar` in implementation 25 | | const bar: u64 = 1; -26 | | //~^ ERROR E0323 -27 | | //~| NOTE does not match trait +... | 28 | | const MY_CONST: u32 = 1; 29 | | } | |_^ ...ending here: missing `bar` in implementation @@ -50,8 +49,7 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST` 34 | | //~^ ERROR E0046 35 | | //~| NOTE missing `MY_CONST` in implementation 36 | | fn bar(&self) {} -37 | | fn MY_CONST() {} -38 | | //~^ ERROR E0324 +... | 39 | | //~| NOTE does not match trait 40 | | } | |_^ ...ending here: missing `MY_CONST` in implementation @@ -76,8 +74,7 @@ error[E0046]: not all trait items implemented, missing: `bar` 45 | | //~^ ERROR E0046 46 | | //~| NOTE missing `bar` in implementation 47 | | type bar = u64; -48 | | //~^ ERROR E0325 -49 | | //~| NOTE does not match trait +... | 50 | | const MY_CONST: u32 = 1; 51 | | } | |_^ ...ending here: missing `bar` in implementation diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr index 493ca01778bc..701576ff6f47 100644 --- a/src/test/ui/span/issue-23729.stderr +++ b/src/test/ui/span/issue-23729.stderr @@ -1,8 +1,15 @@ error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | -20 | impl Iterator for Recurrence { - | ^ missing `Item` in implementation +20 | impl Iterator for Recurrence { + | _________^ starting here... +21 | | //~^ ERROR E0046 +22 | | //~| NOTE missing `Item` in implementation +23 | | //~| NOTE `Item` from trait: `type Item;` +... | +36 | | } +37 | | } + | |_________^ ...ending here: missing `Item` in implementation | = note: `Item` from trait: `type Item;` diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr index 6c1c24675301..457fed34ff1a 100644 --- a/src/test/ui/span/issue-23827.stderr +++ b/src/test/ui/span/issue-23827.stderr @@ -6,8 +6,7 @@ error[E0046]: not all trait items implemented, missing: `Output` 37 | | //~^ ERROR E0046 38 | | //~| NOTE missing `Output` in implementation 39 | | //~| NOTE `Output` from trait: `type Output;` -40 | | extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype { -41 | | Fn::call(&self, (comp,)) +... | 42 | | } 43 | | } | |_^ ...ending here: missing `Output` in implementation From a2b28be3f8f2920d39c9c87fef968d3885753ba4 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Fri, 10 Mar 2017 12:10:26 -0500 Subject: [PATCH 392/905] Reduce str transmutes, add mut versions of methods. --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/str-mut-extras.md | 8 +++++ src/libcollections/lib.rs | 1 + src/libcollections/str.rs | 9 ++++- src/libcollections/string.rs | 4 +-- src/libcore/char.rs | 3 +- src/libcore/str/mod.rs | 39 +++++++++++++++++---- src/libstd/ascii.rs | 5 ++- src/libstd/lib.rs | 1 + 9 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 src/doc/unstable-book/src/str-mut-extras.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index d86766bac02a..c077568d96e1 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -187,6 +187,7 @@ - [str_checked_slicing](str-checked-slicing.md) - [str_escape](str-escape.md) - [str_internals](str-internals.md) +- [str_mut_extras](str-mut-extras.md) - [struct_field_attributes](struct-field-attributes.md) - [structural_match](structural-match.md) - [target_feature](target-feature.md) diff --git a/src/doc/unstable-book/src/str-mut-extras.md b/src/doc/unstable-book/src/str-mut-extras.md new file mode 100644 index 000000000000..df4f35832cdc --- /dev/null +++ b/src/doc/unstable-book/src/str-mut-extras.md @@ -0,0 +1,8 @@ +# `str_mut_extras` + +The tracking issue for this feature is: [#str_mut_extras] + +[#str_mut_extras]: https://github.com/rust-lang/rust/issues/41119 + +------------------------ + diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f..b485f900094f 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -57,6 +57,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] +#![feature(str_mut_extras)] #![feature(trusted_len)] #![feature(unicode)] #![feature(unique)] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c37a4fa6b557..d04f414250ad 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -72,7 +72,7 @@ pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8_unchecked, ParseBoolError}; +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; #[stable(feature = "rust1", since = "1.0.0")] @@ -294,6 +294,13 @@ impl str { core_str::StrExt::as_bytes(self) } + /// Converts a mutable string slice to a mutable byte slice. + #[unstable(feature = "str_mut_extras", issue = "41119")] + #[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 diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 0ee4c8b8e95a..7d9d7276201b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1790,7 +1790,7 @@ impl ops::IndexMut> for String { impl ops::IndexMut for String { #[inline] fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { - unsafe { mem::transmute(&mut *self.vec) } + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -1822,7 +1822,7 @@ impl ops::Deref for String { impl ops::DerefMut for String { #[inline] fn deref_mut(&mut self) -> &mut str { - unsafe { mem::transmute(&mut *self.vec) } + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } diff --git a/src/libcore/char.rs b/src/libcore/char.rs index b27c801cf89d..98268e3813fa 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -19,6 +19,7 @@ use char_private::is_printable; use convert::TryFrom; use fmt::{self, Write}; use slice; +use str::from_utf8_unchecked_mut; use iter::FusedIterator; use mem::transmute; @@ -448,7 +449,7 @@ impl CharExt for char { code, dst.len()) }; - transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len)) + from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 352cc926994e..2ceef54ffed6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -21,8 +21,8 @@ use char; use convert::TryFrom; use fmt; use iter::{Map, Cloned, FusedIterator}; -use mem; use slice::{self, SliceIndex}; +use mem; pub mod pattern; @@ -300,6 +300,13 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { Ok(unsafe { from_utf8_unchecked(v) }) } +/// Converts a mutable slice of bytes to a mutable string slice. +#[unstable(feature = "str_mut_extras", issue = "41119")] +pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + run_utf8_validation(v)?; + 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. @@ -325,7 +332,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// str is returned. /// unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { - mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len)) + from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len)) } /// Converts a slice of bytes to a string slice without checking @@ -365,6 +372,18 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { mem::transmute(v) } +/// Converts a slice of bytes to a string slice without checking +/// that the string contains valid UTF-8; mutable version. +/// +/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information. +/// +/// [fromutf8]: fn.from_utf8_unchecked.html +#[inline(always)] +#[unstable(feature = "str_mut_extras", issue = "41119")] +pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { + mem::transmute(v) +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1474,7 +1493,6 @@ Section: Trait implementations mod traits { use cmp::Ordering; use ops; - use mem; use slice::{self, SliceIndex}; use str::eq_slice; @@ -1811,7 +1829,7 @@ mod traits { unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr().offset(self.start as isize); let len = self.end - self.start; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1859,7 +1877,7 @@ mod traits { #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr(); - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1905,7 +1923,7 @@ mod traits { unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr().offset(self.start as isize); let len = slice.len() - self.start; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1998,7 +2016,7 @@ mod traits { #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_ptr(); - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2096,6 +2114,8 @@ pub trait StrExt { fn is_char_boundary(&self, index: usize) -> bool; #[stable(feature = "core", since = "1.6.0")] fn as_bytes(&self) -> &[u8]; + #[unstable(feature = "str_mut_extras", issue = "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")] @@ -2373,6 +2393,11 @@ impl StrExt for str { unsafe { mem::transmute(self) } } + #[inline] + unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + mem::transmute(self) + } + fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { pat.into_searcher(self).next_match().map(|(i, _)| i) } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index b36253862094..4e3781ecafab 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -27,7 +27,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use mem; use ops::Range; use iter::FusedIterator; @@ -599,12 +598,12 @@ impl AsciiExt for str { } fn make_ascii_uppercase(&mut self) { - let me: &mut [u8] = unsafe { mem::transmute(self) }; + let me = unsafe { self.as_bytes_mut() }; me.make_ascii_uppercase() } fn make_ascii_lowercase(&mut self) { - let me: &mut [u8] = unsafe { mem::transmute(self) }; + let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 064144dcd681..6299a9070ae0 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -296,6 +296,7 @@ #![feature(stmt_expr_attributes)] #![feature(str_char)] #![feature(str_internals)] +#![feature(str_mut_extras)] #![feature(str_utf16)] #![feature(test, rustc_private)] #![feature(thread_local)] From 3d60bf45f42fe3ab6f6a64a983ed256d86ffdbbe Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Sun, 9 Apr 2017 19:42:01 -0400 Subject: [PATCH 393/905] Minor fix to mutex example Presumably `N` was supposed to be used in both places. --- src/libstd/sync/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index f2c178a1ad50..a27f621e6b2a 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -61,7 +61,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// let data = Arc::new(Mutex::new(0)); /// /// let (tx, rx) = channel(); -/// for _ in 0..10 { +/// for _ in 0..N { /// let (data, tx) = (data.clone(), tx.clone()); /// thread::spawn(move || { /// // The shared state can only be accessed once the lock is held. From 0867981f5e5dafa80135314fba3e989dc1bd6209 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 10 Apr 2017 05:53:10 +0200 Subject: [PATCH 394/905] Apply clippy's doc_markdown improvements to libcollections Since my last PR led to linker failure, I'm now taking much smaller steps. This only fixes some doc_markdown warnings; as they are in comments only, we shouldn't get any problems building. --- src/libcollections/btree/map.rs | 24 ++++++++++++------------ src/libcollections/enum_set.rs | 2 +- src/libcollections/lib.rs | 4 ++-- src/libcollections/range.rs | 2 +- src/libcollections/vec_deque.rs | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index dcacef4f0f0d..b30700c3f694 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -262,7 +262,7 @@ impl super::Recover for BTreeMap } } -/// An iterator over a BTreeMap's entries. +/// An iterator over a `BTreeMap`'s entries. #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { range: Range<'a, K, V>, @@ -276,7 +276,7 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Iter<'a, K, V> { } } -/// A mutable iterator over a BTreeMap's entries. +/// A mutable iterator over a `BTreeMap`'s entries. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, K: 'a, V: 'a> { @@ -284,7 +284,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { length: usize, } -/// An owning iterator over a BTreeMap's entries. +/// An owning iterator over a `BTreeMap`'s entries. #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { front: Handle, marker::Edge>, @@ -303,7 +303,7 @@ impl fmt::Debug for IntoIter { } } -/// An iterator over a BTreeMap's keys. +/// An iterator over a `BTreeMap`'s keys. #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -316,7 +316,7 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Keys<'a, K, V> { } } -/// An iterator over a BTreeMap's values. +/// An iterator over a `BTreeMap`'s values. #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -329,14 +329,14 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Values<'a, K, V> } } -/// A mutable iterator over a BTreeMap's values. +/// A mutable iterator over a `BTreeMap`'s values. #[stable(feature = "map_values_mut", since = "1.10.0")] #[derive(Debug)] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } -/// An iterator over a sub-range of BTreeMap's entries. +/// An iterator over a sub-range of `BTreeMap`'s entries. #[stable(feature = "btree_range", since = "1.17.0")] pub struct Range<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -350,7 +350,7 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> } } -/// A mutable iterator over a sub-range of BTreeMap's entries. +/// A mutable iterator over a sub-range of `BTreeMap`'s entries. #[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -378,12 +378,12 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for RangeMut<'a, K, /// [`entry`]: struct.BTreeMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { - /// A vacant Entry + /// A vacant `Entry` #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), - /// An occupied Entry + /// An occupied `Entry` #[stable(feature = "rust1", since = "1.0.0")] Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), @@ -403,7 +403,7 @@ impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { } } -/// A vacant Entry. It is part of the [`Entry`] enum. +/// A vacant `Entry`. It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] @@ -425,7 +425,7 @@ impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { } } -/// An occupied Entry. It is part of the [`Entry`] enum. +/// An occupied `Entry`. It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index e56b94b2e1ea..ebee75d1a1a6 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -215,7 +215,7 @@ impl BitXor for EnumSet { } } -/// An iterator over an EnumSet +/// An iterator over an `EnumSet` pub struct Iter { index: usize, bits: usize, diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 248c15e96f8f..79ae2d411b6f 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -10,8 +10,8 @@ //! Collection types. //! -//! See [std::collections](../std/collections/index.html) for a detailed discussion of -//! collections in Rust. +//! See [`std::collections`](../std/collections/index.html) for a detailed +//! discussion of collections in Rust. #![crate_name = "collections"] #![crate_type = "rlib"] diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 06d89a6a70b4..8f3209d015b1 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -17,7 +17,7 @@ use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; use Bound::{self, Excluded, Included, Unbounded}; -/// **RangeArgument** is implemented by Rust's built-in range types, produced +/// `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. diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 22f2ff1a3461..f1ea0010e98c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! VecDeque is a double-ended queue, which is implemented with the help of a +//! `VecDeque` is a double-ended queue, which is implemented with the help of a //! growing ring buffer. //! //! This queue has `O(1)` amortized inserts and removals from both ends of the @@ -1847,7 +1847,7 @@ fn wrap_index(index: usize, size: usize) -> usize { index & (size - 1) } -/// Returns the two slices that cover the VecDeque's valid range +/// Returns the two slices that cover the `VecDeque`'s valid range trait RingSlices: Sized { fn slice(self, from: usize, to: usize) -> Self; fn split_at(self, i: usize) -> (Self, Self); @@ -2047,7 +2047,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} -/// A by-value VecDeque iterator +/// A by-value `VecDeque` iterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -2097,7 +2097,7 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -/// A draining VecDeque iterator +/// A draining `VecDeque` iterator #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { after_tail: usize, From 1e7f3551d161ace63264b466707c0a1c5c589fb9 Mon Sep 17 00:00:00 2001 From: mandeep Date: Sun, 9 Apr 2017 23:07:18 -0500 Subject: [PATCH 395/905] Added doc comments for fmt::Result --- src/libcore/fmt/mod.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0bfab92fa5d5..8c3d3ce7d886 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -49,8 +49,31 @@ pub mod rt { pub mod v1; } -#[stable(feature = "rust1", since = "1.0.0")] /// The type returned by formatter methods. +/// +/// # Examples +/// +/// ``` +/// use std::fmt; +/// +/// #[derive(Debug)] +/// struct Triangle { +/// a: f32, +/// b: f32, +/// c: f32 +/// } +/// +/// impl fmt::Display for Triangle { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "({}, {}, {})", self.a, self.b, self.c) +/// } +/// } +/// +/// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 }; +/// +/// println!("{}", pythagorean_triple); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub type Result = result::Result<(), Error>; /// The error type which is returned from formatting a message into a stream. From 251d9be42933e4cc4660802dc449d9466f54209b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 09:53:24 -0500 Subject: [PATCH 396/905] --subsystem needs -Wl when using non-ld linkers --- src/librustc_trans/back/linker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 48e469e28ee3..61c57f00de70 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -363,7 +363,7 @@ impl<'a> Linker for GccLinker<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("--subsystem,{}", subsystem)); + self.linker_arg(&format!("--subsystem,{}", subsystem)); } fn finalize(&mut self) -> Command { From e192fb3d892f04e90a78378bd772cc003304a887 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 10 Apr 2017 09:55:52 -0500 Subject: [PATCH 397/905] explain why we have a fake cfail test --- src/test/compile-fail/feature-gate-linker-flavor.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/compile-fail/feature-gate-linker-flavor.rs b/src/test/compile-fail/feature-gate-linker-flavor.rs index 68679d7dac89..955ec39cda1e 100644 --- a/src/test/compile-fail/feature-gate-linker-flavor.rs +++ b/src/test/compile-fail/feature-gate-linker-flavor.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// This is a fake compile fail test as there's no way to generate a +// `#![feature(linker_flavor)]` error. The only reason we have a `linker_flavor` +// feature gate is to be able to document `-Z linker-flavor` in the unstable +// book + #[used] fn foo() {} //~^^ ERROR the `#[used]` attribute is an experimental feature From 12d7c3d9d8e6694b693e9ee30402063b6cef18ab Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 10 Apr 2017 17:50:54 +0200 Subject: [PATCH 398/905] Fixed indent, grammar, and link in std::hash docs --- src/libcore/hash/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 4ebec401669c..f68361e85227 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -119,12 +119,12 @@ mod sip; /// ``` /// #[derive(Hash)] /// struct Rustacean { -/// name: String, -/// country: String, +/// name: String, +/// country: String, /// } /// ``` /// -/// If you need more control over how a value is hash, you can of course +/// If you need more control over how a value is hashed, you can of course /// implement the `Hash` trait yourself: /// /// ``` @@ -378,7 +378,7 @@ pub trait Hasher { /// assert_eq!(hasher_1.finish(), hasher_2.finish()); /// ``` /// -/// [`build_hasher`]: #method.build_hasher +/// [`build_hasher`]: #tymethod.build_hasher /// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] From 1c3f34dba6a8219822a48f3db7e6f50ff04e0f78 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 10 Apr 2017 20:50:42 +0000 Subject: [PATCH 399/905] Convert HashMap to BTree in build-manifest --- src/tools/build-manifest/src/main.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index adddd7b7e89b..a7a43e6858ef 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -11,7 +11,7 @@ extern crate toml; extern crate rustc_serialize; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::env; use std::fs::File; use std::io::{self, Read, Write}; @@ -101,13 +101,13 @@ static MINGW: &'static [&'static str] = &[ struct Manifest { manifest_version: String, date: String, - pkg: HashMap, + pkg: BTreeMap, } #[derive(RustcEncodable)] struct Package { version: String, - target: HashMap, + target: BTreeMap, } #[derive(RustcEncodable)] @@ -138,7 +138,7 @@ struct Builder { input: PathBuf, output: PathBuf, gpg_passphrase: String, - digests: HashMap, + digests: BTreeMap, s3_address: String, date: String, rust_version: String, @@ -162,7 +162,7 @@ fn main() { input: input, output: output, gpg_passphrase: passphrase, - digests: HashMap::new(), + digests: BTreeMap::new(), s3_address: s3_address, date: date, rust_version: String::new(), @@ -214,7 +214,7 @@ impl Builder { let mut manifest = Manifest { manifest_version: "2".to_string(), date: self.date.to_string(), - pkg: HashMap::new(), + pkg: BTreeMap::new(), }; self.package("rustc", &mut manifest.pkg, HOSTS); @@ -230,7 +230,7 @@ impl Builder { let mut pkg = Package { version: self.cached_version("rust").to_string(), - target: HashMap::new(), + target: BTreeMap::new(), }; for host in HOSTS { let filename = self.filename("rust", host); @@ -299,7 +299,7 @@ impl Builder { fn package(&mut self, pkgname: &str, - dst: &mut HashMap, + dst: &mut BTreeMap, targets: &[&str]) { let targets = targets.iter().map(|name| { let filename = self.filename(pkgname, name); From 4c80170782c168e5aae848b2911c16921e5a2f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 9 Apr 2017 16:28:31 -0700 Subject: [PATCH 400/905] Point at only one char on `Span::next_point` Avoid pointing at two chars so the diagnostic output doesn't display a multiline span when starting beyond a line end. --- src/libsyntax/parse/parser.rs | 6 ++++-- src/libsyntax_pos/lib.rs | 2 +- src/test/ui/token/issue-41155.rs | 13 +++++++++++++ src/test/ui/token/issue-41155.stderr | 10 ++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/token/issue-41155.rs create mode 100644 src/test/ui/token/issue-41155.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43d21015a4fb..58be43526fd9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -592,8 +592,10 @@ impl<'a> Parser<'a> { } else { label_sp }; - err.span_label(sp, &label_exp); - if !sp.source_equal(&self.span) { + if self.span.contains(sp) { + err.span_label(self.span, &label_exp); + } else { + err.span_label(sp, &label_exp); err.span_label(self.span, &"unexpected token"); } Err(err) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9b88b9f7696f..aaafcadc38a1 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -89,7 +89,7 @@ impl Span { /// Returns a new span representing the next character after the end-point of this span pub fn next_point(self) -> Span { let lo = cmp::max(self.hi.0, self.lo.0 + 1); - Span { lo: BytePos(lo), hi: BytePos(lo + 1), ..self } + Span { lo: BytePos(lo), hi: BytePos(lo), ..self } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. diff --git a/src/test/ui/token/issue-41155.rs b/src/test/ui/token/issue-41155.rs new file mode 100644 index 000000000000..0f473c9e0738 --- /dev/null +++ b/src/test/ui/token/issue-41155.rs @@ -0,0 +1,13 @@ +// 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. + +impl S { + pub +} diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr new file mode 100644 index 000000000000..0da3abd4eaf9 --- /dev/null +++ b/src/test/ui/token/issue-41155.stderr @@ -0,0 +1,10 @@ +error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}` + --> $DIR/issue-41155.rs:13:1 + | +12 | pub + | - expected one of 7 possible tokens here +13 | } + | ^ unexpected token + +error: aborting due to previous error + From b9d662a00026390aa7b7b5706d3c800e4d6e6fdb Mon Sep 17 00:00:00 2001 From: Nathaniel Ringo Date: Mon, 10 Apr 2017 16:12:39 -0500 Subject: [PATCH 401/905] Fixes incorrect formatting in array's documentation. --- src/libstd/primitive_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5b2053e929a1..052340a0f253 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -277,7 +277,7 @@ mod prim_pointer { } /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if /// the element type allows it: /// -/// - [`Clone`][clone] (only if `T: [Copy][copy]`) +/// - [`Clone`][clone] (only if `T: `[`Copy`][copy]) /// - [`Debug`][debug] /// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) /// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] From be8787dfe564cf315a9343a84724130da322e805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 10 Apr 2017 14:17:49 -0700 Subject: [PATCH 402/905] Explicit help message for binop type missmatch When trying to do a binary operation with missing implementation, for example `1 + Some(2)`, provide an explicit help message: ``` note: no implementation for `{integer} + std::option::Option<{integer}>` ``` Use `rustc_on_unimplemented` for the suggestions. Move cfail test to ui. --- src/libcore/cmp.rs | 2 + src/libcore/ops.rs | 20 +++++++ src/librustc/traits/error_reporting.rs | 20 +++---- .../impl-trait/equality.rs | 2 +- src/test/ui/impl-trait/equality.stderr | 55 ++++++++++++++++++ src/test/ui/mismatched_types/binops.rs | 18 ++++++ src/test/ui/mismatched_types/binops.stderr | 58 +++++++++++++++++++ src/test/ui/span/multiline-span-simple.stderr | 6 +- 8 files changed, 164 insertions(+), 17 deletions(-) rename src/test/{compile-fail => ui}/impl-trait/equality.rs (95%) create mode 100644 src/test/ui/impl-trait/equality.stderr create mode 100644 src/test/ui/mismatched_types/binops.rs create mode 100644 src/test/ui/mismatched_types/binops.stderr diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 74ded948b18e..d4544dadaeb0 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -102,6 +102,7 @@ use self::Ordering::*; /// ``` #[lang = "eq"] #[stable(feature = "rust1", since = "1.0.0")] +#[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 /// by `==`. @@ -550,6 +551,7 @@ impl PartialOrd for Ordering { /// ``` #[lang = "ord"] #[stable(feature = "rust1", since = "1.0.0")] +#[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/ops.rs b/src/libcore/ops.rs index d203b68c0dfd..175b3a5a69ac 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -242,6 +242,7 @@ pub trait Drop { /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"] pub trait Add { /// The resulting type after applying the `+` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -315,6 +316,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"] pub trait Sub { /// The resulting type after applying the `-` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -437,6 +439,7 @@ 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}`"] pub trait Mul { /// The resulting type after applying the `*` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -565,6 +568,7 @@ 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}`"] pub trait Div { /// The resulting type after applying the `/` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -644,6 +648,7 @@ div_impl_float! { f32 f64 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"] pub trait Rem { /// The resulting type after applying the `%` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -883,6 +888,7 @@ 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}`"] pub trait BitAnd { /// The resulting type after applying the `&` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -966,6 +972,7 @@ 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}`"] pub trait BitOr { /// The resulting type after applying the `|` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1052,6 +1059,7 @@ 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}`"] pub trait BitXor { /// The resulting type after applying the `^` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1134,6 +1142,7 @@ 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}`"] pub trait Shl { /// The resulting type after applying the `<<` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1237,6 +1246,7 @@ 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}`"] pub trait Shr { /// The resulting type after applying the `>>` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1321,6 +1331,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// ``` #[lang = "add_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"] pub trait AddAssign { /// The method for the `+=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1377,6 +1388,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 = "no implementation for `{Self} -= {Rhs}`"] pub trait SubAssign { /// The method for the `-=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1422,6 +1434,7 @@ 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}`"] pub trait MulAssign { /// The method for the `*=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1467,6 +1480,7 @@ 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}`"] pub trait DivAssign { /// The method for the `/=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1511,6 +1525,7 @@ 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}`"] pub trait RemAssign { /// The method for the `%=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1597,6 +1612,7 @@ rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "bitand_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"] pub trait BitAndAssign { /// The method for the `&=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1641,6 +1657,7 @@ 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}`"] pub trait BitOrAssign { /// The method for the `|=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1685,6 +1702,7 @@ 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}`"] pub trait BitXorAssign { /// The method for the `^=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1729,6 +1747,7 @@ 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}`"] pub trait ShlAssign { /// The method for the `<<=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1794,6 +1813,7 @@ 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}`"] pub trait ShrAssign { /// The method for the `>>=` operator #[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 152dd6ac3000..931c77badad2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -524,15 +524,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "the trait bound `{}` is not satisfied{}", trait_ref.to_predicate(), post_message); - err.span_label(span, - &format!("{}the trait `{}` is not \ - implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); // Try to report a help message - if !trait_ref.has_infer_types() && self.predicate_can_apply(trait_ref) { // If a where-clause may be useful, remind the @@ -544,17 +537,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - } else if let Some(s) = self.on_unimplemented_note(trait_ref, - obligation) { + } else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) { // If it has a custom "#[rustc_on_unimplemented]" // error message, let's display it! err.note(&s); } else { - // If we can't show anything useful, try to find - // similar impls. + // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_ref); self.report_similar_impl_candidates(impl_candidates, &mut err); } + + err.span_label(span, + &format!("{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty())); err } @@ -997,3 +994,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { suggested_limit)); } } + diff --git a/src/test/compile-fail/impl-trait/equality.rs b/src/test/ui/impl-trait/equality.rs similarity index 95% rename from src/test/compile-fail/impl-trait/equality.rs rename to src/test/ui/impl-trait/equality.rs index 36df4f0eb4d4..96db53ad2e46 100644 --- a/src/test/compile-fail/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 no implementation for `u32 + impl Foo` } } diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr new file mode 100644 index 000000000000..bd024d6766ed --- /dev/null +++ b/src/test/ui/impl-trait/equality.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/equality.rs:25:5 + | +25 | 0_u32 + | ^^^^^ expected i32, found u32 + | + = note: expected type `i32` + found type `u32` + +error[E0277]: the trait bound `u32: std::ops::Add` is not satisfied + --> $DIR/equality.rs:34:9 + | +34 | n + sum_to(n - 1) + | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Add` is not implemented for `u32` + | + = note: no implementation for `u32 + impl Foo` + +error[E0308]: mismatched types + --> $DIR/equality.rs:53:18 + | +53 | let _: u32 = hide(0_u32); + | ^^^^^^^^^^^ expected u32, found anonymized type + | + = note: expected type `u32` + found type `impl Foo` + +error[E0308]: mismatched types + --> $DIR/equality.rs:59:18 + | +59 | let _: i32 = Leak::leak(hide(0_i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found associated type + | + = note: expected type `i32` + found type `::T` + +error[E0308]: mismatched types + --> $DIR/equality.rs:66:10 + | +66 | x = (x.1, + | ^^^ expected u32, found i32 + | + = note: expected type `impl Foo` (u32) + found type `impl Foo` (i32) + +error[E0308]: mismatched types + --> $DIR/equality.rs:69:10 + | +69 | x.0); + | ^^^ expected i32, found u32 + | + = note: expected type `impl Foo` (i32) + found type `impl Foo` (u32) + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs new file mode 100644 index 000000000000..98449e596641 --- /dev/null +++ b/src/test/ui/mismatched_types/binops.rs @@ -0,0 +1,18 @@ +// 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() { + 1 + Some(1); + 2 as usize - Some(1); + 3 * (); + 4 / ""; + 5 < String::new(); + 6 == Ok(1); +} diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr new file mode 100644 index 000000000000..a0f7ff658709 --- /dev/null +++ b/src/test/ui/mismatched_types/binops.stderr @@ -0,0 +1,58 @@ +error[E0277]: the trait bound `{integer}: std::ops::Add>` is not satisfied + --> $DIR/binops.rs:12:5 + | +12 | 1 + Some(1); + | ^^^^^^^^^^^ the trait `std::ops::Add>` is not implemented for `{integer}` + | + = note: no implementation for `{integer} + std::option::Option<{integer}>` + +error[E0277]: the trait bound `usize: std::ops::Sub>` is not satisfied + --> $DIR/binops.rs:13:5 + | +13 | 2 as usize - Some(1); + | ^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Sub>` is not implemented for `usize` + | + = note: no implementation for `usize - std::option::Option<{integer}>` + +error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied + --> $DIR/binops.rs:14:5 + | +14 | 3 * (); + | ^^^^^^ the trait `std::ops::Mul<()>` is not implemented for `{integer}` + | + = note: no implementation for `{integer} * ()` + +error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied + --> $DIR/binops.rs:15:5 + | +15 | 4 / ""; + | ^^^^^^ the trait `std::ops::Div<&str>` is not implemented for `{integer}` + | + = note: no implementation for `{integer} / &str` + +error[E0277]: the trait bound `{integer}: std::cmp::PartialEq` is not satisfied + --> $DIR/binops.rs:16:5 + | +16 | 5 < String::new(); + | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialEq` is not implemented for `{integer}` + | + = note: can't compare `{integer}` with `std::string::String` + +error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd` is not satisfied + --> $DIR/binops.rs:16:5 + | +16 | 5 < String::new(); + | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::PartialOrd` is not implemented for `{integer}` + | + = note: can't compare `{integer}` with `std::string::String` + +error[E0277]: the trait bound `{integer}: std::cmp::PartialEq>` is not satisfied + --> $DIR/binops.rs:17:5 + | +17 | 6 == Ok(1); + | ^^^^^^^^^^ the trait `std::cmp::PartialEq>` is not implemented for `{integer}` + | + = note: can't compare `{integer}` with `std::result::Result<{integer}, _>` + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 85c11c05b9f9..161b6ca48b28 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -9,11 +9,7 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied 27 | | y), | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32` | - = help: the following implementations were found: - - <&'a u32 as std::ops::Add> - > - <&'b u32 as std::ops::Add<&'a u32>> + = note: no implementation for `u32 + ()` error: aborting due to previous error From f297767b2c262e8542a4734a3f47b0a75502c9fd Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Tue, 11 Apr 2017 00:22:26 +0100 Subject: [PATCH 403/905] Make sccache a bit quieter --- src/bootstrap/native.rs | 2 +- src/ci/docker/run.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 62eed8be3ccb..726e94e49a19 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -147,7 +147,7 @@ pub fn llvm(build: &Build, target: &str) { } if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=debug"); + cfg.env("RUST_LOG", "sccache=info"); } // FIXME: we don't actually need to build all LLVM tools and all LLVM diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 71a4bfae3caf..59b93b784b2f 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -38,7 +38,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" - args="$args --env SCCACHE_LOG_LEVEL=debug" args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache From 0303a3364b68e412539634617c734192760a7df4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 11 Apr 2017 01:04:33 +0300 Subject: [PATCH 404/905] Fix pairs of doubles using an illegal <8 x i8> vector. --- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/cabi_x86_64.rs | 17 +++++++++-------- .../extern-fn-struct-passing-abi/test.c | 19 +++++++++++++++++++ .../extern-fn-struct-passing-abi/test.rs | 11 +++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 7be80a757ca0..c4fdc46d030c 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -283,7 +283,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { Layout::Vector { .. } => { Some(Reg { - kind: RegKind::Integer, + kind: RegKind::Vector, size: self.size(ccx) }) } diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index cbe170d85834..2daebf5cf3d6 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -173,14 +173,15 @@ fn reg_component(cls: &[Class], i: &mut usize, size: u64) -> Option { Class::Sse => { let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count(); *i += vec_len; - Some(match size { - 4 => Reg::f32(), - 8 => Reg::f64(), - _ => { - Reg { - kind: RegKind::Vector, - size: Size::from_bytes(vec_len as u64 * 8) - } + Some(if vec_len == 1 { + match size { + 4 => Reg::f32(), + _ => Reg::f64() + } + } else { + Reg { + kind: RegKind::Vector, + size: Size::from_bytes(vec_len as u64 * 8) } }) } diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c index 4253767ee76a..4e09928edc6d 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.c +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c @@ -38,6 +38,11 @@ struct Huge { int32_t e; }; +struct FloatPoint { + double x; + double y; +}; + // System V x86_64 ABI: // a, b, c, d, e should be in registers // s should be byval pointer @@ -258,3 +263,17 @@ struct Huge huge_struct(struct Huge s) { return s; } + +// System V x86_64 ABI: +// p should be in registers +// return should be in registers +// +// Win64 ABI: +// p should be a byval pointer +// return should be in a hidden sret pointer +struct FloatPoint float_point(struct FloatPoint p) { + assert(p.x == 5.); + assert(p.y == -3.); + + return p; +} diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs index b91362b8edcc..ff845a644b11 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs @@ -46,6 +46,13 @@ struct Huge { e: i32 } +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] +struct FloatPoint { + x: f64, + y: f64 +} + #[link(name = "test", kind = "static")] extern { fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect); @@ -72,6 +79,8 @@ extern { fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect; fn huge_struct(s: Huge) -> Huge; + + fn float_point(p: FloatPoint) -> FloatPoint; } fn main() { @@ -79,6 +88,7 @@ fn main() { let t = BiggerRect { s: s, a: 27834, b: 7657 }; let u = FloatRect { a: 3489, b: 3490, c: 8. }; let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 }; + let p = FloatPoint { x: 5., y: -3. }; unsafe { byval_rect(1, 2, 3, 4, 5, s); @@ -94,5 +104,6 @@ fn main() { assert_eq!(split_ret_byval_struct(1, 2, s), s); assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t); assert_eq!(sret_split_struct(1, 2, s), t); + assert_eq!(float_point(p), p); } } From 63ebf08be50c2716b66f14f0ab6e9885542eb0a0 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 16:28:47 -0500 Subject: [PATCH 405/905] Initial attempt at implementing optimization fuel and re-enabling struct field reordering. --- src/librustc/session/config.rs | 24 +++++++++ src/librustc/session/mod.rs | 52 ++++++++++++++++++++ src/librustc/ty/context.rs | 5 ++ src/librustc/ty/layout.rs | 9 +--- src/librustc/ty/mod.rs | 5 ++ src/librustc_driver/lib.rs | 8 +++ src/test/run-pass/type-sizes.rs | 13 +++++ src/test/ui/print_type_sizes/nullable.stdout | 35 ++++++------- src/test/ui/print_type_sizes/packed.stdout | 10 ++-- src/test/ui/print_type_sizes/padding.stdout | 16 +++--- 10 files changed, 138 insertions(+), 39 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ef825a6854ce..b9a974045bce 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -643,6 +643,8 @@ macro_rules! options { Some("one of: `address`, `leak`, `memory` or `thread`"); pub const parse_linker_flavor: Option<&'static str> = Some(::rustc_back::LinkerFlavor::one_of()); + pub const parse_optimization_fuel: Option<&'static str> = + Some("crate=integer"); } #[allow(dead_code)] @@ -787,6 +789,21 @@ macro_rules! options { } true } + + fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) => { + let parts = s.split('=').collect::>(); + if parts.len() != 2 { return false; } + let crate_name = parts[0].to_string(); + let fuel = parts[1].parse::(); + if fuel.is_err() { return false; } + *slot = Some((crate_name, fuel.unwrap())); + true + } + } + } } ) } @@ -991,6 +1008,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "Use a sanitizer"), linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], "Linker flavor"), + fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], + "Set the optimization fuel quota for a crate."), + print_fuel: Option = (None, parse_opt_string, [TRACKED], + "Make Rustc print the total optimization fuel used by a crate."), } pub fn default_lib_output() -> CrateType { @@ -1784,11 +1805,13 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(bool); impl_dep_tracking_hash_via_hash!(usize); + impl_dep_tracking_hash_via_hash!(u64); impl_dep_tracking_hash_via_hash!(String); impl_dep_tracking_hash_via_hash!(lint::Level); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option<(String, u64)>); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); @@ -1810,6 +1833,7 @@ mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, Option)); + impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); impl DepTrackingHash for SearchPaths { fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) { let mut elems: Vec<_> = self diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 70b2809ccbed..2d204908a521 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -123,6 +123,20 @@ pub struct Session { pub code_stats: RefCell, next_node_id: Cell, + + /// If -zfuel=crate=n is specified, Some(crate). + optimization_fuel_crate: Option, + /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0. + optimization_fuel_limit: Cell, + /// We're rejecting all further optimizations. + out_of_fuel: Cell, + + // The next two are public because the driver needs to read them. + + /// If -zprint-fuel=crate, Some(crate). + pub print_fuel_crate: Option, + /// Always set to zero and incremented so that we can print fuel expended by a crate. + pub print_fuel: Cell, } pub struct PerfStats { @@ -507,6 +521,33 @@ impl Session { println!("Total time spent decoding DefPath tables: {}", duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } + + /// We want to know if we're allowed to do an optimization for crate crate. + /// This expends fuel if applicable, and records fuel if applicable. + pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { + let mut ret = true; + match self.optimization_fuel_crate { + Some(ref c) if c == crate_name => { + let fuel = self.optimization_fuel_limit.get(); + ret = fuel != 0; + if fuel == 0 && !self.out_of_fuel.get(){ + println!("optimization-fuel-exhausted: {}", msg()); + self.out_of_fuel.set(true); + } + else { + self.optimization_fuel_limit.set(fuel-1); + } + } + _ => {} + } + match self.print_fuel_crate { + Some(ref c) if c == crate_name=> { + self.print_fuel.set(self.print_fuel.get()+1); + }, + _ => {} + } + ret + } } pub fn build_session(sopts: config::Options, @@ -602,6 +643,12 @@ pub fn build_session_(sopts: config::Options, } ); + let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); + let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref() + .map(|i| i.1).unwrap_or(0)); + let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); + let print_fuel = Cell::new(0); + let sess = Session { dep_graph: dep_graph.clone(), target: target_cfg, @@ -643,6 +690,11 @@ pub fn build_session_(sopts: config::Options, decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), }, code_stats: RefCell::new(CodeStats::new()), + optimization_fuel_crate: optimization_fuel_crate, + optimization_fuel_limit: optimization_fuel_limit, + print_fuel_crate: print_fuel_crate, + print_fuel: print_fuel, + out_of_fuel: Cell::new(false), }; init_llvm(&sess); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index da56514ea82f..8b7438c0bfad 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -732,6 +732,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ast_ty_to_ty_cache: RefCell::new(NodeMap()), }, f) } + + pub fn consider_optimizing String>(&self, msg: T) -> bool { + let cname = self.crate_name(LOCAL_CRATE).as_str(); + self.sess.consider_optimizing(&cname, msg) + } } impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 54e5de390908..a344f89a6683 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -580,7 +580,6 @@ enum StructKind { } impl<'a, 'gcx, 'tcx> Struct { - // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type. fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, repr: &ReprOptions, kind: StructKind, scapegoat: Ty<'gcx>) -> Result> { @@ -598,12 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct { // Neither do 1-member and 2-member structs. // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. - let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && ! (repr.c || repr.packed); - - // Disable field reordering until we can decide what to do. - // The odd pattern here avoids a warning about the value never being read. - if can_optimize { can_optimize = false; } + let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) + && ! (repr.c || repr.packed || repr.linear || repr.simd); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f..ba9c177f9048 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1411,6 +1411,8 @@ pub struct ReprOptions { pub packed: bool, pub simd: bool, pub int: Option, + // Internal only for now. If true, don't reorder fields. + pub linear: bool, } impl_stable_hash_for!(struct ReprOptions { @@ -1440,6 +1442,9 @@ impl ReprOptions { ret.simd = true; } + // This is here instead of layout because the choice must make it into metadata. + ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", + tcx.item_path_str(did))); ret } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index c90dde3a5f6e..1fef97d54a14 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -517,6 +517,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.make_glob_map = resolve::MakeGlobMap::Yes; } + if sess.print_fuel_crate.is_some() { + control.compilation_done.callback = box |state| { + let sess = state.session; + println!("Fuel used by {}: {}", + sess.print_fuel_crate.as_ref().unwrap(), + sess.print_fuel.get()); + } + } control } } diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index bbb01eaaf46b..9d1a3500a582 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -31,6 +31,17 @@ enum e3 { a([u16; 0], u8), b } +struct ReorderedStruct { + a: u8, + b: u64, + c: u8 +} + +enum ReorderedEnum { + A(u8, u64, u8), + B(u8, u64, u8), +} + pub fn main() { assert_eq!(size_of::(), 1 as usize); assert_eq!(size_of::(), 4 as usize); @@ -54,4 +65,6 @@ pub fn main() { assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 4 as usize); + assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), 16); } diff --git a/src/test/ui/print_type_sizes/nullable.stdout b/src/test/ui/print_type_sizes/nullable.stdout index dd999c4a5e4c..830678f174f8 100644 --- a/src/test/ui/print_type_sizes/nullable.stdout +++ b/src/test/ui/print_type_sizes/nullable.stdout @@ -1,25 +1,22 @@ -print-type-size type: `IndirectNonZero`: 20 bytes, alignment: 4 bytes -print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.nested`: 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 end padding: 2 bytes -print-type-size type: `MyOption>`: 20 bytes, alignment: 4 bytes -print-type-size variant `Some`: 20 bytes -print-type-size field `.0`: 20 bytes -print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes -print-type-size variant `Record`: 10 bytes -print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.val`: 4 bytes, alignment: 4 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 variant `Some`: 12 bytes +print-type-size field `.0`: 12 bytes +print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes +print-type-size variant `Record`: 7 bytes +print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes -print-type-size type: `NestedNonZero`: 12 bytes, alignment: 4 bytes -print-type-size field `.pre`: 1 bytes -print-type-size padding: 3 bytes -print-type-size field `.val`: 4 bytes, alignment: 4 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 field `.val`: 4 bytes print-type-size field `.post`: 2 bytes -print-type-size end padding: 2 bytes +print-type-size field `.pre`: 1 bytes +print-type-size end padding: 1 bytes print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout index 1278a7d7c92c..83fd333c9c7f 100644 --- a/src/test/ui/print_type_sizes/packed.stdout +++ b/src/test/ui/print_type_sizes/packed.stdout @@ -1,13 +1,11 @@ -print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes +print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.h`: 2 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes -print-type-size padding: 2 bytes -print-type-size field `.g`: 4 bytes, alignment: 4 bytes print-type-size field `.c`: 1 bytes -print-type-size padding: 1 bytes -print-type-size field `.h`: 2 bytes, alignment: 2 bytes print-type-size field `.d`: 1 bytes -print-type-size end padding: 3 bytes +print-type-size end padding: 2 bytes print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout index bb95f790bd9e..0eaff7118b35 100644 --- a/src/test/ui/print_type_sizes/padding.stdout +++ b/src/test/ui/print_type_sizes/padding.stdout @@ -1,10 +1,12 @@ print-type-size type: `E1`: 12 bytes, alignment: 4 bytes -print-type-size discriminant: 4 bytes -print-type-size variant `A`: 5 bytes -print-type-size field `.0`: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `A`: 7 bytes print-type-size field `.1`: 1 bytes -print-type-size variant `B`: 8 bytes -print-type-size field `.0`: 8 bytes +print-type-size padding: 2 bytes +print-type-size field `.0`: 4 bytes, alignment: 4 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `E2`: 12 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes print-type-size variant `A`: 7 bytes @@ -15,7 +17,7 @@ print-type-size variant `B`: 11 bytes print-type-size padding: 3 bytes print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `S`: 8 bytes, alignment: 4 bytes +print-type-size field `.g`: 4 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes -print-type-size padding: 2 bytes -print-type-size field `.g`: 4 bytes, alignment: 4 bytes +print-type-size end padding: 2 bytes From 4db9c7a2a2ba42fb15a58f5d770294b797bd57d4 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 22:20:07 -0500 Subject: [PATCH 406/905] Make a comment better. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2d204908a521..4304248d158e 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate crate. + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From 912599944effe3ad379622c173e8f9a85dd7eaac Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Fri, 10 Mar 2017 14:13:59 -0500 Subject: [PATCH 407/905] Tests for -Z fuel=foo=n --- src/librustc/session/mod.rs | 2 +- src/test/run-pass/optimization-fuel-0.rs | 24 ++++++++++++++++++++++ src/test/run-pass/optimization-fuel-1.rs | 26 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/optimization-fuel-0.rs create mode 100644 src/test/run-pass/optimization-fuel-1.rs diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 4304248d158e..1be7d1afe45a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -534,7 +534,7 @@ impl Session { println!("optimization-fuel-exhausted: {}", msg()); self.out_of_fuel.set(true); } - else { + else if fuel > 0{ self.optimization_fuel_limit.set(fuel-1); } } diff --git a/src/test/run-pass/optimization-fuel-0.rs b/src/test/run-pass/optimization-fuel-0.rs new file mode 100644 index 000000000000..3832c040108f --- /dev/null +++ b/src/test/run-pass/optimization-fuel-0.rs @@ -0,0 +1,24 @@ +// 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. + +#![crate_name="foo"] + +use std::mem::size_of; + +// compile-flags: -Z fuel=foo=0 + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); + +fn main() { + assert_eq!(size_of::(), 6); + assert_eq!(size_of::(), 6); +} + diff --git a/src/test/run-pass/optimization-fuel-1.rs b/src/test/run-pass/optimization-fuel-1.rs new file mode 100644 index 000000000000..5f294e26aa53 --- /dev/null +++ b/src/test/run-pass/optimization-fuel-1.rs @@ -0,0 +1,26 @@ +// 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. + +#![crate_name="foo"] + +use std::mem::size_of; + +// compile-flags: -Z fuel=foo=1 + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); + +fn main() { + let optimized = (size_of::() == 4) as usize + +(size_of::() == 4) as usize; + assert_eq!(optimized, 1); +} + + From 8b00837691d9757b6c607b28b42d33dd581cac3b Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Fri, 10 Mar 2017 14:24:50 -0500 Subject: [PATCH 408/905] UI test for -Z print-fuel=foo --- src/test/ui/print-fuel/print-fuel.rs | 21 +++++++++++++++++++++ src/test/ui/print-fuel/print-fuel.stdout | 1 + 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/print-fuel/print-fuel.rs create mode 100644 src/test/ui/print-fuel/print-fuel.stdout diff --git a/src/test/ui/print-fuel/print-fuel.rs b/src/test/ui/print-fuel/print-fuel.rs new file mode 100644 index 000000000000..0d9e243763f7 --- /dev/null +++ b/src/test/ui/print-fuel/print-fuel.rs @@ -0,0 +1,21 @@ +// 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. + +#![crate_name="foo"] +#![allow(dead_code)] + +// compile-flags: -Z print-fuel=foo + +struct S1(u8, u16, u8); +struct S2(u8, u16, u8); +struct S3(u8, u16, u8); + +fn main() { +} diff --git a/src/test/ui/print-fuel/print-fuel.stdout b/src/test/ui/print-fuel/print-fuel.stdout new file mode 100644 index 000000000000..cc88cc077bb2 --- /dev/null +++ b/src/test/ui/print-fuel/print-fuel.stdout @@ -0,0 +1 @@ +Fuel used by foo: 3 From 98eb121b7a748fd2668bf03ace8307be2880955f Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Mon, 20 Mar 2017 14:07:46 -0400 Subject: [PATCH 409/905] We have to use u16 to test field reordering because u64's alignment changes based on 32-bit or 64-bit architecture. --- src/test/run-pass/type-sizes.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 9d1a3500a582..2f50e63153ea 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -33,13 +33,13 @@ enum e3 { struct ReorderedStruct { a: u8, - b: u64, + b: u16, c: u8 } enum ReorderedEnum { - A(u8, u64, u8), - B(u8, u64, u8), + A(u8, u16, u8), + B(u8, u16, u8), } pub fn main() { @@ -65,6 +65,6 @@ pub fn main() { assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 8 as usize); assert_eq!(size_of::(), 4 as usize); - assert_eq!(size_of::(), 16); - assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 6); } From 0931e2006a5f8fd88032247ea543239c628cf10c Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 16:28:47 -0500 Subject: [PATCH 410/905] Initial attempt at implementing optimization fuel and re-enabling struct field reordering. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1be7d1afe45a..b32d05971ff3 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. + /// We want to know if we're allowed to do an optimization for crate crate. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From d821e98fd73ee16c2f2733570220b2b64d367d45 Mon Sep 17 00:00:00 2001 From: Austin Hicks Date: Wed, 8 Mar 2017 22:20:07 -0500 Subject: [PATCH 411/905] Make a comment better. --- src/librustc/session/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b32d05971ff3..1be7d1afe45a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -522,7 +522,7 @@ impl Session { duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } - /// We want to know if we're allowed to do an optimization for crate crate. + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; From a384f131cbb3e79154cc99ef0d025fc9ed6d9674 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 11 Apr 2017 14:31:20 +0300 Subject: [PATCH 412/905] Fix handling of closure arguments Those did not take tuple reordering into account, causing majority of the compiler test suite to fail. --- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/mod.rs | 3 ++- src/librustc_trans/intrinsic.rs | 9 +++++---- src/librustc_trans/mir/mod.rs | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a344f89a6683..d7a4b3fda63b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -598,7 +598,7 @@ impl<'a, 'gcx, 'tcx> Struct { // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && ! (repr.c || repr.packed || repr.linear || repr.simd); + && !(repr.c || repr.packed || repr.linear || repr.simd); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ba9c177f9048..a2c356c20db0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1419,7 +1419,8 @@ impl_stable_hash_for!(struct ReprOptions { c, packed, simd, - int + int, + linear }); impl ReprOptions { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5e7d612d17f8..b6fbc2f5ad53 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -16,7 +16,7 @@ use llvm; use llvm::{ValueRef}; use abi::{Abi, FnType}; use adt; -use mir::lvalue::LvalueRef; +use mir::lvalue::{LvalueRef, Alignment}; use base::*; use common::*; use declare; @@ -36,8 +36,6 @@ use syntax_pos::Span; use std::cmp::Ordering; use std::iter; -use mir::lvalue::Alignment; - fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { let llvm_name = match name { "sqrtf32" => "llvm.sqrt.f32", @@ -622,7 +620,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, for i in 0..elems.len() { let val = bcx.extract_value(val, i); - bcx.store(val, bcx.struct_gep(llresult, i), None); + let lval = LvalueRef::new_sized_ty(llresult, ret_ty, + Alignment::AbiAligned); + let (dest, _) = lval.trans_field_ptr(bcx, i); + bcx.store(val, dest, None); } C_nil(ccx) } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c8d15d28708f..f4c9a136ace3 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -386,7 +386,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let lvalue = LvalueRef::alloca(bcx, arg_ty, &format!("arg{}", arg_index)); for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() { - let dst = bcx.struct_gep(lvalue.llval, i); + let (dst, _) = lvalue.trans_field_ptr(bcx, i); let arg = &mircx.fn_ty.args[idx]; idx += 1; if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) { From e18c59fd48a8387767d44fdd4d36208dfd33f762 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 11 Apr 2017 15:57:49 +0300 Subject: [PATCH 413/905] Fix some nits --- src/librustc/session/mod.rs | 5 ++--- src/librustc_driver/lib.rs | 4 +++- src/librustc_trans/intrinsic.rs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1be7d1afe45a..039db3d9ee91 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -530,11 +530,10 @@ impl Session { Some(ref c) if c == crate_name => { let fuel = self.optimization_fuel_limit.get(); ret = fuel != 0; - if fuel == 0 && !self.out_of_fuel.get(){ + if fuel == 0 && !self.out_of_fuel.get() { println!("optimization-fuel-exhausted: {}", msg()); self.out_of_fuel.set(true); - } - else if fuel > 0{ + } else if fuel > 0 { self.optimization_fuel_limit.set(fuel-1); } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1fef97d54a14..1a892b73aa5d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -518,7 +518,9 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } if sess.print_fuel_crate.is_some() { - control.compilation_done.callback = box |state| { + let old_callback = control.compilation_done.callback; + control.compilation_done.callback = box move |state| { + old_callback(state); let sess = state.session; println!("Fuel used by {}: {}", sess.print_fuel_crate.as_ref().unwrap(), diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b6fbc2f5ad53..7cfc28622c44 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -622,8 +622,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let val = bcx.extract_value(val, i); let lval = LvalueRef::new_sized_ty(llresult, ret_ty, Alignment::AbiAligned); - let (dest, _) = lval.trans_field_ptr(bcx, i); - bcx.store(val, dest, None); + let (dest, align) = lval.trans_field_ptr(bcx, i); + bcx.store(val, dest, align.to_align()); } C_nil(ccx) } From 143f7be8b65d5e1be549e1b283e8e3423bdab41c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 10 Apr 2017 14:35:28 +0200 Subject: [PATCH 414/905] Remove strings fulfilled with whitespaces in code block headers --- src/librustdoc/html/markdown.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index dca873a85d81..c59101cc7799 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -469,28 +469,28 @@ impl LangString { ); for token in tokens { - match token { + match token.trim() { "" => {}, "should_panic" => { data.should_panic = true; seen_rust_tags = seen_other_tags == false; } - "no_run" => { data.no_run = true; seen_rust_tags = seen_other_tags == false; } - "ignore" => { data.ignore = true; seen_rust_tags = seen_other_tags == false; } + "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; } + "ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; } "rust" => { data.rust = true; seen_rust_tags = true; } "test_harness" => { data.test_harness = true; - seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; } "compile_fail" if allow_compile_fail => { data.compile_fail = true; - seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; data.no_run = true; } x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => { if let Ok(_) = x[1..].parse::() { data.error_codes.push(x.to_owned()); - seen_rust_tags = seen_other_tags == false || seen_rust_tags == true; + seen_rust_tags = !seen_other_tags || seen_rust_tags; } else { seen_other_tags = true; } @@ -680,6 +680,7 @@ mod tests { t("{.example .rust}", false, false, false, true, false, false, Vec::new()); t("{.test_harness .rust}", false, false, false, true, true, false, Vec::new()); t("text, no_run", false, true, false, false, false, false, Vec::new()); + t("text,no_run", false, true, false, false, false, false, Vec::new()); } #[test] From 316af6082c8c23615cc54302ee7efa0811bbabe7 Mon Sep 17 00:00:00 2001 From: Sebastian Hahn Date: Tue, 11 Apr 2017 14:51:56 +0200 Subject: [PATCH 415/905] Clarify Iterator::position doc Extend the example a little bit to show behaviour better. --- src/libcore/iter/iterator.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 618edf48abd0..8bf641e37fe4 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1532,14 +1532,18 @@ pub trait Iterator { /// Stopping at the first `true`: /// /// ``` - /// let a = [1, 2, 3]; + /// let a = [1, 2, 3, 4]; /// /// let mut iter = a.iter(); /// - /// assert_eq!(iter.position(|&x| x == 2), Some(1)); + /// assert_eq!(iter.position(|&x| x >= 2), Some(1)); /// /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Some(&3)); + /// + /// // The returned index depends on iterator state + /// assert_eq!(iter.position(|&x| x == 4), Some(0)); + /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 13d008d1e8b671e78c92e61b42ae7b82f5736121 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 10 Apr 2017 11:22:38 -0700 Subject: [PATCH 416/905] Touch up rls integration * Use the right version when building combined installer * Update dependencies of rls as it depends on rustc and plugins * Fix build-manifest and the versions it uses for the rls --- cargo | 2 +- src/bootstrap/dist.rs | 18 ++++++++++++-- src/bootstrap/lib.rs | 3 +++ src/bootstrap/step.rs | 9 +++++-- src/tools/build-manifest/src/main.rs | 35 ++++++++++++++++------------ 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/cargo b/cargo index 4e95c6b41eca..4729175045b4 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 +Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e786d69555a1..4328c4e3f1d4 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -39,8 +39,10 @@ use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe}; fn pkgname(build: &Build, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, build.cargo_package_vers()) + } else if component == "rls" { + format!("{}-{}", component, build.package_vers(&build.release_num("rls"))) } else { - assert!(component.starts_with("rust") || component == "rls"); + assert!(component.starts_with("rust")); format!("{}-{}", component, build.rust_package_vers()) } } @@ -598,7 +600,8 @@ pub fn rls(build: &Build, stage: u32, target: &str) { let src = build.src.join("rls"); let release_num = build.release_num("rls"); - let name = format!("rls-{}", build.package_vers(&release_num)); + let name = pkgname(build, "rls"); + let version = build.rls_info.version(build, &release_num); let tmp = tmpdir(build); let image = tmp.join("rls-image"); @@ -614,6 +617,15 @@ pub fn rls(build: &Build, stage: u32, target: &str) { install(&src.join("LICENSE-MIT"), &doc, 0o644); install(&src.join("LICENSE-APACHE"), &doc, 0o644); + // Prepare the overlay + let overlay = tmp.join("rls-overlay"); + drop(fs::remove_dir_all(&overlay)); + t!(fs::create_dir_all(&overlay)); + install(&src.join("README.md"), &overlay, 0o644); + install(&src.join("LICENSE-MIT"), &overlay, 0o644); + install(&src.join("LICENSE-APACHE"), &overlay, 0o644); + t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes())); + // Generate the installer tarball let mut cmd = Command::new("sh"); cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) @@ -623,6 +635,7 @@ pub fn rls(build: &Build, stage: u32, target: &str) { .arg(format!("--image-dir={}", sanitize_sh(&image))) .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build)))) .arg(format!("--output-dir={}", sanitize_sh(&distdir(build)))) + .arg(format!("--non-installed-overlay={}", sanitize_sh(&overlay))) .arg(format!("--package-name={}-{}", name, target)) .arg("--component-name=rls") .arg("--legacy-manifest-dirs=rustlib,cargo"); @@ -991,6 +1004,7 @@ pub fn hash_and_sign(build: &Build) { cmd.arg(today.trim()); cmd.arg(build.rust_package_vers()); cmd.arg(build.package_vers(&build.release_num("cargo"))); + cmd.arg(build.package_vers(&build.release_num("rls"))); cmd.arg(addr); t!(fs::create_dir_all(distdir(build))); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e91664ac8aba..d711b63ea2e2 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -151,6 +151,7 @@ pub struct Build { out: PathBuf, rust_info: channel::GitInfo, cargo_info: channel::GitInfo, + rls_info: channel::GitInfo, local_rebuild: bool, // Probed tools at runtime @@ -234,6 +235,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); + let rls_info = channel::GitInfo::new(&src.join("rls")); let src_is_git = src.join(".git").exists(); Build { @@ -246,6 +248,7 @@ impl Build { rust_info: rust_info, cargo_info: cargo_info, + rls_info: rls_info, local_rebuild: local_rebuild, cc: HashMap::new(), cxx: HashMap::new(), diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index d1581576957d..596cbcf01bb8 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -572,7 +572,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); rules.build("tool-rls", "rls") .host(true) - .dep(|s| s.name("libstd")) + .dep(|s| s.name("librustc")) + .dep(move |s| { + // rls, like cargo, uses procedural macros + s.name("librustc-link") + .target(&build.config.build) + .host(&build.config.build) + }) .run(move |s| compile::tool(build, s.stage, s.target, "rls")); // ======================================================================== @@ -695,7 +701,6 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("dist-analysis", "analysis") .dep(|s| s.name("dist-std")) - .default(true) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); rules.dist("dist-rls", "rls") diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index eab2dc75af8d..248f3d49f093 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -135,6 +135,7 @@ macro_rules! t { struct Builder { rust_release: String, cargo_release: String, + rls_release: String, input: PathBuf, output: PathBuf, gpg_passphrase: String, @@ -143,6 +144,7 @@ struct Builder { date: String, rust_version: String, cargo_version: String, + rls_version: String, } fn main() { @@ -152,6 +154,7 @@ fn main() { let date = args.next().unwrap(); let rust_release = args.next().unwrap(); let cargo_release = args.next().unwrap(); + let rls_release = args.next().unwrap(); let s3_address = args.next().unwrap(); let mut passphrase = String::new(); t!(io::stdin().read_to_string(&mut passphrase)); @@ -159,6 +162,7 @@ fn main() { Builder { rust_release: rust_release, cargo_release: cargo_release, + rls_release: rls_release, input: input, output: output, gpg_passphrase: passphrase, @@ -167,6 +171,7 @@ fn main() { date: date, rust_version: String::new(), cargo_version: String::new(), + rls_version: String::new(), }.build(); } @@ -174,6 +179,7 @@ impl Builder { fn build(&mut self) { self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu"); self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu"); + self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu"); self.digest_and_sign(); let Manifest { manifest_version, date, pkg } = self.build_manifest(); @@ -223,11 +229,8 @@ impl Builder { self.package("rust-std", &mut manifest.pkg, TARGETS); self.package("rust-docs", &mut manifest.pkg, TARGETS); self.package("rust-src", &mut manifest.pkg, &["*"]); - - if self.rust_release == "nightly" { - self.package("rls", &mut manifest.pkg, HOSTS); - self.package("rust-analysis", &mut manifest.pkg, TARGETS); - } + self.package("rls", &mut manifest.pkg, HOSTS); + self.package("rust-analysis", &mut manifest.pkg, TARGETS); let mut pkg = Package { version: self.cached_version("rust").to_string(), @@ -266,6 +269,14 @@ impl Builder { }); } + extensions.push(Component { + pkg: "rls".to_string(), + target: host.to_string(), + }); + extensions.push(Component { + pkg: "rust-analysis".to_string(), + target: host.to_string(), + }); for target in TARGETS { if target != host { extensions.push(Component { @@ -273,16 +284,6 @@ impl Builder { target: target.to_string(), }); } - if self.rust_release == "nightly" { - extensions.push(Component { - pkg: "rust-analysis".to_string(), - target: target.to_string(), - }); - extensions.push(Component { - pkg: "rls".to_string(), - target: host.to_string(), - }); - } } extensions.push(Component { pkg: "rust-src".to_string(), @@ -348,6 +349,8 @@ impl Builder { format!("rust-src-{}.tar.gz", self.rust_release) } else if component == "cargo" { format!("cargo-{}-{}.tar.gz", self.cargo_release, target) + } else if component == "rls" { + format!("rls-{}-{}.tar.gz", self.rls_release, target) } else { format!("{}-{}-{}.tar.gz", component, self.rust_release, target) } @@ -356,6 +359,8 @@ impl Builder { fn cached_version(&self, component: &str) -> &str { if component == "cargo" { &self.cargo_version + } else if component == "rls" { + &self.rls_version } else { &self.rust_version } From 4b4b1e1b2581b9aa3229d17d7e0027cfb4086add Mon Sep 17 00:00:00 2001 From: Paul Lange Date: Thu, 6 Apr 2017 22:30:26 +0200 Subject: [PATCH 417/905] Improve module description for std::f32 and std::f64. Fixes #29353 --- src/libstd/f32.rs | 4 +++- src/libstd/f64.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 544f4f9ddbed..dd8318006835 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 32-bit floating point type. +//! 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](../primitive.f32.html).* diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index dd4bc253bed4..2f02e01935a4 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 64-bit floating point type. +//! 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](../primitive.f64.html).* From 384ec80d2b3dd61a5f9910dc660bffea8710002e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 11 Apr 2017 23:52:51 +0300 Subject: [PATCH 418/905] store Spans for all MIR locals --- src/librustc/ich/impls_mir.rs | 3 +- src/librustc/mir/mod.rs | 40 +++++++++++-------- src/librustc/mir/visit.rs | 5 +-- .../borrowck/mir/elaborate_drops.rs | 6 +-- src/librustc_mir/build/expr/as_lvalue.rs | 3 +- src/librustc_mir/build/expr/as_rvalue.rs | 14 +++---- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 3 +- src/librustc_mir/build/matches/test.rs | 13 +++--- src/librustc_mir/build/misc.rs | 6 +-- src/librustc_mir/build/mod.rs | 12 ++++-- src/librustc_mir/shim.rs | 23 ++++++----- src/librustc_mir/transform/inline.rs | 15 +++---- src/librustc_mir/transform/promote_consts.rs | 6 ++- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_mir/util/patch.rs | 5 ++- src/librustc_mir/util/pretty.rs | 4 +- .../debuginfo/create_scope_map.rs | 2 +- src/librustc_trans/mir/mod.rs | 5 +-- 21 files changed, 96 insertions(+), 77 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 401f7e1921ab..3ff8ffb35054 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -22,7 +22,8 @@ impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); -impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info, +is_user_variable}); impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index aea4684e526c..9ff64b295b76 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -197,10 +197,10 @@ impl<'tcx> Mir<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - Some(local) - } else { + if self.local_decls[local].is_user_variable { None + } else { + Some(local) } }) } @@ -210,10 +210,10 @@ impl<'tcx> Mir<'tcx> { pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - None - } else { + if self.local_decls[local].is_user_variable { Some(local) + } else { + None } }) } @@ -370,6 +370,9 @@ pub struct LocalDecl<'tcx> { /// Temporaries and the return pointer are always mutable. pub mutability: Mutability, + /// True if this corresponds to a user-declared local variable. + pub is_user_variable: bool, + /// Type of this local. pub ty: Ty<'tcx>, @@ -379,24 +382,23 @@ pub struct LocalDecl<'tcx> { /// to generate better debuginfo. pub name: Option, - /// For user-declared variables, stores their source information. - /// - /// For temporaries, this is `None`. - /// - /// This is the primary way to differentiate between user-declared - /// variables and compiler-generated temporaries. - pub source_info: Option, + /// Source info of the local. + pub source_info: SourceInfo, } impl<'tcx> LocalDecl<'tcx> { /// Create a new `LocalDecl` for a temporary. #[inline] - pub fn new_temp(ty: Ty<'tcx>) -> Self { + pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { LocalDecl { mutability: Mutability::Mut, ty: ty, name: None, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, + is_user_variable: false } } @@ -404,12 +406,16 @@ impl<'tcx> LocalDecl<'tcx> { /// /// This must be inserted into the `local_decls` list as the first local. #[inline] - pub fn new_return_pointer(return_ty: Ty) -> LocalDecl { + pub fn new_return_pointer(return_ty: Ty, span: Span) -> LocalDecl { LocalDecl { mutability: Mutability::Mut, ty: return_ty, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, name: None, // FIXME maybe we do want some name here? + is_user_variable: false } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 733ad36de90e..83963de8b001 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -630,12 +630,11 @@ macro_rules! make_mir_visitor { ref $($mutability)* ty, name: _, ref $($mutability)* source_info, + is_user_variable: _, } = *local_decl; self.visit_ty(ty); - if let Some(ref $($mutability)* info) = *source_info { - self.visit_source_info(info); - } + self.visit_source_info(source_info); } fn super_visibility_scope(&mut self, diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 713e65666627..ca313622a3af 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -307,12 +307,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { data } - fn create_drop_flag(&mut self, index: MovePathIndex) { + fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let tcx = self.tcx; let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.mir.span); self.drop_flags.entry(index).or_insert_with(|| { - patch.new_temp(tcx.types.bool) + patch.new_temp(tcx.types.bool, span) }); } @@ -374,7 +374,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", child, location, path, (maybe_live, maybe_dead)); if maybe_live && maybe_dead { - self.create_drop_flag(child) + self.create_drop_flag(child, terminator.source_info.span) } }); } diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 1cd9a1b25bad..df2841a66826 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -62,7 +62,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let idx = unpack!(block = this.as_operand(block, None, index)); // bounds check: - let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty)); + let (len, lt) = (this.temp(usize_ty.clone(), expr_span), + this.temp(bool_ty, expr_span)); this.cfg.push_assign(block, source_info, // len = len(slice) &len, Rvalue::Len(slice.clone())); this.cfg.push_assign(block, source_info, // lt = idx < len diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6694107a8d48..fb547332c5f5 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = this.hir.bool_ty(); let minval = this.minval_literal(expr_span, expr.ty); - let is_min = this.temp(bool_ty); + let is_min = this.temp(bool_ty, expr_span); this.cfg.push_assign(block, source_info, &is_min, Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval)); @@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } ExprKind::Box { value, value_extents } => { let value = this.hir.mirror(value); - let result = this.temp(expr.ty); + let result = this.temp(expr.ty, expr_span); // to start, malloc some memory of suitable type (thus far, uninitialized): this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty)); this.in_scope(value_extents, block, |this| { @@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = self.hir.bool_ty(); if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() { let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty], false); - let result_value = self.temp(result_tup); + let result_value = self.temp(result_tup, span); self.cfg.push_assign(block, source_info, &result_value, Rvalue::CheckedBinaryOp(op, @@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; // Check for / 0 - let is_zero = self.temp(bool_ty); + let is_zero = self.temp(bool_ty, span); let zero = self.zero_literal(span, ty); self.cfg.push_assign(block, source_info, &is_zero, Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero)); @@ -315,9 +315,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let neg_1 = self.neg_1_literal(span, ty); let min = self.minval_literal(span, ty); - let is_neg_1 = self.temp(bool_ty); - let is_min = self.temp(bool_ty); - let of = self.temp(bool_ty); + let is_neg_1 = self.temp(bool_ty, span); + let is_min = self.temp(bool_ty, span); + let of = self.temp(bool_ty, span); // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 42d9ab4d2bf2..e4598b414387 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -44,8 +44,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let expr_ty = expr.ty.clone(); - let temp = this.temp(expr_ty.clone()); let expr_span = expr.span; + let temp = this.temp(expr_ty.clone(), expr_span); let source_info = this.source_info(expr_span); if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) { diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 7336da654c18..c03432312b0a 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => { let expr_ty = expr.ty; - let temp = this.temp(expr.ty.clone()); + let temp = this.temp(expr.ty.clone(), expr_span); unpack!(block = this.into(&temp, block, expr)); unpack!(block = this.build_drop(block, expr_span, temp, expr_ty)); block.unit() diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 705eb1f56608..ddeec1fe6d0b 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -710,7 +710,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mutability: mutability, ty: var_ty.clone(), name: Some(name), - source_info: Some(source_info), + source_info: source_info, + is_user_variable: true, }); self.var_indices.insert(var_id, var); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index f4fdf8ade900..5fece4d6a5d2 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", num_enum_variants, values, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); - let discr = self.temp(discr_ty); + let discr = self.temp(discr_ty, test.span); self.cfg.push_assign(block, source_info, &discr, Rvalue::Discriminant(lvalue.clone())); assert_eq!(values.len() + 1, targets.len()); @@ -270,7 +270,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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); + 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::Consume(val_slice); @@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: value.clone() }); - let slice = self.temp(ty); + let slice = self.temp(ty, test.span); self.cfg.push_assign(block, source_info, &slice, Rvalue::Cast(CastKind::Unsize, array, ty)); Operand::Consume(slice) @@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); - let eq_result = self.temp(bool_ty); + let eq_result = self.temp(bool_ty, test.span); let eq_block = self.cfg.start_new_block(); let cleanup = self.diverge_cleanup(); self.cfg.terminate(block, source_info, TerminatorKind::Call { @@ -349,7 +349,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TestKind::Len { len, op } => { let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty()); - let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty)); + let (actual, result) = (self.temp(usize_ty, test.span), + self.temp(bool_ty, test.span)); // actual = len(lvalue) self.cfg.push_assign(block, source_info, @@ -383,7 +384,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { left: Operand<'tcx>, right: Operand<'tcx>) -> BasicBlock { let bool_ty = self.hir.bool_ty(); - let result = self.temp(bool_ty); + let result = self.temp(bool_ty, span); // result = op(left, right) let source_info = self.source_info(span); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 99aa5cb0fa86..35a8b245f2bb 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -27,8 +27,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// /// NB: **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. - pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> { - let temp = self.local_decls.push(LocalDecl::new_temp(ty)); + pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Lvalue<'tcx> { + let temp = self.local_decls.push(LocalDecl::new_temp(ty, span)); let lvalue = Lvalue::Local(temp); debug!("temp: created temp {:?} with type {:?}", lvalue, self.local_decls[temp].ty); @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: u64) -> Lvalue<'tcx> { let usize_ty = self.hir.usize_ty(); - let temp = self.temp(usize_ty); + let temp = self.temp(usize_ty, source_info.span); self.cfg.push_assign_constant( block, source_info, &temp, Constant { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index db03a1c68f71..ef3fa23500b3 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -249,7 +249,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, breakable_scopes: vec![], - local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), + local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty, + span), 1), var_indices: NodeMap(), unit_temp: None, cached_resume_block: None, @@ -304,8 +305,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.local_decls.push(LocalDecl { mutability: Mutability::Not, ty: ty, - source_info: None, + source_info: SourceInfo { + scope: ARGUMENT_VISIBILITY_SCOPE, + span: pattern.map_or(self.fn_span, |pat| pat.span) + }, name: name, + is_user_variable: false, }); } @@ -341,7 +346,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Some(ref tmp) => tmp.clone(), None => { let ty = self.hir.unit_ty(); - let tmp = self.temp(ty); + let fn_span = self.fn_span; + let tmp = self.temp(ty, fn_span); self.unit_temp = Some(tmp.clone()); tmp } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 63d20be88fee..0cec84d16a81 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -137,16 +137,20 @@ enum CallKind { Direct(DefId), } -fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl { - LocalDecl { mutability, ty, name: None, source_info: None } +fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl { + LocalDecl { + mutability, ty, name: None, + source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span }, + is_user_variable: false + } } -fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>) +fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span) -> IndexVec> { - iter::once(temp_decl(Mutability::Mut, sig.output())) + iter::once(temp_decl(Mutability::Mut, sig.output(), span)) .chain(sig.inputs().iter().map( - |ity| temp_decl(Mutability::Not, ity))) + |ity| temp_decl(Mutability::Not, ity, span))) .collect() } @@ -188,7 +192,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ), IndexVec::new(), sig.output(), - local_decls_for_sig(&sig), + local_decls_for_sig(&sig, span), sig.inputs().len(), vec![], span @@ -297,7 +301,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, debug!("build_call_shim: sig={:?}", sig); - let mut local_decls = local_decls_for_sig(&sig); + let mut local_decls = local_decls_for_sig(&sig, span); let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }; let rcvr_arg = Local::new(1+0); @@ -317,7 +321,8 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, tcx.mk_ref(re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::MutMutable - }) + }), + span )); statements.push(Statement { source_info: source_info, @@ -442,7 +447,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields); - let local_decls = local_decls_for_sig(&sig); + let local_decls = local_decls_for_sig(&sig, span); let source_info = SourceInfo { span: span, diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 80a9c06f11b2..ac2bdaad24f7 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -461,11 +461,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { for loc in callee_mir.vars_and_temps_iter() { let mut local = callee_mir.local_decls[loc].clone(); - if let Some(ref mut source_info) = local.source_info { - source_info.scope = scope_map[source_info.scope]; - - source_info.span = callsite.location.span; - } + local.source_info.scope = scope_map[local.source_info.scope]; + local.source_info.span = callsite.location.span; let idx = caller_mir.local_decls.push(local); local_map.push(idx); @@ -506,7 +503,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ty = dest.ty(caller_mir, self.tcx); - let temp = LocalDecl::new_temp(ty); + let temp = LocalDecl::new_temp(ty, callsite.location.span); let tmp = caller_mir.local_decls.push(temp); let tmp = Lvalue::Local(tmp); @@ -590,7 +587,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { arg.deref()); let ty = arg.ty(caller_mir, self.tcx); - let ref_tmp = LocalDecl::new_temp(ty); + let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span); let ref_tmp = caller_mir.local_decls.push(ref_tmp); let ref_tmp = Lvalue::Local(ref_tmp); @@ -611,7 +608,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty); - let cast_tmp = LocalDecl::new_temp(ptr_ty); + let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span); let cast_tmp = caller_mir.local_decls.push(cast_tmp); let cast_tmp = Lvalue::Local(cast_tmp); @@ -645,7 +642,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let ty = arg.ty(caller_mir, tcx); - let arg_tmp = LocalDecl::new_temp(ty); + let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); let arg_tmp = caller_mir.local_decls.push(arg_tmp); let arg_tmp = Lvalue::Local(arg_tmp); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 57cf4b1e8b02..ed9a0d3809f2 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -208,7 +208,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let no_stmts = self.source[loc.block].statements.len(); let new_temp = self.promoted.local_decls.push( - LocalDecl::new_temp(self.source.local_decls[temp].ty)); + LocalDecl::new_temp(self.source.local_decls[temp].ty, + self.source.local_decls[temp].source_info.span)); debug!("promote({:?} @ {:?}/{:?}, {:?})", temp, loc, no_stmts, self.keep_original); @@ -379,7 +380,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }; // Declare return pointer local - let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect(); + let initial_locals = iter::once(LocalDecl::new_return_pointer(ty, span)) + .collect(); let mut promoter = Promoter { promoted: Mir::new( diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8eabe92fb98c..1313b24fa74f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -881,7 +881,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Avoid a generic error for other uses of arguments. if self.qualif.intersects(Qualif::FN_ARGUMENT) { let decl = &self.mir.local_decls[index]; - span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022, + span_err!(self.tcx.sess, decl.source_info.span, E0022, "arguments of constant functions can only \ be immutable by-value bindings"); return; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index ccbc6700d89c..04a1fc891cf1 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -686,7 +686,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> } fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { - self.elaborator.patch().new_temp(ty) + self.elaborator.patch().new_temp(ty, self.source_info.span) } fn terminator_loc(&mut self, bb: BasicBlock) -> Location { diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 19f240da7305..7898d93c22e3 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -11,6 +11,7 @@ use rustc::ty::Ty; use rustc::mir::*; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use syntax_pos::Span; /// This struct represents a patch to MIR, which can add /// new statements and basic blocks and patch over block @@ -92,10 +93,10 @@ impl<'tcx> MirPatch<'tcx> { } } - pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { + pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; - self.new_locals.push(LocalDecl::new_temp(ty)); + self.new_locals.push(LocalDecl::new_temp(ty, span)); Local::new(index as usize) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index ef2bf6e54342..b202e1495104 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -196,8 +196,8 @@ fn write_scope_tree(tcx: TyCtxt, // User variable types (including the user's name in a comment). for local in mir.vars_iter() { let var = &mir.local_decls[local]; - let (name, source_info) = if var.source_info.unwrap().scope == child { - (var.name.unwrap(), var.source_info.unwrap()) + let (name, source_info) = if var.source_info.scope == child { + (var.name.unwrap(), var.source_info) } else { // Not a variable or not declared in this scope. continue; diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index c6f8ba7b6dc7..3d074c31c8a3 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -65,7 +65,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function 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.unwrap().scope.index()); + has_variables.insert(decl.source_info.scope.index()); } // Instantiate all scopes. diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c8d15d28708f..892a27e4550a 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -255,8 +255,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( if let Some(name) = decl.name { // User variable - let source_info = decl.source_info.unwrap(); - let debug_scope = mircx.scopes[source_info.scope]; + let debug_scope = mircx.scopes[decl.source_info.scope]; let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo; if !lvalue_locals.contains(local.index()) && !dbg { @@ -268,7 +267,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( assert!(!ty.has_erasable_regions()); let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str()); if dbg { - let (scope, span) = mircx.debug_loc(source_info); + let (scope, span) = mircx.debug_loc(decl.source_info); declare_local(&bcx, &mircx.debug_context, name, ty, scope, VariableAccess::DirectVariable { alloca: lvalue.llval }, VariableKind::LocalVariable, span); From 56503dd4adf65518a9645409e534935c2f434fe2 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 11 Apr 2017 22:53:16 +0200 Subject: [PATCH 419/905] use correct vault url --- src/ci/docker/dist-i686-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index b322f56f0d04..c25c770136f9 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index cbe5f5936a50..e835e8d2f716 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /build # to http://vault.centos.org/ RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo -RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo RUN yum upgrade -y && yum install -y \ curl \ From 0144613078b8210a774f51d7bf6282812bef1e91 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 11 Apr 2017 23:53:20 +0300 Subject: [PATCH 420/905] Move rvalue checking to MIR Fixes #41139. --- src/librustc_driver/driver.rs | 8 +- src/librustc_mir/diagnostics.rs | 33 ++++++++ src/librustc_mir/transform/type_check.rs | 48 ++++++++++- src/librustc_passes/diagnostics.rs | 33 -------- src/librustc_passes/lib.rs | 1 - src/librustc_passes/rvalues.rs | 103 ----------------------- src/test/compile-fail/issue-41139.rs | 18 ++++ 7 files changed, 97 insertions(+), 147 deletions(-) delete mode 100644 src/librustc_passes/rvalues.rs create mode 100644 src/test/compile-fail/issue-41139.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bdb05d06b0b1..4dfffe7fd5c9 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -35,7 +35,7 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, +use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats, mir_stats}; use rustc_const_eval::check_match; use super::Compilation; @@ -957,10 +957,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "liveness checking", || middle::liveness::check_crate(tcx)); - time(time_passes, - "rvalue checking", - || rvalues::check_crate(tcx)); - time(time_passes, "MIR dump", || mir::mir_map::build_mir_for_crate(tcx)); @@ -976,8 +972,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // in stage 4 below. passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial")); - passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass(box mir::transform::type_check::TypeckMir); + passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass( box mir::transform::simplify_branches::SimplifyBranches::new("initial")); passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index eb16812af9b0..bb07081fe433 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -244,6 +244,39 @@ let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; ``` "##, +E0161: r##" +A value was moved. However, its size was not known at compile time, and only +values of a known size can be moved. + +Erroneous code example: + +```compile_fail +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<[isize]> = box *array; + // error: cannot move a value of type [isize]: the size of [isize] cannot + // be statically determined +} +``` + +In Rust, you can only move a value when its size is known at compile time. + +To work around this restriction, consider "hiding" the value behind a reference: +either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move +it around as usual. Example: + +``` +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<&[isize]> = box array; // ok! +} +``` +"##, + E0396: r##" The value behind a raw pointer can't be determined at compile-time (or even link-time), which means it can't be used in a constant diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 3d604affbfea..f209b93cee18 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -24,6 +24,7 @@ use std::fmt; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { @@ -87,6 +88,11 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.sanitize_type(rvalue, rval_ty); } + fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) { + self.super_local_decl(local_decl); + self.sanitize_type(local_decl, local_decl.ty); + } + fn visit_mir(&mut self, mir: &Mir<'tcx>) { self.sanitize_type(&"return type", mir.return_ty); for local_decl in &mir.local_decls { @@ -317,6 +323,7 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fulfillment_cx: traits::FulfillmentContext<'tcx>, last_span: Span, body_id: ast::NodeId, + reported_errors: FxHashSet<(Ty<'tcx>, Span)>, } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { @@ -326,6 +333,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fulfillment_cx: traits::FulfillmentContext::new(), last_span: DUMMY_SP, body_id: body_id, + reported_errors: FxHashSet(), } } @@ -641,9 +649,39 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn typeck_mir(&mut self, mir: &Mir<'tcx>) { + fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) { + match mir.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Arg => { + // return values of normal functions are required to be + // sized by typeck, but return values of ADT constructors are + // not because we don't include a `Self: Sized` bounds on them. + // + // Unbound parts of arguments were never required to be Sized + // - maybe we should make that a warning. + return + } + LocalKind::Var | LocalKind::Temp => {} + } + + let span = local_decl.source_info.span; + let ty = local_decl.ty; + if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) { + if let None = self.reported_errors.replace((ty, span)) { + span_err!(self.tcx().sess, span, E0161, + "cannot move a value of type {0}: the size of {0} \ + cannot be statically determined", ty); + } + } + } + + fn typeck_mir(&mut self, mir: &Mir<'gcx>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); + + for (local, local_decl) in mir.local_decls.iter_enumerated() { + self.check_local(mir, local, local_decl); + } + for block in mir.basic_blocks() { for stmt in &block.statements { if stmt.source_info.span != DUMMY_SP { @@ -698,16 +736,18 @@ impl TypeckMir { impl<'tcx> MirPass<'tcx> for TypeckMir { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { - debug!("run_pass: {}", tcx.node_path_str(src.item_id())); + let item_id = src.item_id(); + let def_id = tcx.hir.local_def_id(item_id); + debug!("run_pass: {}", tcx.item_path_str(def_id)); if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. return; } - let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id()); + let param_env = ty::ParameterEnvironment::for_item(tcx, item_id); tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { - let mut checker = TypeChecker::new(&infcx, src.item_id()); + let mut checker = TypeChecker::new(&infcx, item_id); { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 5f06eadb84a9..036a52d5a3db 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -82,39 +82,6 @@ extern { ``` "##, -E0161: r##" -A value was moved. However, its size was not known at compile time, and only -values of a known size can be moved. - -Erroneous code example: - -```compile_fail -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<[isize]> = box *array; - // error: cannot move a value of type [isize]: the size of [isize] cannot - // be statically determined -} -``` - -In Rust, you can only move a value when its size is known at compile time. - -To work around this restriction, consider "hiding" the value behind a reference: -either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move -it around as usual. Example: - -``` -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<&[isize]> = box array; // ok! -} -``` -"##, - E0265: r##" This error indicates that a static or constant references itself. All statics and constants need to resolve to a value in an acyclic manner. diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 7a465f0ec423..22566c813d86 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -47,5 +47,4 @@ pub mod hir_stats; pub mod loops; pub mod mir_stats; pub mod no_asm; -pub mod rvalues; pub mod static_recursion; diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs deleted file mode 100644 index c367e71fcd24..000000000000 --- a/src/librustc_passes/rvalues.rs +++ /dev/null @@ -1,103 +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. - -// Checks that all rvalues in a crate have statically known size. check_crate -// is the public starting point. - -use rustc::dep_graph::DepNode; -use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization as mc; -use rustc::ty::{self, TyCtxt}; -use rustc::traits::Reveal; - -use rustc::hir; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use syntax::ast; -use syntax_pos::Span; - -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut rvcx = RvalueContext { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor()); -} - -struct RvalueContext<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_nested_body(&mut self, body_id: hir::BodyId) { - let body = self.tcx.hir.body(body_id); - self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { - let mut delegate = RvalueContextDelegate { - tcx: infcx.tcx, - param_env: &infcx.parameter_environment - }; - euv::ExprUseVisitor::new(&mut delegate, &infcx).consume_body(body); - }); - self.visit_body(body); - } -} - -struct RvalueContextDelegate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - param_env: &'a ty::ParameterEnvironment<'gcx>, -} - -impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tcx> { - fn consume(&mut self, - _: ast::NodeId, - span: Span, - cmt: mc::cmt<'tcx>, - _: euv::ConsumeMode) { - debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty); - let ty = self.tcx.lift_to_global(&cmt.ty).unwrap(); - if !ty.is_sized(self.tcx.global_tcx(), self.param_env, span) { - span_err!(self.tcx.sess, span, E0161, - "cannot move a value of type {0}: the size of {0} cannot be statically determined", - ty); - } - } - - fn matched_pat(&mut self, - _matched_pat: &hir::Pat, - _cmt: mc::cmt, - _mode: euv::MatchMode) {} - - fn consume_pat(&mut self, - _consume_pat: &hir::Pat, - _cmt: mc::cmt, - _mode: euv::ConsumeMode) { - } - - fn borrow(&mut self, - _borrow_id: ast::NodeId, - _borrow_span: Span, - _cmt: mc::cmt, - _loan_region: &'tcx ty::Region, - _bk: ty::BorrowKind, - _loan_cause: euv::LoanCause) { - } - - fn decl_without_init(&mut self, - _id: ast::NodeId, - _span: Span) { - } - - fn mutate(&mut self, - _assignment_id: ast::NodeId, - _assignment_span: Span, - _assignee_cmt: mc::cmt, - _mode: euv::MutateMode) { - } -} diff --git a/src/test/compile-fail/issue-41139.rs b/src/test/compile-fail/issue-41139.rs new file mode 100644 index 000000000000..15ca151c49a7 --- /dev/null +++ b/src/test/compile-fail/issue-41139.rs @@ -0,0 +1,18 @@ +// 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. + +trait Trait {} + +fn get_function<'a>() -> &'a Fn() -> Trait { panic!("") } + +fn main() { + let t : &Trait = &get_function()(); + //~^ ERROR cannot move a value of type Trait + 'static +} From 540a069761c1184ee2998f23a24b76c97c274043 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 12 Apr 2017 00:44:17 +0300 Subject: [PATCH 421/905] address review comments --- src/librustc_mir/transform/type_check.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index f209b93cee18..bfb08de56d8b 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -666,6 +666,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let span = local_decl.source_info.span; let ty = local_decl.ty; if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) { + // in current MIR construction, all non-control-flow rvalue + // expressions evaluate through `as_temp` or `into` a return + // slot or local, so to find all unsized rvalues it is enough + // to check all temps, return slots and locals. if let None = self.reported_errors.replace((ty, span)) { span_err!(self.tcx().sess, span, E0161, "cannot move a value of type {0}: the size of {0} \ From 2389830deaf39b736e35c471e39543d30f708972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 Feb 2017 14:31:59 -0800 Subject: [PATCH 422/905] Highlight and simplify mismatched types Shorten mismatched types errors by replacing subtypes that are not different with `_`, and highlighting only the subtypes that are different. Given a file ```rust struct X { x: T1, y: T2, } fn foo() -> X, String> { X { x: X {x: "".to_string(), y: 2}, y: "".to_string()} } fn bar() -> Option { "".to_string() } ``` provide the following output ```rust error[E0308]: mismatched types --> file.rs:6:5 | 6 | X { x: X {x: "".to_string(), y: 2}, y: "".to_string()} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found {integer} | = note: expected type `X, _>` ^^^^^^^^^^^^^^^^^^^ // < highlighted found type `X, _>` ^^^^^^^^^ // < highlighted error[E0308]: mismatched types --> file.rs:6:5 | 10 | "".to_string() | ^^^^^^^^^^^^^^ expected struct `std::option::Option`, found `std::string::String` | = note: expected type `Option` ^^^^^^^ ^ // < highlighted found type `std::string::String` ``` --- src/librustc/infer/error_reporting/mod.rs | 288 +++++++++++++++++- src/librustc/infer/error_reporting/note.rs | 2 + src/librustc/ty/mod.rs | 2 +- src/librustc_errors/diagnostic.rs | 72 ++++- src/librustc_errors/diagnostic_builder.rs | 10 +- src/librustc_errors/lib.rs | 2 +- .../ex2a-push-one-existing-name.stderr | 4 +- .../ex2b-push-no-existing-names.stderr | 4 +- .../ex2c-push-inference-variable.stderr | 2 +- src/test/ui/mismatched_types/abridged.rs | 61 ++++ src/test/ui/mismatched_types/abridged.stderr | 70 +++++ 11 files changed, 485 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/mismatched_types/abridged.rs create mode 100644 src/test/ui/mismatched_types/abridged.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 9fa2bc8a2a7a..dcbe50de2e9b 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -70,7 +70,7 @@ use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, Issue32330}; use ty::error::TypeError; use syntax_pos::{Pos, Span}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticStyledString}; mod note; @@ -365,6 +365,262 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` + /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and + /// populate `other_value` with `other_ty`. + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn highlight_outer(&self, + mut value: &mut DiagnosticStyledString, + mut other_value: &mut DiagnosticStyledString, + name: String, + sub: &ty::subst::Substs<'tcx>, + pos: usize, + other_ty: &ty::Ty<'tcx>) { + // `value` and `other_value` hold two incomplete type representation for display. + // `name` is the path of both types being compared. `sub` + value.push_highlighted(name); + let len = sub.len(); + if len > 0 { + value.push_highlighted("<"); + } + + // Output the lifetimes fot the first type + let lifetimes = sub.regions().map(|lifetime| { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + }).collect::>().join(", "); + if !lifetimes.is_empty() { + if sub.regions().count() < len { + value.push_normal(lifetimes + &", "); + } else { + value.push_normal(lifetimes); + } + } + + // Highlight all the type arguments that aren't at `pos` and compare the type argument at + // `pos` and `other_ty`. + for (i, type_arg) in sub.types().enumerate() { + if i == pos { + let values = self.cmp(type_arg, other_ty); + value.0.extend((values.0).0); + other_value.0.extend((values.1).0); + } else { + value.push_highlighted(format!("{}", type_arg)); + } + + if len > 0 && i != len - 1 { + value.push_normal(", "); + } + //self.push_comma(&mut value, &mut other_value, len, i); + } + if len > 0 { + value.push_highlighted(">"); + } + } + + /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, + /// as that is the difference to the other type. + /// + /// For the following code: + /// + /// ```norun + /// let x: Foo> = foo::>(); + /// ``` + /// + /// The type error output will behave in the following way: + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn cmp_type_arg(&self, + mut t1_out: &mut DiagnosticStyledString, + mut t2_out: &mut DiagnosticStyledString, + path: String, + sub: &ty::subst::Substs<'tcx>, + other_path: String, + other_ty: &ty::Ty<'tcx>) -> Option<()> { + for (i, ta) in sub.types().enumerate() { + if &ta == other_ty { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + if let &ty::TyAdt(def, _) = &ta.sty { + let path_ = self.tcx.item_path_str(def.did.clone()); + if path_ == other_path { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + } + } + None + } + + /// Add a `,` to the type representation only if it is appropriate. + fn push_comma(&self, + value: &mut DiagnosticStyledString, + other_value: &mut DiagnosticStyledString, + len: usize, + pos: usize) { + if len > 0 && pos != len - 1 { + value.push_normal(", "); + other_value.push_normal(", "); + } + } + + /// Compare two given types, eliding parts that are the same between them and highlighting + /// relevant differences, and return two representation of those types for highlighted printing. + fn cmp(&self, t1: ty::Ty<'tcx>, t2: ty::Ty<'tcx>) + -> (DiagnosticStyledString, DiagnosticStyledString) + { + match (&t1.sty, &t2.sty) { + (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { + let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); + let path1 = self.tcx.item_path_str(def1.did.clone()); + let path2 = self.tcx.item_path_str(def2.did.clone()); + if def1.did == def2.did { + // Easy case. Replace same types with `_` to shorten the output and highlight + // the differing ones. + // let x: Foo = y::>(); + // Foo + // Foo + // --- ^ type argument elided + // | + // highlighted in output + values.0.push_normal(path1); + values.1.push_normal(path2); + + // Only draw `<...>` if there're lifetime/type arguments. + let len = sub1.len(); + if len > 0 { + values.0.push_normal("<"); + values.1.push_normal("<"); + } + + fn lifetime_display(lifetime: &Region) -> String { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + } + // At one point we'd like to elide all lifetimes here, they are irrelevant for + // all diagnostics that use this output + // + // Foo<'x, '_, Bar> + // Foo<'y, '_, Qux> + // ^^ ^^ --- type arguments are not elided + // | | + // | elided as they were the same + // not elided, they were different, but irrelevant + let lifetimes = sub1.regions().zip(sub2.regions()); + for (i, lifetimes) in lifetimes.enumerate() { + let l1 = lifetime_display(lifetimes.0); + let l2 = lifetime_display(lifetimes.1); + if l1 == l2 { + values.0.push_normal("'_"); + values.1.push_normal("'_"); + } else { + values.0.push_highlighted(l1); + values.1.push_highlighted(l2); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // We're comparing two types with the same path, so we compare the type + // arguments for both. If they are the same, do not highlight and elide from the + // output. + // Foo<_, Bar> + // Foo<_, Qux> + // ^ elided type as this type argument was the same in both sides + let type_arguments = sub1.types().zip(sub2.types()); + let regions_len = sub1.regions().collect::>().len(); + for (i, (ta1, ta2)) in type_arguments.enumerate() { + let i = i + regions_len; + if ta1 == ta2 { + values.0.push_normal("_"); + values.1.push_normal("_"); + } else { + let (x1, x2) = self.cmp(ta1, ta2); + (values.0).0.extend(x1.0); + (values.1).0.extend(x2.0); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // Close the type argument bracket. + // Only draw `<...>` if there're lifetime/type arguments. + if len > 0 { + values.0.push_normal(">"); + values.1.push_normal(">"); + } + values + } else { + // Check for case: + // let x: Foo = foo::>(); + // Foo + // ------- this type argument is exactly the same as the other type + // Bar + if self.cmp_type_arg(&mut values.0, + &mut values.1, + path1.clone(), + sub1, + path2.clone(), + &t2).is_some() { + return values; + } + // Check for case: + // let x: Bar = y:>>(); + // Bar + // Foo> + // ------- this type argument is exactly the same as the other type + if self.cmp_type_arg(&mut values.1, + &mut values.0, + path2, + sub2, + path1, + &t1).is_some() { + return values; + } + + // We couldn't find anything in common, highlight everything. + // let x: Bar = y::>(); + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + _ => { + if t1 == t2 { + // The two types are the same, elide and don't highlight. + (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) + } else { + // We couldn't find anything in common, highlight everything. + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + } + } + pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, @@ -397,14 +653,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { - (&TypeError::Sorts(ref values), false, true) => { + (&TypeError::Sorts(ref values), false, true) => { diag.note_expected_found_extra( - &"type", &expected, &found, + &"type", expected, found, &format!(" ({})", values.expected.sort_string(self.tcx)), &format!(" ({})", values.found.sort_string(self.tcx))); } (_, false, _) => { - diag.note_expected_found(&"type", &expected, &found); + diag.note_expected_found(&"type", expected, found); } _ => (), } @@ -472,26 +728,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag } - /// Returns a string of the form "expected `{}`, found `{}`". - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { + fn values_str(&self, values: &ValuePairs<'tcx>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> + { match *values { - infer::Types(ref exp_found) => self.expected_found_str(exp_found), + infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } } + fn expected_found_str_ty(&self, + exp_found: &ty::error::ExpectedFound>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { + let exp_found = self.resolve_type_vars_if_possible(exp_found); + if exp_found.references_error() { + return None; + } + + Some(self.cmp(exp_found.expected, exp_found.found)) + } + + /// Returns a string of the form "expected `{}`, found `{}`". fn expected_found_str>( &self, exp_found: &ty::error::ExpectedFound) - -> Option<(String, String)> + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_type_vars_if_possible(exp_found); if exp_found.references_error() { return None; } - Some((format!("{}", exp_found.expected), format!("{}", exp_found.found))) + Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), + DiagnosticStyledString::highlighted(format!("{}", exp_found.found)))) } fn report_generic_bound_failure(&self, diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 8f8b2603dad8..8b753e0d22be 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -20,6 +20,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match *origin { infer::Subtype(ref trace) => { if let Some((expected, found)) = self.values_str(&trace.values) { + let expected = expected.content(); + let found = found.content(); // FIXME: do we want a "the" here? err.span_note(trace.cause.span, &format!("...so that {} (expected {}, found {})", diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f..3c51fd546c7c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2218,7 +2218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `DefId` is really just an interned def-path). /// /// Note that if `id` is not local to this crate, the result will - // be a non-local `DefPath`. + /// be a non-local `DefPath`. pub fn def_path(self, id: DefId) -> hir_map::DefPath { if id.is_local() { self.hir.def_path(id) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 1b77ead92deb..9715ace3e2e2 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -35,6 +35,46 @@ pub struct SubDiagnostic { pub render_span: Option, } +#[derive(PartialEq, Eq)] +pub struct DiagnosticStyledString(pub Vec); + +impl DiagnosticStyledString { + pub fn new() -> DiagnosticStyledString { + DiagnosticStyledString(vec![]) + } + pub fn push_normal>(&mut self, t: S) { + self.0.push(StringPart::Normal(t.into())); + } + pub fn push_highlighted>(&mut self, t: S) { + self.0.push(StringPart::Highlighted(t.into())); + } + pub fn normal>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Normal(t.into())]) + } + + pub fn highlighted>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) + } + + pub fn content(&self) -> String { + self.0.iter().map(|x| x.content()).collect::() + } +} + +#[derive(PartialEq, Eq)] +pub enum StringPart { + Normal(String), + Highlighted(String), +} + +impl StringPart { + pub fn content(&self) -> String { + match self { + &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned() + } + } +} + impl Diagnostic { pub fn new(level: Level, message: &str) -> Self { Diagnostic::new_with_code(level, None, message) @@ -81,8 +121,8 @@ impl Diagnostic { pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self { self.note_expected_found_extra(label, expected, found, &"", &"") @@ -90,21 +130,29 @@ impl Diagnostic { pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self { + let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)]; + msg.extend(expected.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}\n", expected_extra), Style::NoStyle)); + msg.push((format!(" found {} `", label), Style::NoStyle)); + msg.extend(found.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}", found_extra), Style::NoStyle)); + // For now, just attach these as notes - self.highlighted_note(vec![ - (format!("expected {} `", label), Style::NoStyle), - (format!("{}", expected), Style::Highlight), - (format!("`{}\n", expected_extra), Style::NoStyle), - (format!(" found {} `", label), Style::NoStyle), - (format!("{}", found), Style::Highlight), - (format!("`{}", found_extra), Style::NoStyle), - ]); + self.highlighted_note(msg); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7dfea6b8951b..7b27f13951b6 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -9,6 +9,8 @@ // except according to those terms. use Diagnostic; +use DiagnosticStyledString; + use Level; use Handler; use std::fmt::{self, Debug}; @@ -115,14 +117,14 @@ impl<'a> DiagnosticBuilder<'a> { forward!(pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self); forward!(pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self); diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 2efdaa57fba3..da29e354a701 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -203,7 +203,7 @@ impl error::Error for ExplicitBug { } } -pub use diagnostic::{Diagnostic, SubDiagnostic}; +pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, StringPart}; pub use diagnostic_builder::DiagnosticBuilder; /// A handler deals with errors; certain errors diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr index 6f42a9f679a6..6956a043cc69 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 16 | x.push(y); | ^ lifetime mismatch | - = note: expected type `Ref<'a, i32>` - found type `Ref<'_, i32>` + = note: expected type `Ref<'a, _>` + found type `Ref<'_, _>` note: the anonymous lifetime #2 defined on the body at 15:51... --> $DIR/ex2a-push-one-existing-name.rs:15:52 | diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr index edc1c2362de5..990ae65ba985 100644 --- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 16 | x.push(y); | ^ lifetime mismatch | - = note: expected type `Ref<'_, i32>` - found type `Ref<'_, i32>` + = note: expected type `Ref<'_, _>` + found type `Ref<'_, _>` note: the anonymous lifetime #3 defined on the body at 15:43... --> $DIR/ex2b-push-no-existing-names.rs:15:44 | diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr index 755b71d4a1d9..82f6c71ec1c2 100644 --- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr +++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr @@ -27,7 +27,7 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body 17 | | x.push(z); 18 | | } | |_^ ...ending here -note: ...so that expression is assignable (expected Ref<'b, i32>, found Ref<'_, i32>) +note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>) --> $DIR/ex2c-push-inference-variable.rs:17:12 | 17 | x.push(z); diff --git a/src/test/ui/mismatched_types/abridged.rs b/src/test/ui/mismatched_types/abridged.rs new file mode 100644 index 000000000000..c448ad955fab --- /dev/null +++ b/src/test/ui/mismatched_types/abridged.rs @@ -0,0 +1,61 @@ +// 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. + +enum Bar { + Qux, + Zar, +} + +struct Foo { + bar: usize, +} + +struct X { + x: T1, + y: T2, +} + +fn a() -> Foo { + Some(Foo { bar: 1 }) +} + +fn a2() -> Foo { + Ok(Foo { bar: 1}) +} + +fn b() -> Option { + Foo { bar: 1 } +} + +fn c() -> Result { + Foo { bar: 1 } +} + +fn d() -> X, String> { + X { + x: X { + x: "".to_string(), + y: 2, + }, + y: 3, + } +} + +fn e() -> X, String> { + X { + x: X { + x: "".to_string(), + y: 2, + }, + y: "".to_string(), + } +} + +fn main() {} diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr new file mode 100644 index 000000000000..c67c6113d17c --- /dev/null +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -0,0 +1,70 @@ +error[E0308]: mismatched types + --> $DIR/abridged.rs:26:5 + | +26 | Some(Foo { bar: 1 }) + | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option` + | + = note: expected type `Foo` + found type `std::option::Option` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:30:5 + | +30 | Ok(Foo { bar: 1}) + | ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result` + | + = note: expected type `Foo` + found type `std::result::Result` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:34:5 + | +34 | Foo { bar: 1 } + | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo` + | + = note: expected type `std::option::Option` + found type `Foo` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:38:5 + | +38 | Foo { bar: 1 } + | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo` + | + = note: expected type `std::result::Result` + found type `Foo` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:42:5 + | +42 | X { + | _____^ starting here... +43 | | x: X { +44 | | x: "".to_string(), +45 | | y: 2, +46 | | }, +47 | | y: 3, +48 | | } + | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | + = note: expected type `X, std::string::String>` + found type `X, {integer}>` + +error[E0308]: mismatched types + --> $DIR/abridged.rs:52:5 + | +52 | X { + | _____^ starting here... +53 | | x: X { +54 | | x: "".to_string(), +55 | | y: 2, +56 | | }, +57 | | y: "".to_string(), +58 | | } + | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | + = note: expected type `X, _>` + found type `X, _>` + +error: aborting due to 6 previous errors + From 4a0a0e949a077a6d83ca152daa404ff47c9c1dcf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 21:29:22 -0500 Subject: [PATCH 423/905] remove type variable defaults code This just limits ourselves to the "old school" defaults: diverging variables and integer variables. --- src/librustc_typeck/check/mod.rs | 211 +----------------- .../compile-fail/default_ty_param_conflict.rs | 33 --- .../default_ty_param_conflict_cross_crate.rs | 32 --- ...param_default_dependent_associated_type.rs | 36 --- .../default_ty_param_dependent_defaults.rs | 19 -- .../default_ty_param_method_call_test.rs | 24 -- src/test/run-pass/default_ty_param_struct.rs | 23 -- .../default_ty_param_struct_and_type_alias.rs | 40 ---- .../run-pass/default_ty_param_trait_impl.rs | 25 --- .../default_ty_param_trait_impl_simple.rs | 26 --- .../run-pass/default_ty_param_type_alias.rs | 19 -- 11 files changed, 3 insertions(+), 485 deletions(-) delete mode 100644 src/test/compile-fail/default_ty_param_conflict.rs delete mode 100644 src/test/compile-fail/default_ty_param_conflict_cross_crate.rs delete mode 100644 src/test/run-pass/default_ty_param_default_dependent_associated_type.rs delete mode 100644 src/test/run-pass/default_ty_param_dependent_defaults.rs delete mode 100644 src/test/run-pass/default_ty_param_method_call_test.rs delete mode 100644 src/test/run-pass/default_ty_param_struct.rs delete mode 100644 src/test/run-pass/default_ty_param_struct_and_type_alias.rs delete mode 100644 src/test/run-pass/default_ty_param_trait_impl.rs delete mode 100644 src/test/run-pass/default_ty_param_trait_impl_simple.rs delete mode 100644 src/test/run-pass/default_ty_param_type_alias.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c995b7e92843..d300552af2ca 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,7 +88,7 @@ use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; -use rustc::infer::type_variable::{self, TypeVariableOrigin}; +use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; @@ -105,7 +105,7 @@ use session::{Session, CompileResult}; use TypeAndSubsts; use lint; use util::common::{ErrorReported, indenter}; -use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap}; +use util::nodemap::{DefIdMap, FxHashMap, NodeMap}; use std::cell::{Cell, RefCell}; use std::cmp; @@ -1978,218 +1978,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + // Implements type inference fallback algorithm fn select_all_obligations_and_apply_defaults(&self) { - if self.tcx.sess.features.borrow().default_type_parameter_fallback { - self.new_select_all_obligations_and_apply_defaults(); - } else { - self.old_select_all_obligations_and_apply_defaults(); - } - } - - // Implements old type inference fallback algorithm - fn old_select_all_obligations_and_apply_defaults(&self) { self.select_obligations_where_possible(); self.default_type_parameters(); self.select_obligations_where_possible(); } - fn new_select_all_obligations_and_apply_defaults(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - // For the time being this errs on the side of being memory wasteful but provides better - // error reporting. - // let type_variables = self.type_variables.clone(); - - // There is a possibility that this algorithm will have to run an arbitrary number of times - // to terminate so we bound it by the compiler's recursion limit. - for _ in 0..self.tcx.sess.recursion_limit.get() { - // First we try to solve all obligations, it is possible that the last iteration - // has made it possible to make more progress. - self.select_obligations_where_possible(); - - let mut conflicts = Vec::new(); - - // Collect all unsolved type, integral and floating point variables. - let unsolved_variables = self.unsolved_variables(); - - // We must collect the defaults *before* we do any unification. Because we have - // directly attached defaults to the type variables any unification that occurs - // will erase defaults causing conflicting defaults to be completely ignored. - let default_map: FxHashMap, _> = - unsolved_variables - .iter() - .filter_map(|t| self.default(t).map(|d| (*t, d))) - .collect(); - - let mut unbound_tyvars = FxHashSet(); - - debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); - - // We loop over the unsolved variables, resolving them and if they are - // and unconstrainted numeric type we add them to the set of unbound - // variables. We do this so we only apply literal fallback to type - // variables without defaults. - for ty in &unsolved_variables { - let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt | UnconstrainedFloat => { - unbound_tyvars.insert(resolved); - }, - Neither => {} - } - } - } - - // We now remove any numeric types that also have defaults, and instead insert - // the type variable with a defined fallback. - for ty in &unsolved_variables { - if let Some(_default) = default_map.get(ty) { - let resolved = self.resolve_type_vars_if_possible(ty); - - debug!("select_all_obligations_and_apply_defaults: \ - ty: {:?} with default: {:?}", - ty, _default); - - match resolved.sty { - ty::TyInfer(ty::TyVar(_)) => { - unbound_tyvars.insert(ty); - } - - ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) => { - unbound_tyvars.insert(ty); - if unbound_tyvars.contains(resolved) { - unbound_tyvars.remove(resolved); - } - } - - _ => {} - } - } - } - - // If there are no more fallbacks to apply at this point we have applied all possible - // defaults and type inference will proceed as normal. - if unbound_tyvars.is_empty() { - break; - } - - // Finally we go through each of the unbound type variables and unify them with - // the proper fallback, reporting a conflicting default error if any of the - // unifications fail. We know it must be a conflicting default because the - // variable would only be in `unbound_tyvars` and have a concrete value if - // it had been solved by previously applying a default. - - // We wrap this in a transaction for error reporting, if we detect a conflict - // we will rollback the inference context to its prior state so we can probe - // for conflicts and correctly report them. - - let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| { - conflicts.extend( - self.apply_defaults_and_return_conflicts(&unbound_tyvars, &default_map, None) - ); - - // If there are conflicts we rollback, otherwise commit - if conflicts.len() > 0 { - Err(()) - } else { - Ok(()) - } - }); - - // Loop through each conflicting default, figuring out the default that caused - // a unification failure and then report an error for each. - for (conflict, default) in conflicts { - let conflicting_default = - self.apply_defaults_and_return_conflicts( - &unbound_tyvars, - &default_map, - Some(conflict) - ) - .last() - .map(|(_, tv)| tv) - .unwrap_or(type_variable::Default { - ty: self.next_ty_var( - TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)), - origin_span: syntax_pos::DUMMY_SP, - // what do I put here? - def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID) - }); - - // This is to ensure that we elimnate any non-determinism from the error - // reporting by fixing an order, it doesn't matter what order we choose - // just that it is consistent. - let (first_default, second_default) = - if default.def_id < conflicting_default.def_id { - (default, conflicting_default) - } else { - (conflicting_default, default) - }; - - - self.report_conflicting_default_types( - first_default.origin_span, - self.body_id, - first_default, - second_default) - } - } - - self.select_obligations_where_possible(); - } - - // For use in error handling related to default type parameter fallback. We explicitly - // apply the default that caused conflict first to a local version of the type variable - // table then apply defaults until we find a conflict. That default must be the one - // that caused conflict earlier. - fn apply_defaults_and_return_conflicts<'b>( - &'b self, - unbound_vars: &'b FxHashSet>, - default_map: &'b FxHashMap, type_variable::Default<'tcx>>, - conflict: Option>, - ) -> impl Iterator, type_variable::Default<'tcx>)> + 'b { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - conflict.into_iter().chain(unbound_vars.iter().cloned()).flat_map(move |ty| { - if self.type_var_diverges(ty) { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(ty) { - UnconstrainedInt => { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.i32) - }, - UnconstrainedFloat => { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.f64) - }, - Neither => { - if let Some(default) = default_map.get(ty) { - let default = default.clone(); - let default_ty = self.normalize_associated_types_in( - default.origin_span, &default.ty); - match self.eq_types(false, - &self.misc(default.origin_span), - ty, - default_ty) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - return Some((ty, default)); - } - } - } - } - } - } - - None - }) - } - fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs deleted file mode 100644 index 8cde239ca6ed..000000000000 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ /dev/null @@ -1,33 +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(default_type_parameter_fallback)] - -use std::fmt::Debug; - -// Example from the RFC -fn foo() -> F { F::default() } -//~^ NOTE: a default was defined here... - -fn bar(b: B) { println!("{:?}", b); } -//~^ NOTE: a second default was defined here... - -fn main() { - // Here, F is instantiated with $0=uint - let x = foo(); - //~^ ERROR: mismatched types - //~| NOTE: conflicting type parameter defaults `usize` and `isize` - //~| NOTE: conflicting type parameter defaults `usize` and `isize` - //~| NOTE: ...that was applied to an unconstrained type variable here - - // Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added. - bar(x); - //~^ NOTE: ...that also applies to the same type variable here -} diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs deleted file mode 100644 index e5b035e50aa9..000000000000 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.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. -// -//aux-build:default_ty_param_cross_crate_crate.rs - -#![feature(default_type_parameter_fallback)] - -extern crate default_param_test; - -use default_param_test::{Foo, bleh}; - -fn meh(x: Foo) {} -//~^ NOTE: a default was defined here... - -fn main() { - let foo = bleh(); - //~^ NOTE: ...that also applies to the same type variable here - - meh(foo); - //~^ ERROR: mismatched types - //~| NOTE: conflicting type parameter defaults `bool` and `char` - //~| NOTE: conflicting type parameter defaults `bool` and `char` - //~| a second default is defined on `default_param_test::bleh` - //~| NOTE: ...that was applied to an unconstrained type variable here -} diff --git a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs deleted file mode 100644 index 8fc2c2e6bce7..000000000000 --- a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs +++ /dev/null @@ -1,36 +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(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -trait Id { - type This; -} - -impl Id for A { - type This = A; -} - -struct Foo::This> { - data: PhantomData<(X, Y)> -} - -impl Foo { - fn new() -> Foo { - Foo { data: PhantomData } - } -} - -fn main() { - let foo = Foo::new(); -} diff --git a/src/test/run-pass/default_ty_param_dependent_defaults.rs b/src/test/run-pass/default_ty_param_dependent_defaults.rs deleted file mode 100644 index ac833d0f5474..000000000000 --- a/src/test/run-pass/default_ty_param_dependent_defaults.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. -// - -#![feature(default_type_parameter_fallback)] -use std::marker::PhantomData; - -struct Foo { t: T, data: PhantomData } - -fn main() { - let foo = Foo { t: 'a', data: PhantomData }; -} diff --git a/src/test/run-pass/default_ty_param_method_call_test.rs b/src/test/run-pass/default_ty_param_method_call_test.rs deleted file mode 100644 index e8d93092ec53..000000000000 --- a/src/test/run-pass/default_ty_param_method_call_test.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. - -#![feature(default_type_parameter_fallback)] - -struct Foo; - -impl Foo { - fn method(&self) -> A { - A::default() - } -} - -fn main() { - let f = Foo.method(); - println!("{}", f); -} diff --git a/src/test/run-pass/default_ty_param_struct.rs b/src/test/run-pass/default_ty_param_struct.rs deleted file mode 100644 index d9ac51fc23b0..000000000000 --- a/src/test/run-pass/default_ty_param_struct.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. - -#![feature(default_type_parameter_fallback)] - -struct Foo(A); - -impl Foo { - fn new() -> Foo { - Foo(A::default()) - } -} - -fn main() { - let foo = Foo::new(); -} diff --git a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs deleted file mode 100644 index d3bdab9082e3..000000000000 --- a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs +++ /dev/null @@ -1,40 +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(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -pub struct DeterministicHasher; -pub struct RandomHasher; - - -pub struct MyHashMap { - data: PhantomData<(K, V, H)> -} - -impl MyHashMap { - fn new() -> MyHashMap { - MyHashMap { data: PhantomData } - } -} - -mod mystd { - use super::{MyHashMap, RandomHasher}; - pub type HashMap = MyHashMap; -} - -fn try_me(hash_map: mystd::HashMap) {} - -fn main() { - let hash_map = mystd::HashMap::new(); - try_me(hash_map); -} diff --git a/src/test/run-pass/default_ty_param_trait_impl.rs b/src/test/run-pass/default_ty_param_trait_impl.rs deleted file mode 100644 index c67d3a49aff3..000000000000 --- a/src/test/run-pass/default_ty_param_trait_impl.rs +++ /dev/null @@ -1,25 +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(default_type_parameter_fallback)] - -// Another example from the RFC -trait Foo { } -trait Bar { } - -impl Foo for Vec {} -impl Bar for usize {} - -fn takes_foo(f: F) {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - takes_foo(x); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default_ty_param_trait_impl_simple.rs b/src/test/run-pass/default_ty_param_trait_impl_simple.rs deleted file mode 100644 index 067ad524922c..000000000000 --- a/src/test/run-pass/default_ty_param_trait_impl_simple.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. - -#![feature(default_type_parameter_fallback)] - -// An example from the RFC -trait Foo { fn takes_foo(&self); } -trait Bar { } - -impl Foo for Vec { - fn takes_foo(&self) {} -} - -impl Bar for usize {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - x.takes_foo(); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default_ty_param_type_alias.rs b/src/test/run-pass/default_ty_param_type_alias.rs deleted file mode 100644 index 1b4747406d0c..000000000000 --- a/src/test/run-pass/default_ty_param_type_alias.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. - -#![feature(default_type_parameter_fallback)] - -use std::collections::HashMap; - -type IntMap = HashMap; - -fn main() { - let x = IntMap::new(); -} From 18ea55fe1636001c4d030911e2c4c165af1cabfc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 10 Mar 2017 13:30:09 -0500 Subject: [PATCH 424/905] remove bivariance There is one fishy part of these changes: when computing the LUB/GLB of a "bivariant" type parameter, I currently return the `a` value. Bivariant type parameters are only allowed in a very particular situation, where the type parameter is only used as an associated type output, like this: ```rust pub struct Foo where A: Fn() -> B { data: A } ``` In principle, if one had `T=Foo` and `U=Foo` and (e.g.) `A: for<'a> Fn() -> &'a u32`, then I think that computing the LUB of `T` and `U` might do the wrong thing. Probably the right behavior is just to create a fresh type variable. However, that particular example would not compile (because the where-clause is illegal; `'a` does not appear in any input type). I was not able to make an example that *would* compile and demonstrate this shortcoming, and handling the LUB/GLB was mildly inconvenient, so I left it as is. I am considering whether to revisit this. --- src/librustc/infer/bivariate.rs | 123 -------------------------------- src/librustc/infer/combine.rs | 7 +- src/librustc/infer/glb.rs | 2 +- src/librustc/infer/lub.rs | 2 +- src/librustc/infer/mod.rs | 1 - src/librustc/infer/sub.rs | 2 +- 6 files changed, 4 insertions(+), 133 deletions(-) delete mode 100644 src/librustc/infer/bivariate.rs diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs deleted file mode 100644 index 4acb8b807d59..000000000000 --- a/src/librustc/infer/bivariate.rs +++ /dev/null @@ -1,123 +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. - -//! Applies the "bivariance relationship" to two types and/or regions. -//! If (A,B) are bivariant then either A <: B or B <: A. It occurs -//! when type/lifetime parameters are unconstrained. Usually this is -//! an error, but we permit it in the specific case where a type -//! parameter is constrained in a where-clause via an associated type. -//! -//! There are several ways one could implement bivariance. You could -//! just do nothing at all, for example, or you could fully verify -//! that one of the two subtyping relationships hold. We choose to -//! thread a middle line: we relate types up to regions, but ignore -//! all region relationships. -//! -//! At one point, handling bivariance in this fashion was necessary -//! for inference, but I'm actually not sure if that is true anymore. -//! In particular, it might be enough to say (A,B) are bivariant for -//! all (A,B). - -use super::combine::CombineFields; -use super::type_variable::{BiTo}; - -use ty::{self, Ty, TyCtxt}; -use ty::TyVar; -use ty::relate::{Relate, RelateResult, TypeRelation}; - -pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) - -> Bivariate<'combine, 'infcx, 'gcx, 'tcx> - { - Bivariate { fields: fields, a_is_expected: a_is_expected } - } -} - -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> - for Bivariate<'combine, 'infcx, 'gcx, 'tcx> -{ - fn tag(&self) -> &'static str { "Bivariate" } - - fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.a_is_expected } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - // If we have Foo and Foo is invariant w/r/t A, - // and we want to assert that - // - // Foo <: Foo || - // Foo <: Foo - // - // then still A must equal B. - ty::Invariant => self.relate(a, b), - - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.relate(a, b), - ty::Contravariant => self.relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), - a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id); - Ok(a) - } - - (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?; - Ok(a) - } - - (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?; - Ok(a) - } - - _ => { - self.fields.infcx.super_combine_tys(self, a, b) - } - } - } - - fn regions(&mut self, a: &'tcx ty::Region, _: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { - Ok(a) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'tcx> - { - let a1 = self.tcx().erase_late_bound_regions(a); - let b1 = self.tcx().erase_late_bound_regions(b); - let c = self.relate(&a1, &b1)?; - Ok(ty::Binder(c)) - } -} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 5d33d6e6d2e7..9430421f9101 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -32,7 +32,6 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. -use super::bivariate::Bivariate; use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; @@ -159,10 +158,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Equate::new(self, a_is_expected) } - pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> { - Bivariate::new(self, a_is_expected) - } - pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> { Sub::new(self, a_is_expected) } @@ -251,7 +246,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // to associate causes/spans with each of the relations in // the stack to get this right. match dir { - BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty), + BiTo => Ok(a_ty), EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), SupertypeOf => self.sub(a_is_expected).relate_with_variance( diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 8ccadc6b2af0..8c167e0a8ac9 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -49,7 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 89571dea10c3..28ae1ae556b0 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -49,7 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b07ef4dfd448..98c8ce0f0314 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -48,7 +48,6 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; -mod bivariate; mod combine; mod equate; pub mod error_reporting; diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index dae30ea97c80..a6b0e02d4772 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -65,7 +65,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), } } From 58609ef879e604d161f4ee6c612d6d127120e289 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 9 Mar 2017 21:47:09 -0500 Subject: [PATCH 425/905] add Subtype predicate --- src/librustc/ich/impls_ty.rs | 4 +++ src/librustc/infer/mod.rs | 39 ++++++++++++++++++++++- src/librustc/middle/free_region.rs | 1 + src/librustc/traits/error_reporting.rs | 23 +++++++++++++ src/librustc/traits/fulfill.rs | 21 ++++++++++++ src/librustc/traits/object_safety.rs | 2 ++ src/librustc/traits/select.rs | 12 +++++++ src/librustc/traits/structural_impls.rs | 1 + src/librustc/traits/util.rs | 9 +++++- src/librustc/ty/mod.rs | 17 ++++++++++ src/librustc/ty/structural_impls.rs | 35 ++++++++++++++++++-- src/librustc/ty/util.rs | 1 + src/librustc/ty/wf.rs | 5 +++ src/librustc/util/ppaux.rs | 14 ++++++++ src/librustc_typeck/check/closure.rs | 1 + src/librustc_typeck/check/method/probe.rs | 1 + src/librustdoc/clean/mod.rs | 11 +++++++ 17 files changed, 193 insertions(+), 4 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b6f3af2a11e..b8888eee9c6e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -170,6 +170,7 @@ impl_stable_hash_for!(enum ty::Visibility { impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); +impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); impl<'a, 'tcx, A, B> HashStable> for ty::OutlivesPredicate where A: HashStable>, @@ -200,6 +201,9 @@ impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx ty::Predicate::Equate(ref pred) => { pred.hash_stable(hcx, hasher); } + ty::Predicate::Subtype(ref pred) => { + pred.hash_stable(hcx, hasher); + } ty::Predicate::RegionOutlives(ref pred) => { pred.hash_stable(hcx, hasher); } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 98c8ce0f0314..999ebbfa20fb 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -551,7 +551,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { } impl ExpectedFound { - fn new(a_is_expected: bool, a: T, b: T) -> Self { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { if a_is_expected { ExpectedFound {expected: a, found: b} } else { @@ -1129,6 +1129,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } + pub fn subtype_predicate(&self, + cause: &ObligationCause<'tcx>, + predicate: &ty::PolySubtypePredicate<'tcx>) + -> Option> + { + // Subtle: it's ok to skip the binder here and resolve because + // `shallow_resolve` just ignores anything that is not a type + // variable, and because type variable's can't (at present, at + // least) capture any of the things bound by this binder. + // + // Really, there is no *particular* reason to do this + // `shallow_resolve` here except as a + // micro-optimization. Naturally I could not + // resist. -nmatsakis + let two_unbound_type_vars = { + let a = self.shallow_resolve(predicate.skip_binder().a); + let b = self.shallow_resolve(predicate.skip_binder().b); + a.is_ty_var() && b.is_ty_var() + }; + + if two_unbound_type_vars { + // Two unbound type variables? Can't make progress. + return None; + } + + Some(self.commit_if_ok(|snapshot| { + let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + + let cause_span = cause.span; + let ok = self.sub_types(a_is_expected, cause, a, b)?; + self.leak_check(false, cause_span, &skol_map, snapshot)?; + self.pop_skolemized(skol_map, snapshot); + Ok(ok.unit()) + })) + } + pub fn region_outlives_predicate(&self, cause: &traits::ObligationCause<'tcx>, predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab4009..963cc4314eda 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -60,6 +60,7 @@ impl FreeRegionMap { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 931c77badad2..8a303a5da118 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -39,6 +39,7 @@ use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::Subst; +use ty::SubtypePredicate; use util::nodemap::{FxHashMap, FxHashSet}; use syntax_pos::{DUMMY_SP, Span}; @@ -112,6 +113,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { FulfillmentErrorCode::CodeAmbiguity => { self.maybe_report_ambiguity(&error.obligation); } + FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { + self.report_mismatched_types(&error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone()) + .emit(); + } } } @@ -555,6 +563,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } + ty::Predicate::Subtype(ref predicate) => { + // TODO + panic!("subtype requirement not satisfied {:?}", predicate) + } + ty::Predicate::Equate(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.equality_predicate(&obligation.cause, @@ -761,6 +774,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + ty::Predicate::Subtype(ref data) => { + if data.references_error() || self.tcx.sess.has_errors() { + // no need to overload user in such cases + } else { + let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); + assert!(a.is_ty_var() && b.is_ty_var()); // else other would've been instantiated + self.need_type_info(obligation, a); + } + } + _ => { if !self.tcx.sess.has_errors() { let mut err = struct_span_err!(self.tcx.sess, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index b87d18464377..64453f2983b9 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -11,6 +11,7 @@ use dep_graph::DepGraph; use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate}; +use ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; @@ -496,6 +497,26 @@ fn process_predicate<'a, 'gcx, 'tcx>( s => Ok(s) } } + + ty::Predicate::Subtype(ref subtype) => { + match selcx.infcx().subtype_predicate(&obligation.cause, subtype) { + None => { + // none means that both are unresolved + pending_obligation.stalled_on = vec![subtype.skip_binder().a, + subtype.skip_binder().b]; + Ok(None) + } + Some(Ok(ok)) => { + Ok(Some(ok.obligations)) + } + Some(Err(err)) => { + let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, + subtype.skip_binder().a, + subtype.skip_binder().b); + Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) + } + } + } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7cd0b26940d9..d190635bec30 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -178,6 +178,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Equate(..) => { false } @@ -209,6 +210,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 38ea1e4a19b9..67d50210ba39 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -568,6 +568,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + ty::Predicate::Subtype(ref p) => { + // does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, p) { + Some(Ok(InferOk { obligations, .. })) => { + self.inferred_obligations.extend(obligations); + EvaluatedToOk + }, + Some(Err(_)) => EvaluatedToErr, + None => EvaluatedToAmbig, + } + } + ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(self.infcx, obligation.cause.body_id, ty, obligation.cause.span) { diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 44ef461327dd..fcaa29be9632 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -130,6 +130,7 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { match *self { super::CodeSelectionError(ref e) => write!(f, "{:?}", e), super::CodeProjectionError(ref e) => write!(f, "{:?}", e), + super::CodeSubtypeError(ref a, ref b) => write!(f, "CodeSubtypeError({:?}, {:?})", a, b), super::CodeAmbiguity => write!(f, "Ambiguity") } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 602f27a64d4d..d4245ec9b247 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -42,7 +42,10 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::ObjectSafe(data), ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind) + ty::Predicate::ClosureKind(closure_def_id, kind), + + ty::Predicate::Subtype(ref data) => + ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), } } @@ -160,6 +163,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { // `X == Y`, though conceivably we might. For example, // `&X == &Y` implies that `X == Y`. } + ty::Predicate::Subtype(..) => { + // Currently, we do not "elaborate" predicates like `X + // <: Y`, though conceivably we might. + } ty::Predicate::Projection(..) => { // Nothing to elaborate in a projection predicate. } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f..d720911db39f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -755,6 +755,9 @@ pub enum Predicate<'tcx> { /// for some substitutions `...` and T being a closure type. /// Satisfied (or refuted) once we know the closure's kind. ClosureKind(DefId, ClosureKind), + + /// `T1 <: T2` + Subtype(PolySubtypePredicate<'tcx>), } impl<'a, 'gcx, 'tcx> Predicate<'tcx> { @@ -833,6 +836,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::Trait(ty::Binder(data.subst(tcx, substs))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), + Predicate::Subtype(ty::Binder(ref data)) => + Predicate::Subtype(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), Predicate::TypeOutlives(ty::Binder(ref data)) => @@ -912,6 +917,14 @@ pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Reg &'tcx ty::Region>; pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'tcx ty::Region>; +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct SubtypePredicate<'tcx> { + pub a_is_expected: bool, + pub a: Ty<'tcx>, + pub b: Ty<'tcx> +} +pub type PolySubtypePredicate<'tcx> = ty::Binder>; + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1025,6 +1038,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } + ty::Predicate::Subtype(ty::Binder(SubtypePredicate { a, b, a_is_expected: _ })) => { + vec![a, b] + } ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { vec![data.0] } @@ -1061,6 +1077,7 @@ impl<'tcx> Predicate<'tcx> { } Predicate::Projection(..) | Predicate::Equate(..) | + Predicate::Subtype(..) | Predicate::RegionOutlives(..) | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9126600e3f65..a4466d7d8401 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -111,6 +111,18 @@ impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { + type Lifted = ty::SubtypePredicate<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) + -> Option> { + tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: a, + b: b, + }) + } +} + impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { type Lifted = ty::OutlivesPredicate; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -167,6 +179,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::Equate(ref binder) => { tcx.lift(binder).map(ty::Predicate::Equate) } + ty::Predicate::Subtype(ref binder) => { + tcx.lift(binder).map(ty::Predicate::Subtype) + } ty::Predicate::RegionOutlives(ref binder) => { tcx.lift(binder).map(ty::Predicate::RegionOutlives) } @@ -693,6 +708,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::Trait(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::Subtype(ref binder) => + ty::Predicate::Subtype(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => ty::Predicate::RegionOutlives(binder.fold_with(folder)), ty::Predicate::TypeOutlives(ref binder) => @@ -712,6 +729,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), + ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), @@ -776,8 +794,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::EquatePredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) + ty::EquatePredicate(self.0.fold_with(folder), self.1.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { @@ -785,6 +802,20 @@ impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: self.a.fold_with(folder), + b: self.b.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.a.visit_with(visitor) || self.b.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitPredicate { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd8191303a9a..2efefd750ae8 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -312,6 +312,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 8a5bd6862cf4..0b0e8a180cc3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,6 +94,10 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } ty::Predicate::ClosureKind(..) => { } + ty::Predicate::Subtype(ref data) => { + wf.compute(data.skip_binder().a); // (*) + wf.compute(data.skip_binder().b); // (*) + } } wf.normalize() @@ -156,6 +160,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( match obligation.predicate { ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::ObjectSafe(..) => diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6323f1dc0d4c..2daf71d95add 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -416,6 +416,7 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), + ty::Predicate::Subtype(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair), @@ -676,6 +677,12 @@ impl<'tcx> fmt::Display for ty::Binder> { } } +impl<'tcx> fmt::Display for ty::Binder> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) + } +} + impl<'tcx> fmt::Display for ty::Binder> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) @@ -897,6 +904,12 @@ impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> { } } +impl<'tcx> fmt::Display for ty::SubtypePredicate<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} <: {}", self.a, self.b) + } +} + impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TraitPredicate({:?})", @@ -949,6 +962,7 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), + ty::Predicate::Subtype(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 51fbc5aab6cd..78176b155691 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -169,6 +169,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()), ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), ty::Predicate::Equate(..) => None, + ty::Predicate::Subtype(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 5b0418921563..8071fe3cc280 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -576,6 +576,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } } ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac72d7d29a24..1a194cd12546 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -875,6 +875,7 @@ impl<'a> Clean for ty::Predicate<'a> { match *self { Predicate::Trait(ref pred) => pred.clean(cx), Predicate::Equate(ref pred) => pred.clean(cx), + Predicate::Subtype(ref pred) => pred.clean(cx), Predicate::RegionOutlives(ref pred) => pred.clean(cx), Predicate::TypeOutlives(ref pred) => pred.clean(cx), Predicate::Projection(ref pred) => pred.clean(cx), @@ -904,6 +905,16 @@ impl<'tcx> Clean for ty::EquatePredicate<'tcx> { } } +impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { + fn clean(&self, cx: &DocContext) -> WherePredicate { + let ty::SubtypePredicate { a_is_expected: _, a, b } = *self; + WherePredicate::EqPredicate { // TODO This is obviously wrong :P + lhs: a.clean(cx), + rhs: b.clean(cx) + } + } +} + impl<'tcx> Clean for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::OutlivesPredicate(ref a, ref b) = *self; From 4e4bdea0ae8b3b1995b002374db1a7b7639eb52d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 10 Mar 2017 05:19:49 -0500 Subject: [PATCH 426/905] propagate sub-obligations better The most interesting place is the hinting mechanism; once we start having subtyping obligations, it's important to see those through. --- src/librustc_typeck/check/method/probe.rs | 16 +++++++-------- src/librustc_typeck/check/mod.rs | 25 ++++++++++++++++++++--- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8071fe3cc280..59dbbfe49f0a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1149,19 +1149,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.probe(|_| { // First check that the self type can be related. - match self.sub_types(false, - &ObligationCause::dummy(), - self_ty, - probe.xform_self_ty) { - Ok(InferOk { obligations, value: () }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - } + let sub_obligations = match self.sub_types(false, + &ObligationCause::dummy(), + self_ty, + probe.xform_self_ty) { + Ok(InferOk { obligations, value: () }) => obligations, Err(_) => { debug!("--> cannot relate self-types"); return false; } - } + }; // If so, impls may carry other conditions (e.g., where // clauses) that must be considered. Make sure that those @@ -1200,6 +1197,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Evaluate those obligations to see if they might possibly hold. let mut all_true = true; for o in obligations.iter() + .chain(sub_obligations.iter()) .chain(norm_obligations.iter()) .chain(ref_obligations.iter()) { if !selcx.evaluate_obligation(o) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d300552af2ca..77213b5a7436 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,7 +90,7 @@ use rustc_back::slice::ref_slice; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; +use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; @@ -2552,11 +2552,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // No argument expectations are produced if unification fails. let origin = self.misc(call_span); let ures = self.sub_types(false, &origin, formal_ret, ret_ty); + // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. match ures { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(e) => return Err(e), + Ok(ok) => { + // Process any obligations locally as much as + // we can. We don't care if some things turn + // out unconstrained or ambiguous, as we're + // just trying to get hints here. + let result = self.save_and_restore_obligations_in_snapshot_flag(|_| { + let mut fulfill = FulfillmentContext::new(); + let ok = ok; // FIXME(#30046) + for obligation in ok.obligations { + fulfill.register_predicate_obligation(self, obligation); + } + fulfill.select_where_possible(self) + }); + + match result { + Ok(()) => { } + Err(_) => return Err(()), + } + } + Err(_) => return Err(()), } // Record all the argument types, with the substitutions From 105ec7e3bbbef50076f0e6963e8a9327bacf7b5f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 10 Mar 2017 05:21:27 -0500 Subject: [PATCH 427/905] use obligations to propagate sub-typing instead of the TV code --- src/librustc/infer/sub.rs | 25 +++++++++++++++++++++---- src/librustc/traits/mod.rs | 5 ++++- src/test/compile-fail/issue-7813.rs | 5 ++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index a6b0e02d4772..1a94f12973de 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -12,8 +12,10 @@ use super::SubregionOrigin; use super::combine::CombineFields; use super::type_variable::{SubtypeOf, SupertypeOf}; +use traits::Obligation; use ty::{self, Ty, TyCtxt}; use ty::TyVar; +use ty::fold::TypeFoldable; use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use std::mem; @@ -79,10 +81,25 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables - .borrow_mut() - .relate_vars(a_id, SubtypeOf, b_id); + (&ty::TyInfer(TyVar(_)), &ty::TyInfer(TyVar(_))) => { + // Shouldn't have any LBR here, so we can safely put + // this under a binder below without fear of accidental + // capture. + assert!(!a.has_escaping_regions()); + assert!(!b.has_escaping_regions()); + + // can't make progress on `A <: B` if both A and B are + // type variables, so record an obligation. + self.fields.obligations.push( + Obligation::new( + self.fields.trace.cause.clone(), + ty::Predicate::Subtype( + ty::Binder(ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a, + b, + })))); + Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 47cbccdd2ab1..ea243d65881e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -20,7 +20,8 @@ use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use ty::subst::Substs; use ty::{self, Ty, TyCtxt, TypeFoldable, ToPredicate}; -use infer::InferCtxt; +use ty::error::{ExpectedFound, TypeError}; +use infer::{InferCtxt}; use std::rc::Rc; use syntax::ast; @@ -214,6 +215,8 @@ pub struct FulfillmentError<'tcx> { pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeSubtypeError(ExpectedFound>, + TypeError<'tcx>), // always comes from a SubtypePredicate CodeAmbiguity, } diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index fdd89058fd39..662b9e894ba3 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -10,7 +10,6 @@ fn main() { let v = &[]; - let it = v.iter(); //~ ERROR type annotations needed [E0282] - //~| NOTE cannot infer type for `T` - //~| NOTE consider giving `it` a type + //~^ NOTE consider giving `it` a type + let it = v.iter(); //~ ERROR cannot infer type for `_` } From e58e2b423dabc816ba5d9e2382373622cc07bc8d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Mar 2017 09:05:39 -0400 Subject: [PATCH 428/905] remove the subtyping relations from TypeVariable --- src/librustc/infer/combine.rs | 14 ++- src/librustc/infer/equate.rs | 9 +- src/librustc/infer/sub.rs | 7 +- src/librustc/infer/type_variable.rs | 144 ++++++---------------------- src/librustc/lib.rs | 1 + src/test/compile-fail/issue-7813.rs | 6 +- 6 files changed, 51 insertions(+), 130 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 9430421f9101..825f279e78e4 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -38,7 +38,6 @@ use super::lub::Lub; use super::sub::Sub; use super::InferCtxt; use super::{MiscVariable, TypeTrace}; -use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; use ty::{IntType, UintType}; use ty::{self, Ty, TyCtxt}; @@ -59,6 +58,11 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { pub obligations: PredicateObligations<'tcx>, } +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum RelationDir { + SubtypeOf, SupertypeOf, EqTo +} + impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { pub fn super_combine_tys(&self, relation: &mut R, @@ -177,6 +181,8 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { a_is_expected: bool) -> RelateResult<'tcx, ()> { + use self::RelationDir::*; + // We use SmallVector here instead of Vec because this code is hot and // it's rare that the stack length exceeds 1. let mut stack = SmallVector::new(); @@ -224,7 +230,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // Generalize type if necessary. let generalized_ty = match dir { EqTo => self.generalize(a_ty, b_vid, false), - BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), + SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), }?; debug!("instantiate(a_ty={:?}, dir={:?}, \ b_vid={:?}, generalized_ty={:?})", @@ -232,8 +238,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { generalized_ty); self.infcx.type_variables .borrow_mut() - .instantiate_and_push( - b_vid, generalized_ty, &mut stack); + .instantiate(b_vid, generalized_ty); generalized_ty } }; @@ -246,7 +251,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // to associate causes/spans with each of the relations in // the stack to get this right. match dir { - BiTo => Ok(a_ty), EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), SupertypeOf => self.sub(a_is_expected).relate_with_variance( diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index bf247acec5a2..f620965ced84 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::CombineFields; +use super::combine::{CombineFields, RelationDir}; use super::{Subtype}; -use super::type_variable::{EqTo}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; @@ -58,17 +57,17 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id); + infcx.type_variables.borrow_mut().equate(a_id, b_id); Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 1a94f12973de..f1de9b043e36 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -9,8 +9,7 @@ // except according to those terms. use super::SubregionOrigin; -use super::combine::CombineFields; -use super::type_variable::{SubtypeOf, SupertypeOf}; +use super::combine::{CombineFields, RelationDir}; use traits::Obligation; use ty::{self, Ty, TyCtxt}; @@ -104,11 +103,11 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } (&ty::TyInfer(TyVar(a_id)), _) => { self.fields - .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?; + .instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 67f37e5f9272..298b2a97d5f3 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::RelationDir::*; use self::TypeVariableValue::*; -use self::UndoEntry::*; use hir::def_id::{DefId}; -use syntax::util::small_vector::SmallVector; use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; @@ -55,7 +52,6 @@ struct TypeVariableData<'tcx> { enum TypeVariableValue<'tcx> { Known(Ty<'tcx>), Bounded { - relations: Vec, default: Option> } } @@ -76,33 +72,13 @@ pub struct Snapshot { eq_snapshot: ut::Snapshot, } -enum UndoEntry<'tcx> { - // The type of the var was specified. - SpecifyVar(ty::TyVid, Vec, Option>), - Relate(ty::TyVid, ty::TyVid), - RelateRange(ty::TyVid, usize), +struct Instantiate<'tcx> { + vid: ty::TyVid, + default: Option>, } struct Delegate<'tcx>(PhantomData<&'tcx ()>); -type Relation = (RelationDir, ty::TyVid); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum RelationDir { - SubtypeOf, SupertypeOf, EqTo, BiTo -} - -impl RelationDir { - fn opposite(self) -> RelationDir { - match self { - SubtypeOf => SupertypeOf, - SupertypeOf => SubtypeOf, - EqTo => EqTo, - BiTo => BiTo, - } - } -} - impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { TypeVariableTable { @@ -111,10 +87,6 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { - relations(self.values.get_mut(a.index as usize)) - } - pub fn default(&self, vid: ty::TyVid) -> Option> { match &self.values.get(vid.index as usize).value { &Known(_) => None, @@ -130,68 +102,37 @@ impl<'tcx> TypeVariableTable<'tcx> { &self.values.get(vid.index as usize).origin } - /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`. + /// Records that `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. - pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - let a = self.root_var(a); - let b = self.root_var(b); - if a != b { - if dir == EqTo { - // a and b must be equal which we mark in the unification table - let root = self.eq_relations.union(a, b); - // In addition to being equal, all relations from the variable which is no longer - // the root must be added to the root so they are not forgotten as the other - // variable should no longer be referenced (other than to get the root) - let other = if a == root { b } else { a }; - let count = { - let (relations, root_relations) = if other.index < root.index { - let (pre, post) = self.values.split_at_mut(root.index as usize); - (relations(&mut pre[other.index as usize]), relations(&mut post[0])) - } else { - let (pre, post) = self.values.split_at_mut(other.index as usize); - (relations(&mut post[0]), relations(&mut pre[root.index as usize])) - }; - root_relations.extend_from_slice(relations); - relations.len() - }; - self.values.record(RelateRange(root, count)); - } else { - self.relations(a).push((dir, b)); - self.relations(b).push((dir.opposite(), a)); - self.values.record(Relate(a, b)); - } - } + pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.eq_relations.union(a, b); } - /// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the - /// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)` - /// where `vid1` is some other variable id. + /// Instantiates `vid` with the type `ty`. /// /// Precondition: `vid` must be a root in the unification table - pub fn instantiate_and_push( - &mut self, - vid: ty::TyVid, - ty: Ty<'tcx>, - stack: &mut SmallVector<(Ty<'tcx>, RelationDir, ty::TyVid)>) - { + /// and has not previously been instantiated. + pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { debug_assert!(self.root_var(vid) == vid); + debug_assert!(self.probe(vid).is_none()); + let old_value = { - let value_ptr = &mut self.values.get_mut(vid.index as usize).value; - mem::replace(value_ptr, Known(ty)) + let vid_data = &mut self.values[vid.index as usize]; + mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty)) }; - let (relations, default) = match old_value { - Bounded { relations, default } => (relations, default), - Known(_) => bug!("Asked to instantiate variable that is \ - already instantiated") - }; - - for &(dir, vid) in &relations { - stack.push((ty, dir, vid)); + match old_value { + TypeVariableValue::Bounded { default } => { + self.values.record(Instantiate { vid: vid, default: default }); + } + TypeVariableValue::Known(old_ty) => { + bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", + vid, ty, old_ty) + } } - - self.values.record(SpecifyVar(vid, relations, default)); } pub fn new_var(&mut self, @@ -201,7 +142,7 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); let index = self.values.push(TypeVariableData { - value: Bounded { relations: vec![], default: default }, + value: Bounded { default: default }, origin: origin, diverging: diverging }); @@ -298,7 +239,7 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); } - sv::UndoLog::Other(SpecifyVar(vid, ..)) => { + sv::UndoLog::Other(Instantiate { vid, .. }) => { if vid.index < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. @@ -334,35 +275,12 @@ impl<'tcx> TypeVariableTable<'tcx> { impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; - type Undo = UndoEntry<'tcx>; + type Undo = Instantiate<'tcx>; - fn reverse(values: &mut Vec>, action: UndoEntry<'tcx>) { - match action { - SpecifyVar(vid, relations, default) => { - values[vid.index as usize].value = Bounded { - relations: relations, - default: default - }; - } - - Relate(a, b) => { - relations(&mut (*values)[a.index as usize]).pop(); - relations(&mut (*values)[b.index as usize]).pop(); - } - - RelateRange(i, n) => { - let relations = relations(&mut (*values)[i.index as usize]); - for _ in 0..n { - relations.pop(); - } - } - } - } -} - -fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec { - match v.value { - Known(_) => bug!("var_sub_var: variable is known"), - Bounded { ref mut relations, .. } => relations + fn reverse(values: &mut Vec>, action: Instantiate<'tcx>) { + let Instantiate { vid, default } = action; + values[vid.index as usize].value = Bounded { + default: default + }; } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3b002fd4dfc1..9176a4c01575 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -32,6 +32,7 @@ #![feature(i128_type)] #![feature(libc)] #![feature(loop_break_value)] +#![feature(never_type)] #![feature(nonzero)] #![cfg_attr(stage0, feature(pub_restricted))] #![feature(quote)] diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index 662b9e894ba3..2551ed0208af 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let v = &[]; - //~^ NOTE consider giving `it` a type - let it = v.iter(); //~ ERROR cannot infer type for `_` + let v = &[]; //~ NOTE consider giving `v` a type + let it = v.iter(); //~ ERROR type annotations needed + //~^ NOTE cannot infer type for `_` } From e4b762b532f037d07be282d413c7a864e182b3fc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 16 Mar 2017 09:58:21 -0400 Subject: [PATCH 429/905] add regression test for #30225 Fixes #30225 --- src/test/compile-fail/issue-30225.rs | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/test/compile-fail/issue-30225.rs diff --git a/src/test/compile-fail/issue-30225.rs b/src/test/compile-fail/issue-30225.rs new file mode 100644 index 000000000000..7acbbfb8826d --- /dev/null +++ b/src/test/compile-fail/issue-30225.rs @@ -0,0 +1,48 @@ +// 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. + +// Regression test for #30225, which was an ICE that would trigger as +// a result of a poor interaction between trait result caching and +// type inference. Specifically, at that time, unification could cause +// unrelated type variables to become instantiated, if subtyping +// relationships existed. These relationships are now propagated +// through obligations and hence everything works out fine. + +trait Foo : Sized { + fn foo(self, u: Option, v: Option) {} +} + +struct A; +struct B; + +impl Foo for () {} // impl A +impl Foo for u32 {} // impl B, creating ambiguity + +fn toxic() { + // cache the resolution <() as Foo<$0,$1>> = impl A + let u = None; + let v = None; + Foo::foo((), u, v); +} + +fn bomb() { + let mut u = None; // type is Option<$0> + let mut v = None; // type is Option<$1> + let mut x = None; // type is Option<$2> + + Foo::foo(x.unwrap(),u,v); // register <$2 as Foo<$0, $1>> + u = v; // mark $0 and $1 in a subtype relationship + //~^ ERROR mismatched types + x = Some(()); // set $2 = (), allowing impl selection + // to proceed for <() as Foo<$0, $1>> = impl A. + // kaboom, this *used* to trigge an ICE +} + +fn main() {} From d1033d06bae530881415bda6972c5c8a16d07ade Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 3 Apr 2017 15:59:34 -0400 Subject: [PATCH 430/905] add FIXME to #18653 --- src/librustc/infer/combine.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 825f279e78e4..a23589e7f3f7 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -224,6 +224,9 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // Check whether `vid` has been instantiated yet. If not, // make a generalized form of `ty` and instantiate with // that. + // + // FIXME(#18653) -- we need to generalize nested type + // variables too. let b_ty = match b_ty { Some(t) => t, // ...already instantiated. None => { // ...not yet instantiated: From 77d9e38e9499df1dac393937d62d3bf626c51abb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 3 Apr 2017 16:14:05 -0400 Subject: [PATCH 431/905] add FIXME for bivariant lub/glb --- src/librustc/infer/glb.rs | 1 + src/librustc/infer/lub.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 8c167e0a8ac9..a6dd18c113f1 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -49,6 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), + // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 28ae1ae556b0..d7e5c92b6e17 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -49,6 +49,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), + // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } From 14f1e3459f02e3ce45232a84cd923c86eef55cb5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 16:58:04 -0400 Subject: [PATCH 432/905] fix a bug in compiletest JSON parsing for duplicate errors In some cases, we give multiple primary spans, in which case we would report one `//~` annotation per primary span. That was very confusing because these things are reported to the user as a single error. UI tests would be better here. --- src/test/compile-fail/binop-move-semantics.rs | 2 -- src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs | 1 - .../compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs | 1 - src/test/compile-fail/issue-25579.rs | 1 - src/test/compile-fail/issue-38412.rs | 1 - src/test/compile-fail/lint-unused-imports.rs | 1 - src/tools/compiletest/src/json.rs | 1 + 7 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/test/compile-fail/binop-move-semantics.rs b/src/test/compile-fail/binop-move-semantics.rs index 0cc6ea3e984d..cff0064497af 100644 --- a/src/test/compile-fail/binop-move-semantics.rs +++ b/src/test/compile-fail/binop-move-semantics.rs @@ -62,7 +62,6 @@ fn mut_plus_immut() { &mut f + &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable - //~^ cannot borrow `f` as immutable because it is also borrowed as mutable } fn immut_plus_mut() { @@ -71,7 +70,6 @@ fn immut_plus_mut() { &f + &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable - //~^ cannot borrow `f` as mutable because it is also borrowed as immutable } fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs index 56cbe0b18786..f09e7ffd7e4b 100644 --- a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs @@ -109,7 +109,6 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { borrow(&*v); //~ ERROR cannot borrow if cond2 { x = &mut v; //~ ERROR cannot borrow - //~^ ERROR cannot borrow } } } diff --git a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs index f789d44016eb..38e0e27a7b98 100644 --- a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs +++ b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs @@ -19,7 +19,6 @@ fn main() { match 1 { 1 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time - //~| ERROR cannot borrow `x` as mutable more than once at a time 2 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time _ => { addr = &mut x; } diff --git a/src/test/compile-fail/issue-25579.rs b/src/test/compile-fail/issue-25579.rs index 849c9aa18c90..323ce3b0adf3 100644 --- a/src/test/compile-fail/issue-25579.rs +++ b/src/test/compile-fail/issue-25579.rs @@ -17,7 +17,6 @@ fn causes_ice(mut l: &mut Sexpression) { loop { match l { &mut Sexpression::Num(ref mut n) => {}, &mut Sexpression::Cons(ref mut expr) => { //~ ERROR cannot borrow `l.0` - //~| ERROR cannot borrow `l.0` l = &mut **expr; //~ ERROR cannot assign to `l` } }} diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs index 3b62aaf2ab8e..b4feadbacf74 100644 --- a/src/test/compile-fail/issue-38412.rs +++ b/src/test/compile-fail/issue-38412.rs @@ -11,7 +11,6 @@ fn main() { let Box(a) = loop { }; //~^ ERROR expected tuple struct/variant, found struct `Box` - //~| ERROR expected tuple struct/variant, found struct `Box` // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index f6f7c210f466..5bb2ab75c53f 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -21,7 +21,6 @@ use std::fmt::{}; // Should get errors for both 'Some' and 'None' use std::option::Option::{Some, None}; //~^ ERROR unused imports: `None`, `Some` -//~| ERROR unused imports: `None`, `Some` use test::A; //~ ERROR unused import: `test::A` // Be sure that if we just bring some methods into scope that they're also diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index d9da1bdc3485..06cbd9a3df41 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -97,6 +97,7 @@ fn push_expected_errors(expected_errors: &mut Vec, let primary_spans: Vec<_> = spans_in_this_file.iter() .cloned() .filter(|span| span.is_primary) + .take(1) // sometimes we have more than one showing up in the json; pick first .collect(); let primary_spans = if primary_spans.is_empty() { // subdiagnostics often don't have a span of their own; From 3a5bbf89b2229c629c6f01bdd87354cba136d133 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:16:57 -0400 Subject: [PATCH 433/905] avoid unneeded subtype obligations in lub/glb In some specific cases, the new scheme was failing to learn as much from a LUB/GLB operaiton as the old code, which caused coercion to go awry. A slight ordering hack fixes this. --- src/librustc/infer/lattice.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index f7b26a918b3a..d4d090f0153d 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -44,6 +44,10 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. + // + // Subtle hack: ordering *may* be significant here. This method + // relates `v` to `a` first, which may help us to avoid unecessary + // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } @@ -74,7 +78,29 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, Ok(v) } - (&ty::TyInfer(TyVar(..)), _) | + // If one side is known to be a variable and one is not, + // create a variable (`v`) to represent the LUB. Make sure to + // relate `v` to the non-type-variable first (by passing it + // first to `relate_bound`). Otherwise, we would produce a + // subtype obligation that must then be processed. + // + // Example: if the LHS is a type variable, and RHS is + // `Box`, then we current compare `v` to the RHS first, + // which will instantiate `v` with `Box`. Then when `v` + // is compared to the LHS, we instantiate LHS with `Box`. + // But if we did in reverse order, we would create a `v <: + // LHS` (or vice versa) constraint and then instantiate + // `v`. This would require further processing to achieve same + // end-result; in partiular, this screws up some of the logic + // in coercion, which expects LUB to figure out that the LHS + // is (e.g.) `Box`. A more obvious solution might be to + // iterate on the subtype obligations that are returned, but I + // think this suffices. -nmatsakis + (&ty::TyInfer(TyVar(..)), _) => { + let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); + this.relate_bound(v, b, a)?; + Ok(v) + } (_, &ty::TyInfer(TyVar(..))) => { let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); this.relate_bound(v, a, b)?; From bca56e82a1bbd775498257cc080f5ea27b214f49 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:17:58 -0400 Subject: [PATCH 434/905] generalize type variables too When we are generalizing a super/sub-type, we have to replace type variables with a fresh variable (and not just region variables). So if we know that `Box <: ?U`, for example, we instantiate `?U` with `Box` and then relate `Box` to `Box` (and hence require that `?T <: ?V`). This change has some complex interactions, however: First, the occurs check must be updated to detect constraints like `?T <: ?U` and `?U <: Box`. If we're not careful, we'll create a never-ending sequence of new variables. To address this, we add a second unification set into `type_variables` that tracks type variables related through **either** equality **or** subtyping, and use that during the occurs-check. Second, the "fudge regions if ok" code was expecting no new type variables to be created. It must be updated to create new type variables outside of the probe. This is relatively straight-forward under the new scheme, since type variables are now independent from one another, and any relations are moderated by pending subtype obliations and so forth. This part would be tricky to backport though. cc #18653 cc #40951 --- src/librustc/infer/combine.rs | 46 +++++--- src/librustc/infer/fudge.rs | 73 ++++++++---- src/librustc/infer/mod.rs | 6 +- src/librustc/infer/sub.rs | 8 +- src/librustc/infer/type_variable.rs | 108 +++++++++++++++++- src/librustc/traits/error_reporting.rs | 24 +++- src/test/run-pass/issue-40951.rs | 20 ++++ .../run-pass/type-infer-generalize-ty-var.rs | 60 ++++++++++ 8 files changed, 296 insertions(+), 49 deletions(-) create mode 100644 src/test/run-pass/issue-40951.rs create mode 100644 src/test/run-pass/type-infer-generalize-ty-var.rs diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index a23589e7f3f7..03ed654e3cce 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -264,20 +264,27 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Ok(()) } - /// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that - /// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also - /// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok` - /// otherwise. + /// Attempts to generalize `ty` for the type variable `for_vid`. + /// This checks for cycle -- that is, whether the type `ty` + /// references `for_vid`. If `make_region_vars` is true, it will + /// also replace all regions with fresh variables. Returns + /// `TyError` in the case of a cycle, `Ok` otherwise. + /// + /// Preconditions: + /// + /// - `for_vid` is a "root vid" fn generalize(&self, ty: Ty<'tcx>, for_vid: ty::TyVid, make_region_vars: bool) -> RelateResult<'tcx, Ty<'tcx>> { + debug_assert!(self.infcx.type_variables.borrow_mut().root_var(for_vid) == for_vid); + let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, - for_vid: for_vid, + for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), make_region_vars: make_region_vars, cycle_detected: false }; @@ -293,7 +300,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, span: Span, - for_vid: ty::TyVid, + for_vid_sub_root: ty::TyVid, make_region_vars: bool, cycle_detected: bool, } @@ -305,17 +312,17 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { // Check to see whether the type we are genealizing references - // `vid`. At the same time, also update any type variables to - // the values that they are bound to. This is needed to truly - // check for cycles, but also just makes things readable. - // - // (In particular, you could have something like `$0 = Box<$1>` - // where `$1` has already been instantiated with `Box<$0>`) + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. match t.sty { ty::TyInfer(ty::TyVar(vid)) => { let mut variables = self.infcx.type_variables.borrow_mut(); let vid = variables.root_var(vid); - if vid == self.for_vid { + let sub_vid = variables.sub_root_var(vid); + if sub_vid == self.for_vid_sub_root { + // If sub-roots are equal, then `for_vid` and + // `vid` are related via subtyping. self.cycle_detected = true; self.tcx().types.err } else { @@ -324,7 +331,18 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx drop(variables); self.fold_ty(u) } - None => t, + None => { + if self.make_region_vars { + let origin = variables.origin(vid); + let new_var_id = variables.new_var(false, origin, None); + let u = self.tcx().mk_var(new_var_id); + debug!("generalize: replacing original vid={:?} with new={:?}", + vid, u); + u + } else { + t + } + } } } } diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 806b94486615..ab0ff32dcc3e 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::{self, TyCtxt}; +use infer::type_variable::TypeVariableMap; +use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use super::InferCtxt; @@ -54,57 +55,52 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// the actual types (`?T`, `Option(&self, origin: &RegionVariableOrigin, f: F) -> Result where F: FnOnce() -> Result, T: TypeFoldable<'tcx>, { - let (region_vars, value) = self.probe(|snapshot| { - let vars_at_start = self.type_variables.borrow().num_vars(); + debug!("fudge_regions_if_ok(origin={:?})", origin); + let (type_variables, region_vars, value) = self.probe(|snapshot| { match f() { Ok(value) => { let value = self.resolve_type_vars_if_possible(&value); // At this point, `value` could in principle refer - // to regions that have been created during the - // snapshot (we assert below that `f()` does not - // create any new type variables, so there - // shouldn't be any of those). Once we exit - // `probe()`, those are going to be popped, so we - // will have to eliminate any references to them. + // to types/regions that have been created during + // the snapshot. Once we exit `probe()`, those are + // going to be popped, so we will have to + // eliminate any references to them. - assert_eq!(self.type_variables.borrow().num_vars(), vars_at_start, - "type variables were created during fudge_regions_if_ok"); + let type_variables = + self.type_variables.borrow_mut().types_created_since_snapshot( + &snapshot.type_snapshot); let region_vars = self.region_vars.vars_created_since_snapshot( &snapshot.region_vars_snapshot); - Ok((region_vars, value)) + Ok((type_variables, region_vars, value)) } Err(e) => Err(e), } })?; // At this point, we need to replace any of the now-popped - // region variables that appear in `value` with a fresh region - // variable. We can't do this during the probe because they - // would just get popped then too. =) + // type/region variables that appear in `value` with a fresh + // variable of the appropriate kind. We can't do this during + // the probe because they would just get popped then too. =) // Micro-optimization: if no variables have been created, then // `value` can't refer to any of them. =) So we can just return it. - if region_vars.is_empty() { + if type_variables.is_empty() && region_vars.is_empty() { return Ok(value); } let mut fudger = RegionFudger { infcx: self, + type_variables: &type_variables, region_vars: ®ion_vars, origin: origin }; @@ -115,6 +111,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + type_variables: &'a TypeVariableMap, region_vars: &'a Vec, origin: &'a RegionVariableOrigin, } @@ -124,6 +121,40 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { self.infcx.tcx } + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::TyInfer(ty::InferTy::TyVar(vid)) => { + match self.type_variables.get(&vid) { + None => { + // This variable was created before the + // "fudging". Since we refresh all type + // variables to their binding anyhow, we know + // that it is unbound, so we can just return + // it. + debug_assert!(self.infcx.type_variables.borrow_mut().probe(vid).is_none()); + ty + } + + Some(info) => { + // This variable was created during the + // fudging; it was mapped the root + // `root_vid`. There are now two + // possibilities: either the root was creating + // during the fudging too, in which case we + // want a fresh variable, or it was not, in + // which case we can return it. + if self.type_variables.contains_key(&info.root_vid) { + self.infcx.next_ty_var(info.root_origin) + } else { + self.infcx.tcx.mk_var(info.root_vid) + } + } + } + } + _ => ty.super_fold_with(self), + } + } + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { match *r { ty::ReVar(v) if self.region_vars.contains(&v) => { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 999ebbfa20fb..e98792b120de 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1036,9 +1036,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = &ObligationCause::dummy(); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.sub(true, trace, &a, &b).map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. }) }) } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index f1de9b043e36..2a7dbbc026bc 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -80,7 +80,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(_)), &ty::TyInfer(TyVar(_))) => { + (&ty::TyInfer(TyVar(a_vid)), &ty::TyInfer(TyVar(b_vid))) => { // Shouldn't have any LBR here, so we can safely put // this under a binder below without fear of accidental // capture. @@ -88,7 +88,11 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> assert!(!b.has_escaping_regions()); // can't make progress on `A <: B` if both A and B are - // type variables, so record an obligation. + // type variables, so record an obligation. We also + // have to record in the `type_variables` tracker that + // the two variables are equal modulo subtyping, which + // is important to the occurs check later on. + infcx.type_variables.borrow_mut().sub(a_vid, b_vid); self.fields.obligations.push( Obligation::new( self.fields.trace.cause.clone(), diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 298b2a97d5f3..a32404c1ac51 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -18,16 +18,39 @@ use std::cmp::min; use std::marker::PhantomData; use std::mem; use std::u32; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; pub struct TypeVariableTable<'tcx> { values: sv::SnapshotVec>, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X == ?Y`. eq_relations: ut::UnificationTable, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second + /// table exists only to help with the occurs check. In particular, + /// we want to report constraints like these as an occurs check + /// violation: + /// + /// ?1 <: ?3 + /// Box <: ?1 + /// + /// This works because `?1` and `?3` are unified in the + /// `sub_relations` relation (not in `eq_relations`). Then when we + /// process the `Box <: ?1` constraint, we do an occurs check + /// on `Box` and find a potential cycle. + /// + /// This is reasonable because, in Rust, subtypes have the same + /// "skeleton" and hence there is no possible type such that + /// (e.g.) `Box <: ?3` for any `?3`. + sub_relations: ut::UnificationTable, } /// Reasons to create a type inference variable -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), @@ -41,6 +64,14 @@ pub enum TypeVariableOrigin { DivergingBlockExpr(Span), DivergingFn(Span), LatticeVariable(Span), + Generalized(ty::TyVid), +} + +pub type TypeVariableMap = FxHashMap; + +pub struct TypeVariableInfo { + pub root_vid: ty::TyVid, + pub root_origin: TypeVariableOrigin, } struct TypeVariableData<'tcx> { @@ -70,6 +101,7 @@ pub struct Default<'tcx> { pub struct Snapshot { snapshot: sv::Snapshot, eq_snapshot: ut::Snapshot, + sub_snapshot: ut::Snapshot, } struct Instantiate<'tcx> { @@ -84,6 +116,7 @@ impl<'tcx> TypeVariableTable<'tcx> { TypeVariableTable { values: sv::SnapshotVec::new(), eq_relations: ut::UnificationTable::new(), + sub_relations: ut::UnificationTable::new(), } } @@ -109,6 +142,16 @@ impl<'tcx> TypeVariableTable<'tcx> { debug_assert!(self.probe(a).is_none()); debug_assert!(self.probe(b).is_none()); self.eq_relations.union(a, b); + self.sub_relations.union(a, b); + } + + /// Records that `a <: b`, depending on `dir`. + /// + /// Precondition: neither `a` nor `b` are known. + pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.sub_relations.union(a, b); } /// Instantiates `vid` with the type `ty`. @@ -141,6 +184,7 @@ impl<'tcx> TypeVariableTable<'tcx> { default: Option>,) -> ty::TyVid { debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); + self.sub_relations.new_key(()); let index = self.values.push(TypeVariableData { value: Bounded { default: default }, origin: origin, @@ -155,15 +199,41 @@ impl<'tcx> TypeVariableTable<'tcx> { self.values.len() } + /// Returns the "root" variable of `vid` in the `eq_relations` + /// equivalence table. All type variables that have been equated + /// will yield the same root variable (per the union-find + /// algorithm), so `root_var(a) == root_var(b)` implies that `a == + /// b` (transitively). pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations.find(vid) } + /// Returns the "root" variable of `vid` in the `sub_relations` + /// equivalence table. All type variables that have been are + /// related via equality or subtyping will yield the same root + /// variable (per the union-find algorithm), so `sub_root_var(a) + /// == sub_root_var(b)` implies that: + /// + /// exists X. (a <: X || X <: a) && (b <: X || X <: b) + pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + self.sub_relations.find(vid) + } + + /// True if `a` and `b` have same "sub-root" (i.e., exists some + /// type X such that `forall i in {a, b}. (i <: X || X <: i)`. + pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { + self.sub_root_var(a) == self.sub_root_var(b) + } + pub fn probe(&mut self, vid: ty::TyVid) -> Option> { let vid = self.root_var(vid); self.probe_root(vid) } + pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { + self.values.get(vid.index as usize).origin.clone() + } + /// Retrieves the type of `vid` given that it is currently a root in the unification table pub fn probe_root(&mut self, vid: ty::TyVid) -> Option> { debug_assert!(self.root_var(vid) == vid); @@ -189,6 +259,7 @@ impl<'tcx> TypeVariableTable<'tcx> { Snapshot { snapshot: self.values.start_snapshot(), eq_snapshot: self.eq_relations.snapshot(), + sub_snapshot: self.sub_relations.snapshot(), } } @@ -204,13 +275,40 @@ impl<'tcx> TypeVariableTable<'tcx> { } }); - self.values.rollback_to(s.snapshot); - self.eq_relations.rollback_to(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.rollback_to(snapshot); + self.eq_relations.rollback_to(eq_snapshot); + self.sub_relations.rollback_to(sub_snapshot); } pub fn commit(&mut self, s: Snapshot) { - self.values.commit(s.snapshot); - self.eq_relations.commit(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.commit(snapshot); + self.eq_relations.commit(eq_snapshot); + self.sub_relations.commit(sub_snapshot); + } + + /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are + /// ty-variables created during the snapshot, and the values + /// `{V2}` are the root variables that they were unified with, + /// along with their origin. + pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap { + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + let eq_relations = &mut self.eq_relations; + let values = &self.values; + + actions_since_snapshot + .iter() + .filter_map(|action| match action { + &sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }), + _ => None, + }) + .map(|vid| { + let root_vid = eq_relations.find(vid); + let root_origin = values.get(vid.index as usize).origin.clone(); + (vid, TypeVariableInfo { root_vid, root_origin }) + }) + .collect() } pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec> { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8a303a5da118..f7a7d0e2071f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -69,6 +69,19 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { found_pattern: Option<&'a Pat>, } +impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn is_match(&self, ty: Ty<'tcx>) -> bool { + ty == *self.target_ty || match (&ty.sty, &self.target_ty.sty) { + (&ty::TyInfer(ty::TyVar(a_vid)), &ty::TyInfer(ty::TyVar(b_vid))) => + self.infcx.type_variables + .borrow_mut() + .sub_unified(a_vid, b_vid), + + _ => false, + } + } +} + impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { NestedVisitorMap::None @@ -77,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn visit_local(&mut self, local: &'a Local) { if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) { let ty = self.infcx.resolve_type_vars_if_possible(&ty); - let is_match = ty.walk().any(|t| t == *self.target_ty); + let is_match = ty.walk().any(|t| self.is_match(t)); if is_match && self.found_pattern.is_none() { self.found_pattern = Some(&*local.pat); @@ -564,8 +577,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ty::Predicate::Subtype(ref predicate) => { - // TODO - panic!("subtype requirement not satisfied {:?}", predicate) + // Errors for Subtype predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) } ty::Predicate::Equate(ref predicate) => { @@ -779,7 +794,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // no need to overload user in such cases } else { let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); - assert!(a.is_ty_var() && b.is_ty_var()); // else other would've been instantiated + // both must be type variables, or the other would've been instantiated + assert!(a.is_ty_var() && b.is_ty_var()); self.need_type_info(obligation, a); } } diff --git a/src/test/run-pass/issue-40951.rs b/src/test/run-pass/issue-40951.rs new file mode 100644 index 000000000000..adc7101b16aa --- /dev/null +++ b/src/test/run-pass/issue-40951.rs @@ -0,0 +1,20 @@ +// 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. + +// Regression test for #40951. + +const FOO: [&'static str; 1] = ["foo"]; + +fn find(t: &[T], element: &T) { } + +fn main() { + let x = format!("hi"); + find(&FOO, &&*x); +} diff --git a/src/test/run-pass/type-infer-generalize-ty-var.rs b/src/test/run-pass/type-infer-generalize-ty-var.rs new file mode 100644 index 000000000000..d7fb85ca4842 --- /dev/null +++ b/src/test/run-pass/type-infer-generalize-ty-var.rs @@ -0,0 +1,60 @@ +// 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 a scenario where we generate a constraint like `?1 <: &?2`. +// In such a case, it is important that we instantiate `?1` with `&?3` +// where `?3 <: ?2`, and not with `&?2`. This is a regression test for +// #18653. The important thing is that we build. + +use std::cell::RefCell; + +enum Wrap { + WrapSome(A), + WrapNone +} + +use Wrap::*; + +struct T; +struct U; + +trait Get { + fn get(&self) -> &T; +} + +impl Get for Wrap { + fn get(&self) -> &(MyShow + 'static) { + static x: usize = 42; + &x + } +} + +impl Get for Wrap { + fn get(&self) -> &usize { + static x: usize = 55; + &x + } +} + +trait MyShow { fn dummy(&self) { } } +impl<'a> MyShow for &'a (MyShow + 'a) { } +impl MyShow for usize { } +fn constrain<'a>(rc: RefCell<&'a (MyShow + 'a)>) { } + +fn main() { + let mut collection: Wrap<_> = WrapNone; + + { + let __arg0 = Get::get(&collection); + let __args_cell = RefCell::new(__arg0); + constrain(__args_cell); + } + collection = WrapSome(T); +} From 1c138ed1c79cfac39c47cc4119a464f9b638a9c6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:10:26 -0400 Subject: [PATCH 435/905] update various test cases that generate slightly different output For the most part, it seems to be better, but one side-effect is that I cannot seem to reproduce E0102 anymore. --- src/librustc_typeck/diagnostics.rs | 2 +- src/test/compile-fail/E0102.rs | 5 +++-- src/test/compile-fail/destructure-trait-ref.rs | 2 +- src/test/compile-fail/issue-12187-1.rs | 1 + src/test/compile-fail/issue-12187-2.rs | 1 + src/test/compile-fail/issue-7813.rs | 7 ++++--- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index fb951fd20e56..2d72052f1e5a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1378,7 +1378,7 @@ E0102: r##" You hit this error because the compiler lacks the information to determine the type of this variable. Erroneous code example: -```compile_fail,E0102 +```compile_fail,E0282 // could be an array of anything let x = []; // error: cannot determine a type for this local variable ``` diff --git a/src/test/compile-fail/E0102.rs b/src/test/compile-fail/E0102.rs index 1d64798bb838..6a17ddebd1dc 100644 --- a/src/test/compile-fail/E0102.rs +++ b/src/test/compile-fail/E0102.rs @@ -10,6 +10,7 @@ fn main() { let x = []; - //~^ ERROR E0102 - //~| NOTE cannot resolve type of variable + //~^ ERROR type annotations needed + //~| NOTE consider giving `x` a type + //~| NOTE cannot infer type for `_` } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 835ec8e4a5e7..09bd3a2fc57d 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -35,7 +35,7 @@ fn main() { // n == m let &x = &1isize as &T; //~ ERROR type `&T` cannot be dereferenced let &&x = &(&1isize as &T); //~ ERROR type `&T` cannot be dereferenced - let box x = box 1isize as Box; //~ ERROR `T: std::marker::Sized` is not satisfied + let box x = box 1isize as Box; //~ ERROR type `std::boxed::Box` cannot be dereferenced // n > m let &&x = &1isize as &T; diff --git a/src/test/compile-fail/issue-12187-1.rs b/src/test/compile-fail/issue-12187-1.rs index 346fae11070e..6aeb9442c40e 100644 --- a/src/test/compile-fail/issue-12187-1.rs +++ b/src/test/compile-fail/issue-12187-1.rs @@ -16,4 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` + //~| NOTE consider giving a type to pattern } diff --git a/src/test/compile-fail/issue-12187-2.rs b/src/test/compile-fail/issue-12187-2.rs index 848174d6fe1e..d52ed06c4085 100644 --- a/src/test/compile-fail/issue-12187-2.rs +++ b/src/test/compile-fail/issue-12187-2.rs @@ -16,4 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` + //~| NOTE consider giving a type to pattern } diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index 2551ed0208af..a5f001b785cc 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -9,7 +9,8 @@ // except according to those terms. fn main() { - let v = &[]; //~ NOTE consider giving `v` a type - let it = v.iter(); //~ ERROR type annotations needed - //~^ NOTE cannot infer type for `_` + let v = &[]; //~ ERROR type annotations needed + //~| NOTE consider giving `v` a type + //~| NOTE cannot infer type for `_` + let it = v.iter(); } From 761808ef40b1e2cc9b35f0891a66d2dcf3274834 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:11:05 -0400 Subject: [PATCH 436/905] just panic in rustdoc if we encounter a subtype predicate These are not user expressible anyhow. --- src/librustdoc/clean/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a194cd12546..fb8ba51853fe 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -838,7 +838,7 @@ impl Clean> for ty::Region { pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec}, - EqPredicate { lhs: Type, rhs: Type } + EqPredicate { lhs: Type, rhs: Type }, } impl Clean for hir::WherePredicate { @@ -906,12 +906,9 @@ impl<'tcx> Clean for ty::EquatePredicate<'tcx> { } impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { - fn clean(&self, cx: &DocContext) -> WherePredicate { - let ty::SubtypePredicate { a_is_expected: _, a, b } = *self; - WherePredicate::EqPredicate { // TODO This is obviously wrong :P - lhs: a.clean(cx), - rhs: b.clean(cx) - } + fn clean(&self, _cx: &DocContext) -> WherePredicate { + panic!("subtype predicates are an internal rustc artifact \ + and should not be seen by rustdoc") } } From 59babd80bde4ce2f96768e44047ba0e44afc8eac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:11:22 -0400 Subject: [PATCH 437/905] add some comments and `debug!` calls to "obligation forest" --- .../obligation_forest/mod.rs | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index a46238309bb4..3515e5c5ede3 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -43,7 +43,16 @@ pub trait ObligationProcessor { obligation: &mut Self::Obligation) -> Result>, Self::Error>; - fn process_backedge<'c, I>(&mut self, cycle: I, + /// As we do the cycle check, we invoke this callback when we + /// encounter an actual cycle. `cycle` is an iterator that starts + /// at the start of the cycle in the stack and walks **toward the + /// top**. + /// + /// In other words, if we had O1 which required O2 which required + /// O3 which required O1, we would give an iterator yielding O1, + /// O2, O3 (O1 is not yielded twice). + fn process_backedge<'c, I>(&mut self, + cycle: I, _marker: PhantomData<&'c Self::Obligation>) where I: Clone + Iterator; } @@ -239,8 +248,8 @@ impl ObligationForest { } } Entry::Vacant(v) => { - debug!("register_obligation_at({:?}, {:?}) - ok", - obligation, parent); + debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}", + obligation, parent, self.nodes.len()); v.insert(NodeIndex::new(self.nodes.len())); self.cache_list.push(obligation.as_predicate().clone()); self.nodes.push(Node::new(parent, obligation)); @@ -376,6 +385,9 @@ impl ObligationForest { where P: ObligationProcessor { let mut stack = self.scratch.take().unwrap(); + debug_assert!(stack.is_empty()); + + debug!("process_cycles()"); for index in 0..self.nodes.len() { // For rustc-benchmarks/inflate-0.1.0 this state test is extremely @@ -389,6 +401,9 @@ impl ObligationForest { } } + debug!("process_cycles: complete"); + + debug_assert!(stack.is_empty()); self.scratch = Some(stack); } @@ -402,21 +417,6 @@ impl ObligationForest { NodeState::OnDfsStack => { let index = stack.iter().rposition(|n| *n == index).unwrap(); - // I need a Clone closure - #[derive(Clone)] - struct GetObligation<'a, O: 'a>(&'a [Node]); - impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { - type Output = &'a O; - extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { - extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)), PhantomData); } @@ -645,3 +645,20 @@ impl Node { } } } + +// I need a Clone closure +#[derive(Clone)] +struct GetObligation<'a, O: 'a>(&'a [Node]); + +impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { + type Output = &'a O; + extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} + +impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { + extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} From 0fae3324a2f58e921e2094a6971962c0b09c04ee Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:11:41 -0400 Subject: [PATCH 438/905] add some debug! to coercion --- src/librustc_typeck/check/coercion.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a5acd0c7e530..2033eaf88616 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -195,8 +195,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Consider coercing the subtype to a DST let unsize = self.coerce_unsized(a, b); if unsize.is_ok() { + debug!("coerce: unsize successful"); return unsize; } + debug!("coerce: unsize failed"); // Examine the supertype and consider auto-borrowing. // @@ -745,7 +747,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); let new_ty = self.resolve_type_vars_with_obligations(new_ty); - debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); // Special-ish case: we can coerce any type `T` into the `!` // type, but only if the source expression diverges. From 7832db8031a9051d377e1da92bbcd56e366354c1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 11 Apr 2017 17:12:00 -0400 Subject: [PATCH 439/905] fix long line --- src/librustc/traits/structural_impls.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index fcaa29be9632..9d0b1035ade4 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -130,7 +130,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { match *self { super::CodeSelectionError(ref e) => write!(f, "{:?}", e), super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeSubtypeError(ref a, ref b) => write!(f, "CodeSubtypeError({:?}, {:?})", a, b), + super::CodeSubtypeError(ref a, ref b) => + write!(f, "CodeSubtypeError({:?}, {:?})", a, b), super::CodeAmbiguity => write!(f, "Ambiguity") } } From ed7b6c3724be948bc04aaf3ed4311c877bde6dd3 Mon Sep 17 00:00:00 2001 From: projektir Date: Wed, 12 Apr 2017 00:10:36 -0400 Subject: [PATCH 440/905] Minor nits in primitive str --- src/libcollections/str.rs | 37 +++++++++++++++++++++++------------- src/libstd/primitive_docs.rs | 8 ++++---- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c37a4fa6b557..f85336b8afbf 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -318,8 +318,10 @@ impl str { /// Returns a subslice of `str`. /// - /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever - /// equivalent indexing operation would panic. + /// 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 /// @@ -339,8 +341,10 @@ impl str { /// Returns a mutable subslice of `str`. /// - /// This is the non-panicking alternative to indexing the `str`. Returns `None` whenever - /// equivalent indexing operation would panic. + /// 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 /// @@ -563,7 +567,7 @@ impl str { core_str::StrExt::split_at_mut(self, mid) } - /// Returns an iterator over the `char`s of a string slice. + /// 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. @@ -1650,13 +1654,13 @@ impl str { /// 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 + /// 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. + /// `parse` can parse any type that implements the [`FromStr`] trait. /// /// [`FromStr`]: str/trait.FromStr.html /// @@ -1739,7 +1743,7 @@ impl str { /// /// `replacen` creates a new [`String`], and copies the data from this string slice into it. /// While doing so, it attempts to find matches of a pattern. If it finds any, it - /// replaces them with the replacement string slice at most `N` times. + /// replaces them with the replacement string slice at most `count` times. /// /// [`String`]: string/struct.String.html /// @@ -1885,7 +1889,9 @@ impl str { return s; } - /// Escapes each char in `s` with `char::escape_debug`. + /// Escapes each char in `s` with [`char::escape_debug`]. + /// + /// [`char::escape_debug`]: primitive.char.html#method.escape_debug #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1893,7 +1899,9 @@ impl str { self.chars().flat_map(|c| c.escape_debug()).collect() } - /// Escapes each char in `s` with `char::escape_default`. + /// Escapes each char in `s` with [`char::escape_default`]. + /// + /// [`char::escape_default`]: primitive.char.html#method.escape_default #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1901,7 +1909,9 @@ impl str { self.chars().flat_map(|c| c.escape_default()).collect() } - /// Escapes each char in `s` with `char::escape_unicode`. + /// Escapes each char in `s` with [`char::escape_unicode`]. + /// + /// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1909,9 +1919,10 @@ impl str { self.chars().flat_map(|c| c.escape_unicode()).collect() } - /// Converts a `Box` into a [`String`] without copying or allocating. + /// Converts a [`Box`] into a [`String`] without copying or allocating. /// /// [`String`]: string/struct.String.html + /// [`Box`]: boxed/struct.Box.html /// /// # Examples /// diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5b2053e929a1..8ae987557dd0 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -406,7 +406,7 @@ mod prim_slice { } /// /// This documentation describes a number of methods and trait implementations /// on the `str` type. For technical reasons, there is additional, separate -/// documentation in [the `std::str` module](str/index.html) as well. +/// documentation in the [`std::str`](str/index.html) module as well. /// /// # Examples /// @@ -425,7 +425,7 @@ mod prim_slice { } /// # Representation /// /// A `&str` is made up of two components: a pointer to some bytes, and a -/// length. You can look at these with the [`.as_ptr`] and [`len`] methods: +/// length. You can look at these with the [`as_ptr`] and [`len`] methods: /// /// ``` /// use std::slice; @@ -452,11 +452,11 @@ mod prim_slice { } /// assert_eq!(s, Ok(story)); /// ``` /// -/// [`.as_ptr`]: #method.as_ptr +/// [`as_ptr`]: #method.as_ptr /// [`len`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `.as_slice()` +/// used to get a string slice under normal circumstances. Use `as_slice` /// instead. #[stable(feature = "rust1", since = "1.0.0")] mod prim_str { } From 13c818fa27e4dd3994881fb2f45c2dea3d23363d Mon Sep 17 00:00:00 2001 From: projektir Date: Tue, 11 Apr 2017 22:29:42 -0400 Subject: [PATCH 441/905] Updating docs for std::sync::Weak #29377 --- src/liballoc/arc.rs | 66 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 28f6d97756f2..182a107e3f76 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -165,18 +165,29 @@ unsafe impl Sync for Arc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Arc {} -/// A weak version of [`Arc`][arc]. +/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. /// -/// `Weak` pointers do not count towards determining if the inner value -/// should be dropped. +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. /// -/// The typical way to obtain a `Weak` pointer is to call -/// [`Arc::downgrade`][downgrade]. +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Arc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Arc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. /// -/// See the [`Arc`][arc] documentation for more details. +/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. /// -/// [arc]: struct.Arc.html -/// [downgrade]: struct.Arc.html#method.downgrade +/// [`Arc`]: struct.Arc.html +/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -766,14 +777,11 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { } impl Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -798,13 +806,13 @@ impl Weak { } impl Weak { - /// Upgrades the `Weak` pointer to an [`Arc`][arc], if possible. + /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending + /// the lifetime of the value if successful. /// - /// Returns [`None`][option] if the strong count has reached zero and the - /// inner value was destroyed. + /// Returns [`None`] if the value has since been dropped. /// - /// [arc]: struct.Arc.html - /// [option]: ../../std/option/enum.Option.html + /// [`Arc`]: struct.Arc.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -865,10 +873,7 @@ impl Weak { #[stable(feature = "arc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// weak reference count. + /// Makes a clone of the `Weak` pointer that points to the same value. /// /// # Examples /// @@ -900,14 +905,11 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -926,8 +928,6 @@ impl Default for Weak { impl Drop for Weak { /// Drops the `Weak` pointer. /// - /// This will decrement the weak reference count. - /// /// # Examples /// /// ``` From f39145169f24cc6dd4c17f5529fc02169d8fea0d Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Mon, 10 Apr 2017 20:53:20 +0800 Subject: [PATCH 442/905] COPYRIGHT: remove hoedown license Hoedown was removed in b96fef8411f Also cleanup src/tools/tidy/src/main.rs Signed-off-by: NODA, Kai --- COPYRIGHT | 22 ---------------------- src/tools/tidy/src/main.rs | 2 -- 2 files changed, 24 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index abe899803087..19559fa2950e 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -197,28 +197,6 @@ their own copyright notices and license terms: USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* Hoedown, the markdown parser, under src/rt/hoedown, is - licensed as follows. - - Copyright (c) 2008, Natacha PortΓ© - Copyright (c) 2011, Vicent MartΓ­ - Copyright (c) 2013, Devin Torres and the Hoedown authors - - Permission to use, copy, modify, and distribute this - software for any purpose with or without fee is hereby - granted, provided that the above copyright notice and - this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR - DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR - ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA - OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * libbacktrace, under src/libbacktrace: Copyright (C) 2012-2014 Free Software Foundation, Inc. diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index dee37341051e..17f8b62117ad 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -82,11 +82,9 @@ fn filter_dirs(path: &Path) -> bool { "src/llvm", "src/libbacktrace", "src/compiler-rt", - "src/rt/hoedown", "src/rustllvm", "src/rust-installer", "src/liblibc", - "src/tools/cargo", "src/vendor", ]; skip.iter().any(|p| path.ends_with(p)) From 439ff69d909a0add54b1ea1e093bc838693d1e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 11 Apr 2017 04:40:31 -0700 Subject: [PATCH 443/905] Add a way to get shorter spans until `char` for pointing at defs ```rust error[E0072]: recursive type `X` has infinite size --> file.rs:10:1 | 10 | struct X { | ^^^^^^^^ recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `X` representable ``` vs ```rust error[E0072]: recursive type `X` has infinite size --> file.rs:10:1 | 10 | struct X { | _^ starting here... 11 | | x: X, 12 | | } | |_^ ...ending here: recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `X` representable ``` --- src/librustc/traits/error_reporting.rs | 28 +++++++++----------- src/libsyntax/codemap.rs | 19 +++++++++++++ src/test/ui/resolve/issue-3907-2.stderr | 2 +- src/test/{compile-fail => ui/span}/E0072.rs | 3 +-- src/test/ui/span/E0072.stderr | 10 +++++++ src/test/ui/span/multiline-span-E0072.rs | 20 ++++++++++++++ src/test/ui/span/multiline-span-E0072.stderr | 16 +++++++++++ 7 files changed, 80 insertions(+), 18 deletions(-) rename src/test/{compile-fail => ui/span}/E0072.rs (84%) create mode 100644 src/test/ui/span/E0072.stderr create mode 100644 src/test/ui/span/multiline-span-E0072.rs create mode 100644 src/test/ui/span/multiline-span-E0072.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 152dd6ac3000..dc85353c2198 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -293,22 +293,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Some(val) => Some(val), None => { span_err!(self.tcx.sess, err_sp, E0272, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} refers to \ - non-existent type parameter {}", - trait_str, s); + "the #[rustc_on_unimplemented] attribute on trait \ + definition for {} refers to non-existent type \ + parameter {}", + trait_str, s); errored = true; None } }, _ => { span_err!(self.tcx.sess, err_sp, E0273, - "the #[rustc_on_unimplemented] attribute \ - on trait definition for {} must have \ - named format arguments, eg \ - `#[rustc_on_unimplemented = \ - \"foo {{T}}\"]`", trait_str); + "the #[rustc_on_unimplemented] attribute on trait \ + definition for {} must have named format arguments, eg \ + `#[rustc_on_unimplemented = \"foo {{T}}\"]`", + trait_str); errored = true; None } @@ -449,8 +447,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "impl has stricter requirements than trait"); if let Some(trait_item_span) = self.tcx.hir.span_if_local(trait_item_def_id) { - err.span_label(trait_item_span, - &format!("definition of `{}` from trait", item_name)); + let span = self.tcx.sess.codemap().def_span(trait_item_span); + err.span_label(span, &format!("definition of `{}` from trait", item_name)); } err.span_label( @@ -652,6 +650,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { assert!(type_def_id.is_local()); let span = self.hir.span_if_local(type_def_id).unwrap(); + let span = self.sess.codemap().def_span(span); let mut err = struct_span_err!(self.sess, span, E0072, "recursive type `{}` has infinite size", self.item_path_str(type_def_id)); @@ -669,13 +668,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> { let trait_str = self.item_path_str(trait_def_id); + let span = self.sess.codemap().def_span(span); let mut err = struct_span_err!( self.sess, span, E0038, "the trait `{}` cannot be made into an object", trait_str); - err.span_label(span, &format!( - "the trait `{}` cannot be made into an object", trait_str - )); + err.span_label(span, &format!("the trait `{}` cannot be made into an object", trait_str)); let mut reported_violations = FxHashSet(); for violation in violations { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 4d67390d4423..da2d0a33d1a1 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -441,6 +441,25 @@ impl CodeMap { } } + /// Given a `Span`, try to get a shorter span ending before the first occurrence of `c` `char` + pub fn span_until_char(&self, sp: Span, c: char) -> Span { + match self.span_to_snippet(sp) { + Ok(snippet) => { + let snippet = snippet.split(c).nth(0).unwrap_or("").trim_right(); + if snippet.len() > 0 && !snippet.contains('\n') { + Span { hi: BytePos(sp.lo.0 + snippet.len() as u32), ..sp } + } else { + sp + } + } + _ => sp, + } + } + + pub fn def_span(&self, sp: Span) -> Span { + self.span_until_char(sp, '{') + } + pub fn get_filemap(&self, filename: &str) -> Option> { for fm in self.files.borrow().iter() { if filename == fm.name { diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr index ef02250e21cd..2ef8c830eb2f 100644 --- a/src/test/ui/resolve/issue-3907-2.stderr +++ b/src/test/ui/resolve/issue-3907-2.stderr @@ -2,7 +2,7 @@ error[E0038]: the trait `issue_3907::Foo` cannot be made into an object --> $DIR/issue-3907-2.rs:20:1 | 20 | fn bar(_x: Foo) {} - | ^^^^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object | = note: method `bar` has no receiver diff --git a/src/test/compile-fail/E0072.rs b/src/test/ui/span/E0072.rs similarity index 84% rename from src/test/compile-fail/E0072.rs rename to src/test/ui/span/E0072.rs index e6de7921b303..18ade4f1ab68 100644 --- a/src/test/compile-fail/E0072.rs +++ b/src/test/ui/span/E0072.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct ListNode { //~ ERROR E0072 - //~| NOTE recursive type has infinite size +struct ListNode { head: u8, tail: Option, } diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr new file mode 100644 index 000000000000..5204390ef9d2 --- /dev/null +++ b/src/test/ui/span/E0072.stderr @@ -0,0 +1,10 @@ +error[E0072]: recursive type `ListNode` has infinite size + --> $DIR/E0072.rs:11:1 + | +11 | struct ListNode { + | ^^^^^^^^^^^^^^^ recursive type has infinite size + | + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable + +error: aborting due to previous error + diff --git a/src/test/ui/span/multiline-span-E0072.rs b/src/test/ui/span/multiline-span-E0072.rs new file mode 100644 index 000000000000..323e7fb5a42c --- /dev/null +++ b/src/test/ui/span/multiline-span-E0072.rs @@ -0,0 +1,20 @@ +// 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. + +// It should just use the entire body instead of pointing at the next two lines +struct +ListNode +{ + head: u8, + tail: Option, +} + +fn main() { +} diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr new file mode 100644 index 000000000000..58cdc5023006 --- /dev/null +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -0,0 +1,16 @@ +error[E0072]: recursive type `ListNode` has infinite size + --> $DIR/multiline-span-E0072.rs:12:1 + | +12 | struct + | _^ starting here... +13 | | ListNode +14 | | { +15 | | head: u8, +16 | | tail: Option, +17 | | } + | |_^ ...ending here: recursive type has infinite size + | + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable + +error: aborting due to previous error + From 2e327a668e0f37fa9663ede580d354e28fc016bf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Apr 2017 05:42:02 -0400 Subject: [PATCH 444/905] fix nit --- src/librustc_borrowck/borrowck/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e0b4a23010d2..142286bd834d 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -69,7 +69,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) { *providers = Providers { - borrowck: borrowck, + borrowck, ..*providers }; } From c008cd70f5cb20cf22eb2cc9ae12f978296e8a45 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 6 Apr 2017 16:56:09 +0200 Subject: [PATCH 445/905] Make compiletest write test output to different files for different revisions. --- src/tools/compiletest/src/runtest.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 2865fa6a7925..7fb296c19f6e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1589,8 +1589,14 @@ actual:\n\ } fn dump_output(&self, out: &str, err: &str) { - self.dump_output_file(out, "out"); - self.dump_output_file(err, "err"); + let revision = if let Some(r) = self.revision { + format!("{}.", r) + } else { + String::new() + }; + + self.dump_output_file(out, &format!("{}out", revision)); + self.dump_output_file(err, &format!("{}err", revision)); self.maybe_dump_to_stdout(out, err); } From bc7af816f3b8712efa4e6643f9cdeb1d5ba5c78a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 5 Apr 2017 13:00:17 +0200 Subject: [PATCH 446/905] ICH: Hash everything that gets encoded into crate metadata. --- src/librustc/ich/hcx.rs | 52 ++++ src/librustc/ich/impls_ty.rs | 291 +++++++++++++++++- src/librustc/ich/mod.rs | 4 +- src/librustc/lib.rs | 1 + src/librustc/middle/free_region.rs | 4 + src/librustc_data_structures/array_vec.rs | 6 + .../transitive_relation.rs | 46 +++ src/librustc_metadata/astencode.rs | 42 +-- src/librustc_metadata/encoder.rs | 60 ++-- src/librustc_metadata/index_builder.rs | 77 ++++- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/schema.rs | 58 ++++ 12 files changed, 576 insertions(+), 66 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 5ef30550f115..3a6367c353c1 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -13,8 +13,10 @@ use hir::def_id::DefId; use ich::{self, CachingCodemapView}; use session::config::DebugInfoLevel::NoDebugInfo; use ty; +use util::nodemap::NodeMap; use std::hash as std_hash; +use std::collections::{HashMap, HashSet}; use syntax::ast; use syntax::attr; @@ -296,3 +298,53 @@ impl<'a, 'tcx> HashStable> for Span { } } } + +pub fn hash_stable_hashmap<'a, 'tcx, K, V, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &HashMap, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + V: HashStable>, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = map.keys() + .map(|k| (extract_stable_key(hcx, k), k)) + .collect(); + keys.sort_unstable_by_key(|&(ref stable_key, _)| stable_key.clone()); + keys.len().hash_stable(hcx, hasher); + for (stable_key, key) in keys { + stable_key.hash_stable(hcx, hasher); + map[key].hash_stable(hcx, hasher); + } +} + +pub fn hash_stable_hashset<'a, 'tcx, K, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + set: &HashSet, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = set.iter() + .map(|k| extract_stable_key(hcx, k)) + .collect(); + keys.sort_unstable(); + keys.hash_stable(hcx, hasher); +} + +pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &NodeMap) + where V: HashStable>, + W: StableHasherResult, +{ + hash_stable_hashmap(hcx, hasher, map, |hcx, node_id| { + hcx.tcx.hir.definitions().node_to_hir_id(*node_id).local_id + }); +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b6f3af2a11e..c682f6b8668c 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -11,31 +11,37 @@ //! This module contains `HashStable` implementations for various data types //! from rustc::ty in no particular order. -use ich::StableHashingContext; +use ich::{self, StableHashingContext, NodeIdHashingMode}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; use std::mem; use ty; - -impl<'a, 'tcx> HashStable> for ty::Ty<'tcx> { +impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { - let type_hash = hcx.tcx().type_id_hash(*self); - type_hash.hash_stable(hcx, hasher); + let ty::TyS { + ref sty, + + // The other fields just provide fast access to information that is + // also contained in `sty`, so no need to hash them. + .. + } = *self; + + sty.hash_stable(hcx, hasher); } } impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); -impl<'a, 'tcx, T> HashStable> for ty::Slice +impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice where T: HashStable> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { - (&**self).hash_stable(hcx, hasher); + (&self[..]).hash_stable(hcx, hasher); } } @@ -67,9 +73,13 @@ impl<'a, 'tcx> HashStable> for ty::Region { index.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } + ty::ReScope(code_extent) => { + code_extent.hash_stable(hcx, hasher); + } + ty::ReFree(ref free_region) => { + free_region.hash_stable(hcx, hasher); + } ty::ReLateBound(..) | - ty::ReFree(..) | - ty::ReScope(..) | ty::ReVar(..) | ty::ReSkolemized(..) => { bug!("TypeIdHasher: unexpected region {:?}", *self) @@ -127,7 +137,6 @@ impl_stable_hash_for!(enum ty::BorrowKind { MutBorrow }); - impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, @@ -223,7 +232,6 @@ impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx } } - impl<'a, 'tcx> HashStable> for ty::AdtFlags { fn hash_stable(&self, _: &mut StableHashingContext<'a, 'tcx>, @@ -303,7 +311,6 @@ for ::middle::const_val::ConstVal<'tcx> { impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); - impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { parent, predicates @@ -413,3 +420,263 @@ impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { impl_stable_hash_for!(struct ty::DebruijnIndex { depth }); + +impl_stable_hash_for!(enum ty::cast::CastKind { + CoercionCast, + PtrPtrCast, + PtrAddrCast, + AddrPtrCast, + NumericCast, + EnumCast, + PrimIntCast, + U8CharCast, + ArrayPtrCast, + FnPtrPtrCast, + FnPtrAddrCast +}); + +impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtent +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + hcx.tcx().region_maps.code_extent_data(*self).hash_stable(hcx, hasher); + }); + } +} + +impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtentData +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::region::CodeExtentData; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + CodeExtentData::Misc(node_id) | + CodeExtentData::DestructionScope(node_id) => { + node_id.hash_stable(hcx, hasher); + } + CodeExtentData::CallSiteScope { fn_id, body_id } | + CodeExtentData::ParameterScope { fn_id, body_id } => { + fn_id.hash_stable(hcx, hasher); + body_id.hash_stable(hcx, hasher); + } + CodeExtentData::Remainder(block_remainder) => { + block_remainder.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::middle::region::BlockRemainder { + block, + first_statement_index +}); + +impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo { + custom_kind +}); + +impl_stable_hash_for!(struct ty::FreeRegion { + scope, + bound_region +}); + +impl_stable_hash_for!(enum ty::BoundRegion { + BrAnon(index), + BrNamed(def_id, name), + BrFresh(index), + BrEnv +}); + +impl<'a, 'tcx> HashStable> for ty::TypeVariants<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use ty::TypeVariants::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + TyBool | + TyChar | + TyStr | + TyNever => { + // Nothing more to hash. + } + TyInt(int_ty) => { + int_ty.hash_stable(hcx, hasher); + } + TyUint(uint_ty) => { + uint_ty.hash_stable(hcx, hasher); + } + TyFloat(float_ty) => { + float_ty.hash_stable(hcx, hasher); + } + TyAdt(adt_def, substs) => { + adt_def.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyArray(inner_ty, len) => { + inner_ty.hash_stable(hcx, hasher); + len.hash_stable(hcx, hasher); + } + TySlice(inner_ty) => { + inner_ty.hash_stable(hcx, hasher); + } + TyRawPtr(pointee_ty) => { + pointee_ty.hash_stable(hcx, hasher); + } + TyRef(region, pointee_ty) => { + region.hash_stable(hcx, hasher); + pointee_ty.hash_stable(hcx, hasher); + } + TyFnDef(def_id, substs, ref sig) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + sig.hash_stable(hcx, hasher); + } + TyFnPtr(ref sig) => { + sig.hash_stable(hcx, hasher); + } + TyDynamic(ref existential_predicates, region) => { + existential_predicates.hash_stable(hcx, hasher); + region.hash_stable(hcx, hasher); + } + TyClosure(def_id, closure_substs) => { + def_id.hash_stable(hcx, hasher); + closure_substs.hash_stable(hcx, hasher); + } + TyTuple(inner_tys, from_diverging_type_var) => { + inner_tys.hash_stable(hcx, hasher); + from_diverging_type_var.hash_stable(hcx, hasher); + } + TyProjection(ref projection_ty) => { + projection_ty.hash_stable(hcx, hasher); + } + TyAnon(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyParam(param_ty) => { + param_ty.hash_stable(hcx, hasher); + } + + TyError | + TyInfer(..) => { + bug!("ty::TypeVariants::hash_stable() - Unexpected variant.") + } + } + } +} + +impl_stable_hash_for!(struct ty::ParamTy { + idx, + name +}); + +impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> { + ty, + mutbl +}); + +impl<'a, 'tcx> HashStable> for ty::ExistentialPredicate<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ExistentialPredicate::Trait(ref trait_ref) => { + trait_ref.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::Projection(ref projection) => { + projection.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + def_id.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ExistentialTraitRef<'tcx> { + def_id, + substs +}); + +impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> { + trait_ref, + item_name, + ty +}); + + +impl<'a, 'tcx> HashStable> for ty::TypeckTables<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TypeckTables { + ref type_relative_path_defs, + ref node_types, + ref item_substs, + ref adjustments, + ref method_map, + ref upvar_capture_map, + ref closure_tys, + ref closure_kinds, + ref liberated_fn_sigs, + ref fru_field_types, + + ref cast_kinds, + lints: _, + ref used_trait_imports, + tainted_by_errors, + ref free_region_map, + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs); + ich::hash_stable_nodemap(hcx, hasher, node_types); + ich::hash_stable_nodemap(hcx, hasher, item_substs); + ich::hash_stable_nodemap(hcx, hasher, adjustments); + + ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| { + let ty::MethodCall { + expr_id, + autoderef + } = *method_call; + + let def_id = hcx.tcx().hir.local_def_id(expr_id); + (hcx.def_path_hash(def_id), autoderef) + }); + + ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { + let ty::UpvarId { + var_id, + closure_expr_id + } = *up_var_id; + + let var_def_id = hcx.tcx().hir.local_def_id(var_id); + let closure_def_id = hcx.tcx().hir.local_def_id(closure_expr_id); + (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id)) + }); + + ich::hash_stable_nodemap(hcx, hasher, closure_tys); + ich::hash_stable_nodemap(hcx, hasher, closure_kinds); + ich::hash_stable_nodemap(hcx, hasher, liberated_fn_sigs); + ich::hash_stable_nodemap(hcx, hasher, fru_field_types); + ich::hash_stable_nodemap(hcx, hasher, cast_kinds); + + ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { + hcx.tcx().def_path_hash(*def_id) + }); + + tainted_by_errors.hash_stable(hcx, hasher); + free_region_map.hash_stable(hcx, hasher); + }) + } +} diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index f932c90a331e..d70ed051ac41 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -12,8 +12,8 @@ pub use self::fingerprint::Fingerprint; pub use self::caching_codemap_view::CachingCodemapView; -pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; - +pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap, + hash_stable_hashset, hash_stable_nodemap}; mod fingerprint; mod caching_codemap_view; mod hcx; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3b002fd4dfc1..1f96330d51da 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -42,6 +42,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(discriminant_value)] +#![feature(sort_unstable)] extern crate arena; extern crate core; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab4009..a8eb6a107438 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -180,3 +180,7 @@ fn lub() { map.relate_free_regions(frs[1], frs[2]); assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2])); } + +impl_stable_hash_for!(struct FreeRegionMap { + relation +}); diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index adb221972260..848e5a076bb9 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -40,6 +40,12 @@ unsafe impl Array for [T; 8] { const LEN: usize = 8; } +unsafe impl Array for [T; 32] { + type Element = T; + type PartialStorage = [ManuallyDrop; 32]; + const LEN: usize = 32; +} + pub struct ArrayVec { count: usize, values: A::PartialStorage diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 2bce7faf08ce..2631108aeb5f 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,11 +9,14 @@ // except according to those terms. use bitvec::BitMatrix; +use stable_hasher::{HashStable, StableHasher, StableHasherResult}; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::fmt::Debug; use std::mem; + + #[derive(Clone)] pub struct TransitiveRelation { // List of elements. This is used to map from a T to a usize. We @@ -334,6 +337,49 @@ impl Decodable for TransitiveRelation } } +impl HashStable for TransitiveRelation + where T: HashStable + PartialEq + Debug +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + // We are assuming here that the relation graph has been built in a + // deterministic way and we can just hash it the way it is. + let TransitiveRelation { + ref elements, + ref edges, + // "closure" is just a copy of the data above + closure: _ + } = *self; + + elements.hash_stable(hcx, hasher); + edges.hash_stable(hcx, hasher); + } +} + +impl HashStable for Edge { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Edge { + ref source, + ref target, + } = *self; + + source.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + } +} + +impl HashStable for Index { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Index(idx) = *self; + idx.hash_stable(hcx, hasher); + } +} + #[test] fn test_one_step() { let mut relation = TransitiveRelation::new(); diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 459132eb9c61..d9008ce555cc 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -10,14 +10,12 @@ use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use encoder::EncodeContext; +use index_builder::EntryBuilder; use schema::*; use rustc::hir; use rustc::ty; -use rustc_serialize::Encodable; - #[derive(RustcEncodable, RustcDecodable)] pub struct Ast<'tcx> { pub body: Lazy, @@ -26,7 +24,14 @@ pub struct Ast<'tcx> { pub rvalue_promotable_to_static: bool, } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl_stable_hash_for!(struct Ast<'tcx> { + body, + tables, + nested_bodies, + rvalue_promotable_to_static +}); + +impl<'a, 'b, 'tcx> EntryBuilder<'a, 'b, 'tcx> { pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy> { let body = self.tcx.hir.body(body_id); let lazy_body = self.lazy(body); @@ -34,15 +39,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tables = self.tcx.body_tables(body_id); let lazy_tables = self.lazy(tables); - let nested_pos = self.position(); - let nested_count = { - let mut visitor = NestedBodyEncodingVisitor { - ecx: self, - count: 0, - }; - visitor.visit_body(body); - visitor.count + let mut visitor = NestedBodyCollector { + tcx: self.tcx, + bodies_found: Vec::new(), }; + visitor.visit_body(body); + let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found); let rvalue_promotable_to_static = self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id]; @@ -50,27 +52,25 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(&Ast { body: lazy_body, tables: lazy_tables, - nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count), + nested_bodies: lazy_nested_bodies, rvalue_promotable_to_static: rvalue_promotable_to_static }) } } -struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> { - ecx: &'a mut EncodeContext<'b, 'tcx>, - count: usize, +struct NestedBodyCollector<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + bodies_found: Vec<&'tcx hir::Body>, } -impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> { +impl<'a, 'tcx: 'a> Visitor<'tcx> for NestedBodyCollector<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } fn visit_nested_body(&mut self, body: hir::BodyId) { - let body = self.ecx.tcx.hir.body(body); - body.encode(self.ecx).unwrap(); - self.count += 1; - + let body = self.tcx.hir.body(body); + self.bodies_found.push(body); self.visit_body(body); } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 38d774992a55..a74ce3f65022 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -15,6 +15,7 @@ use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; +use rustc::ich; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; @@ -42,7 +43,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc::hir::intravisit; -use super::index_builder::{FromId, IndexBuilder, Untracked}; +use super::index_builder::{FromId, IndexBuilder, Untracked, EntryBuilder}; pub struct EncodeContext<'a, 'tcx: 'a> { opaque: opaque::Encoder<'a>, @@ -54,6 +55,8 @@ pub struct EncodeContext<'a, 'tcx: 'a> { lazy_state: LazyState, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, + + pub metadata_hashes: Vec<(DefIndex, ich::Fingerprint)>, } macro_rules! encoder_methods { @@ -172,7 +175,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn lazy_seq(&mut self, iter: I) -> LazySeq + pub fn lazy_seq(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: Encodable { @@ -184,7 +187,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) } - fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq + pub fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: 'b + Encodable { @@ -233,10 +236,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Ok(()) } +} +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { let tcx = self.tcx; - self.lazy_seq(tcx.item_variances(def_id).iter().cloned()) + self.lazy_seq_from_slice(&tcx.item_variances(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { @@ -305,7 +310,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ModData { reexports: match tcx.export_map.get(&id) { - Some(exports) if *vis == hir::Public => self.lazy_seq_ref(exports), + Some(exports) if *vis == hir::Public => { + self.lazy_seq_from_slice(exports.as_slice()) + } _ => LazySeq::empty(), }, }; @@ -339,14 +346,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, - EncodeContext::encode_field, + EntryBuilder::encode_field, (adt_def_id, Untracked((variant_index, field_index)))); } } } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { /// Encode data for the given field of the given variant of the /// given ADT. The indices of the variant/field are untracked: /// this is ok because we will have to lookup the adt-def by its @@ -907,7 +914,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let def = self.tcx.lookup_adt_def(def_id); for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, - EncodeContext::encode_enum_variant_info, + EntryBuilder::encode_enum_variant_info, (def_id, Untracked(i))); } } @@ -918,7 +925,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { if !struct_def.is_struct() { let ctor_def_id = self.tcx.hir.local_def_id(struct_def.id()); self.record(ctor_def_id, - EncodeContext::encode_struct_ctor, + EntryBuilder::encode_struct_ctor, (def_id, ctor_def_id)); } } @@ -928,14 +935,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemImpl(..) => { for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(trait_item_def_id, - EncodeContext::encode_info_for_impl_item, + EntryBuilder::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(item_def_id, - EncodeContext::encode_info_for_trait_item, + EntryBuilder::encode_info_for_trait_item, item_def_id); } } @@ -943,7 +950,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_foreign_item(&mut self, (def_id, nitem): (DefId, &hir::ForeignItem)) -> Entry<'tcx> { @@ -1002,7 +1009,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { match item.node { hir::ItemExternCrate(_) | hir::ItemUse(..) => (), // ignore these - _ => self.index.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)), + _ => self.index.record(def_id, EntryBuilder::encode_info_for_item, (def_id, item)), } self.index.encode_addl_info_for_item(item); } @@ -1010,7 +1017,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_foreign_item(self, ni); let def_id = self.index.tcx.hir.local_def_id(ni.id); self.index.record(def_id, - EncodeContext::encode_info_for_foreign_item, + EntryBuilder::encode_info_for_foreign_item, (def_id, ni)); } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { @@ -1023,7 +1030,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { } fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) { let def_id = self.index.tcx.hir.local_def_id(macro_def.id); - self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def); + self.index.record(def_id, EntryBuilder::encode_info_for_macro_def, macro_def); } } @@ -1032,14 +1039,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { for ty_param in &generics.ty_params { let def_id = self.tcx.hir.local_def_id(ty_param.id); let has_default = Untracked(ty_param.default.is_some()); - self.record(def_id, EncodeContext::encode_info_for_ty_param, (def_id, has_default)); + self.record(def_id, EntryBuilder::encode_info_for_ty_param, (def_id, has_default)); } } fn encode_info_for_ty(&mut self, ty: &hir::Ty) { if let hir::TyImplTrait(_) = ty.node { let def_id = self.tcx.hir.local_def_id(ty.id); - self.record(def_id, EncodeContext::encode_info_for_anon_ty, def_id); + self.record(def_id, EntryBuilder::encode_info_for_anon_ty, def_id); } } @@ -1047,14 +1054,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { match expr.node { hir::ExprClosure(..) => { let def_id = self.tcx.hir.local_def_id(expr.id); - self.record(def_id, EncodeContext::encode_info_for_closure, def_id); + self.record(def_id, EntryBuilder::encode_info_for_closure, def_id); } _ => {} } } } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty_param(&mut self, (def_id, Untracked(has_default)): (DefId, Untracked)) -> Entry<'tcx> { @@ -1133,11 +1140,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { + self.lazy_seq_from_slice(attrs) + } +} + +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_items(&mut self) -> Index { let krate = self.tcx.hir.krate(); let mut index = IndexBuilder::new(self); index.record(DefId::local(CRATE_DEF_INDEX), - EncodeContext::encode_info_for_mod, + EntryBuilder::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index }; krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); @@ -1147,10 +1160,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { visitor.index.into_items() } - fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { - self.lazy_seq_ref(attrs) - } - fn encode_crate_deps(&mut self) -> LazySeq { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { // Pull the cnums and name,vers,hash out of cstore @@ -1298,7 +1307,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None => LazySeq::empty(), } } +} +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_crate_root(&mut self) -> Lazy { let mut i = self.position(); let crate_deps = self.encode_crate_deps(); @@ -1448,6 +1459,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), + metadata_hashes: Vec::new(), }; // Encode the rustc version string in a predictable location. diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index a811f72bc956..389ada12da81 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -59,14 +59,19 @@ use encoder::EncodeContext; use index::Index; use schema::*; -use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::ich::{StableHashingContext, Fingerprint}; use rustc::ty::TyCtxt; use syntax::ast; use std::ops::{Deref, DerefMut}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; +use rustc_serialize::Encodable; + +use rustc::dep_graph::DepNode; + /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { @@ -112,16 +117,29 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// holds, and that it is therefore not gaining "secret" access to /// bits of HIR or other state that would not be trackd by the /// content system. - pub fn record(&mut self, - id: DefId, - op: fn(&mut EncodeContext<'b, 'tcx>, DATA) -> Entry<'tcx>, - data: DATA) + pub fn record<'x, DATA>(&'x mut self, + id: DefId, + op: fn(&mut EntryBuilder<'x, 'b, 'tcx>, DATA) -> Entry<'tcx>, + data: DATA) where DATA: DepGraphRead { let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); data.read(self.tcx); - let entry = op(&mut self.ecx, data); - self.items.record(id, self.ecx.lazy(&entry)); + + assert!(id.is_local()); + let tcx: TyCtxt<'b, 'tcx, 'tcx> = self.ecx.tcx; + let ecx: &'x mut EncodeContext<'b, 'tcx> = &mut *self.ecx; + let mut entry_builder = EntryBuilder { + tcx: tcx, + ecx: ecx, + hasher: StableHasher::new(), + hcx: StableHashingContext::new(tcx), + }; + + let entry = op(&mut entry_builder, data); + let entry = entry_builder.ecx.lazy(&entry); + entry_builder.finish(id); + self.items.record(id, entry); } pub fn into_items(self) -> Index { @@ -223,3 +241,48 @@ impl DepGraphRead for FromId { tcx.hir.read(self.0); } } + +pub struct EntryBuilder<'a, 'b: 'a, 'tcx: 'b> { + pub tcx: TyCtxt<'b, 'tcx, 'tcx>, + ecx: &'a mut EncodeContext<'b, 'tcx>, + hasher: StableHasher, + hcx: StableHashingContext<'b, 'tcx>, +} + +impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { + + pub fn finish(self, def_id: DefId) { + let hash = self.hasher.finish(); + self.ecx.metadata_hashes.push((def_id.index, hash)); + } + + pub fn lazy(&mut self, value: &T) -> Lazy + where T: Encodable + HashStable> + { + value.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy(value) + } + + pub fn lazy_seq(&mut self, iter: I) -> LazySeq + where I: IntoIterator, + T: Encodable + HashStable> + { + let items: Vec = iter.into_iter().collect(); + items.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq(items) + } + + pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq + where T: Encodable + HashStable> + { + slice.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq_ref(slice.iter()) + } + + pub fn lazy_seq_ref_from_slice(&mut self, slice: &[&T]) -> LazySeq + where T: Encodable + HashStable> + { + slice.hash_stable(&mut self.hcx, &mut self.hasher); + self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) + } +} diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2fbdb8c0de67..b9e142ac6507 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -27,6 +27,7 @@ #![feature(rustc_private)] #![feature(specialization)] #![feature(staged_api)] +#![feature(discriminant_value)] #[macro_use] extern crate log; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index abb482a50ebc..6ffa31c07270 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -28,6 +28,9 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable, + StableHasherResult}; + pub fn rustc_version() -> String { format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) @@ -100,6 +103,15 @@ impl Clone for Lazy { impl serialize::UseSpecializedEncodable for Lazy {} impl serialize::UseSpecializedDecodable for Lazy {} +impl HashStable for Lazy { + fn hash_stable(&self, + _: &mut CTX, + _: &mut StableHasher) { + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. + } +} + /// A sequence of type T referred to by its absolute position /// in the metadata and length, and which can be decoded lazily. /// The sequence is a single node for the purposes of `Lazy`. @@ -148,6 +160,15 @@ impl Clone for LazySeq { impl serialize::UseSpecializedEncodable for LazySeq {} impl serialize::UseSpecializedDecodable for LazySeq {} +impl HashStable for LazySeq { + fn hash_stable(&self, + _: &mut CTX, + _: &mut StableHasher) { + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. + } +} + /// Encoding / decoding state for `Lazy` and `LazySeq`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum LazyState { @@ -251,17 +272,23 @@ pub struct ModData { pub reexports: LazySeq, } +impl_stable_hash_for!(struct ModData { reexports }); + #[derive(RustcEncodable, RustcDecodable)] pub struct MacroDef { pub body: String, } +impl_stable_hash_for!(struct MacroDef { body }); + #[derive(RustcEncodable, RustcDecodable)] pub struct FnData { pub constness: hir::Constness, pub arg_names: LazySeq, } +impl_stable_hash_for!(struct FnData { constness, arg_names }); + #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData<'tcx> { pub ctor_kind: CtorKind, @@ -273,6 +300,13 @@ pub struct VariantData<'tcx> { pub struct_ctor: Option, } +impl_stable_hash_for!(struct VariantData<'tcx> { + ctor_kind, + discr, + evaluated_discr, + struct_ctor +}); + #[derive(RustcEncodable, RustcDecodable)] pub struct TraitData<'tcx> { pub unsafety: hir::Unsafety, @@ -281,6 +315,13 @@ pub struct TraitData<'tcx> { pub super_predicates: Lazy>, } +impl_stable_hash_for!(struct TraitData<'tcx> { + unsafety, + paren_sugar, + has_default_impl, + super_predicates +}); + #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, @@ -291,6 +332,14 @@ pub struct ImplData<'tcx> { pub trait_ref: Option>>, } +impl_stable_hash_for!(struct ImplData<'tcx> { + polarity, + parent_impl, + coerce_unsized_info, + trait_ref +}); + + /// Describes whether the container of an associated item /// is a trait or an impl and whether, in a trait, it has /// a default, or an in impl, whether it's marked "default". @@ -302,6 +351,13 @@ pub enum AssociatedContainer { ImplFinal, } +impl_stable_hash_for!(enum ::schema::AssociatedContainer { + TraitRequired, + TraitWithDefault, + ImplDefault, + ImplFinal +}); + impl AssociatedContainer { pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer { match *self { @@ -335,9 +391,11 @@ pub struct MethodData { pub container: AssociatedContainer, pub has_self: bool, } +impl_stable_hash_for!(struct MethodData { fn_data, container, has_self }); #[derive(RustcEncodable, RustcDecodable)] pub struct ClosureData<'tcx> { pub kind: ty::ClosureKind, pub ty: Lazy>, } +impl_stable_hash_for!(struct ClosureData<'tcx> { kind, ty }); From ca2dce9b48e65ae2b286fbd10e459536ecccb2d8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 5 Apr 2017 23:39:02 +0200 Subject: [PATCH 447/905] ICH: Replace old, transitive metadata hashing with direct hashing approach. Instead of collecting all potential inputs to some metadata entry and hashing those, we directly hash the values we are storing in metadata. This is more accurate and doesn't suffer from quadratic blow-up when many entries have the same dependencies. --- src/librustc/ich/impls_ty.rs | 32 ++--- src/librustc/middle/cstore.rs | 23 +++- src/librustc/ty/mod.rs | 17 +++ src/librustc/ty/util.rs | 30 +++-- src/librustc_data_structures/blake2b.rs | 34 ++++- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/stable_hasher.rs | 7 +- src/librustc_driver/driver.rs | 1 + src/librustc_incremental/persist/data.rs | 14 +- .../persist/dirty_clean.rs | 64 ++++++--- src/librustc_incremental/persist/preds/mod.rs | 28 +++- src/librustc_incremental/persist/save.rs | 81 ++---------- src/librustc_metadata/cstore_impl.rs | 8 +- src/librustc_metadata/encoder.rs | 48 +++++-- src/librustc_metadata/index_builder.rs | 93 +++++++++++--- src/librustc_metadata/schema.rs | 90 ++++++++++++- src/librustc_trans/back/link.rs | 5 +- src/librustc_trans/base.rs | 11 +- src/librustc_trans/lib.rs | 2 +- src/test/incremental/hashes/enum_defs.rs | 92 ++++++++++--- src/test/incremental/hashes/extern_mods.rs | 40 ++++-- .../incremental/hashes/function_interfaces.rs | 10 +- src/test/incremental/hashes/inherent_impls.rs | 20 ++- src/test/incremental/hashes/struct_defs.rs | 90 ++++++++++--- src/test/incremental/hashes/trait_defs.rs | 121 +++++++++++------- src/test/incremental/hashes/trait_impls.rs | 58 +++------ .../unchecked_dirty_clean_metadata.rs | 10 -- 27 files changed, 689 insertions(+), 341 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index c682f6b8668c..46d1e7ef0c7c 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -16,24 +16,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; use std::mem; +use syntax_pos::symbol::InternedString; use ty; -impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, - hasher: &mut StableHasher) { - let ty::TyS { - ref sty, - - // The other fields just provide fast access to information that is - // also contained in `sty`, so no need to hash them. - .. - } = *self; - - sty.hash_stable(hcx, hasher); - } -} - impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice @@ -288,9 +273,14 @@ for ::middle::const_val::ConstVal<'tcx> { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } - ConstVal::Struct(ref _name_value_map) => { - // BTreeMap>), - panic!("Ordering still unstable") + ConstVal::Struct(ref name_value_map) => { + let mut values: Vec<(InternedString, &ConstVal)> = + name_value_map.iter() + .map(|(name, val)| (name.as_str(), val)) + .collect(); + + values.sort_unstable_by_key(|&(ref name, _)| name.clone()); + values.hash_stable(hcx, hasher); } ConstVal::Tuple(ref value) => { value.hash_stable(hcx, hasher); @@ -632,6 +622,8 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ref fru_field_types, ref cast_kinds, + + // FIXME(#41184): This is still ignored at the moment. lints: _, ref used_trait_imports, tainted_by_errors, @@ -672,7 +664,7 @@ impl<'a, 'tcx> HashStable> for ty::TypeckTables<' ich::hash_stable_nodemap(hcx, hasher, cast_kinds); ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { - hcx.tcx().def_path_hash(*def_id) + hcx.def_path_hash(*def_id) }); tainted_by_errors.hash_stable(hcx, hasher); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 694321812836..81cf24e58dda 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -27,6 +27,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData}; use hir::svh::Svh; +use ich; use middle::lang_items; use ty::{self, TyCtxt}; use session::Session; @@ -161,6 +162,20 @@ pub struct ExternCrate { pub path_len: usize, } +pub struct EncodedMetadata { + pub raw_data: Vec, + pub hashes: Vec, +} + +/// The hash for some metadata that (when saving) will be exported +/// from this crate, or which (when importing) was exported by an +/// upstream crate. +#[derive(Debug, RustcEncodable, RustcDecodable, Copy, Clone)] +pub struct EncodedMetadataHash { + pub def_index: DefIndex, + pub hash: ich::Fingerprint, +} + /// A store of Rust crates, through with their metadata /// can be accessed. pub trait CrateStore { @@ -258,7 +273,8 @@ pub trait CrateStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec; + reachable: &NodeSet) + -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; } @@ -417,7 +433,10 @@ impl CrateStore for DummyCrateStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec { vec![] } + reachable: &NodeSet) + -> EncodedMetadata { + bug!("encode_metadata") + } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a2c356c20db0..23f35d3bdd79 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -452,6 +452,23 @@ impl<'tcx> Hash for TyS<'tcx> { } } +impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TyS { + ref sty, + + // The other fields just provide fast access to information that is + // also contained in `sty`, so no need to hash them. + flags: _, + region_depth: _, + } = *self; + + sty.hash_stable(hcx, hasher); + } +} + pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd8191303a9a..c650ffe30276 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,7 +13,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use infer::InferCtxt; -// use hir::map as hir_map; +use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; @@ -25,8 +25,8 @@ use util::nodemap::FxHashMap; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult}; - +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use std::cell::RefCell; use std::cmp; use std::hash::Hash; @@ -187,6 +187,22 @@ impl<'tcx> ParameterEnvironment<'tcx> { } } +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { + let mut hasher = StableHasher::new(); + let mut hcx = StableHashingContext::new(self); + + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ty.hash_stable(hcx, &mut hasher); + }); + }); + hasher.finish() + } +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { @@ -339,14 +355,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect() } - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { - let mut hasher = TypeIdHasher::new(self); - hasher.visit_ty(ty); - hasher.finish() - } - /// Calculate the destructor of a given type. pub fn calculate_dtor( self, diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index 9d97a83f693c..bdef9fefd41e 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -29,16 +29,23 @@ pub struct Blake2bCtx { t: [u64; 2], c: usize, outlen: u16, - finalized: bool + finalized: bool, + + #[cfg(debug_assertions)] + fnv_hash: u64, } +#[cfg(debug_assertions)] impl ::std::fmt::Debug for Blake2bCtx { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - try!(write!(fmt, "hash: ")); - for v in &self.h { - try!(write!(fmt, "{:x}", v)); - } - Ok(()) + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "{:x}", self.fnv_hash) + } +} + +#[cfg(not(debug_assertions))] +impl ::std::fmt::Debug for Blake2bCtx { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "Enable debug_assertions() for more info.") } } @@ -157,6 +164,9 @@ fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx { c: 0, outlen: outlen as u16, finalized: false, + + #[cfg(debug_assertions)] + fnv_hash: 0xcbf29ce484222325, }; ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64); @@ -194,6 +204,16 @@ fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) { checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy); ctx.c += bytes_to_copy; } + + #[cfg(debug_assertions)] + { + // compute additional FNV hash for simpler to read debug output + const MAGIC_PRIME: u64 = 0x00000100000001b3; + + for &byte in data { + ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME); + } + } } fn blake2b_final(ctx: &mut Blake2bCtx) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 72c533a74618..00c46d992bfd 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -40,6 +40,7 @@ #![feature(discriminant_value)] #![feature(specialization)] #![feature(manually_drop)] +#![feature(struct_field_attributes)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index dc412a0763ef..95f063976d49 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -40,13 +40,18 @@ fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize { /// This hasher currently always uses the stable Blake2b algorithm /// and allows for variable output lengths through its type /// parameter. -#[derive(Debug)] pub struct StableHasher { state: Blake2bHasher, bytes_hashed: u64, width: PhantomData, } +impl ::std::fmt::Debug for StableHasher { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{:?}", self.state) + } +} + pub trait StableHasherResult: Sized { fn finish(hasher: StableHasher) -> Self; } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bdb05d06b0b1..eeacf79514a8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1083,6 +1083,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "serialize dep graph", || rustc_incremental::save_dep_graph(tcx, &incremental_hashes_map, + &translation.metadata.hashes, translation.link.crate_hash)); translation } diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index d90090739565..8a1af5dd08d7 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -13,6 +13,7 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; use rustc::ich::Fingerprint; +use rustc::middle::cstore::EncodedMetadataHash; use std::sync::Arc; use rustc_data_structures::fx::FxHashMap; @@ -98,7 +99,7 @@ pub struct SerializedMetadataHashes { /// where `X` refers to some item in this crate. That `X` will be /// a `DefPathIndex` that gets retracted to the current `DefId` /// (matching the one found in this structure). - pub hashes: Vec, + pub hashes: Vec, /// For each DefIndex (as it occurs in SerializedMetadataHash), this /// map stores the DefPathIndex (as it occurs in DefIdDirectory), so @@ -112,14 +113,3 @@ pub struct SerializedMetadataHashes { /// the DefIndex. pub index_map: FxHashMap } - -/// The hash for some metadata that (when saving) will be exported -/// from this crate, or which (when importing) was exported by an -/// upstream crate. -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct SerializedMetadataHash { - pub def_index: DefIndex, - - /// the hash itself, computed by `calculate_item_hash` - pub hash: Fingerprint, -} diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index d931f64d579e..af5c1f05bd1f 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -215,9 +215,11 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } } -pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &FxHashMap, - current_metadata_hashes: &FxHashMap) { +pub fn check_dirty_clean_metadata<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + prev_metadata_hashes: &FxHashMap, + current_metadata_hashes: &FxHashMap) +{ if !tcx.sess.opts.debugging_opts.query_dep_graph { return; } @@ -230,7 +232,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, current_metadata_hashes: current_metadata_hashes, checked_attrs: FxHashSet(), }; - krate.visit_all_item_likes(&mut dirty_clean_visitor); + intravisit::walk_crate(&mut dirty_clean_visitor, krate); let mut all_attrs = FindAllAttrs { tcx: tcx, @@ -246,30 +248,58 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); } -pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { +pub struct DirtyCleanMetadataVisitor<'a, 'tcx: 'a, 'm> { tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_metadata_hashes: &'m FxHashMap, current_metadata_hashes: &'m FxHashMap, checked_attrs: FxHashSet, } -impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { +impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { + + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::All(&self.tcx.hir) + } + fn visit_item(&mut self, item: &'tcx hir::Item) { self.check_item(item.id, item.span); + intravisit::walk_item(self, item); + } - if let hir::ItemEnum(ref def, _) = item.node { - for v in &def.variants { - self.check_item(v.node.data.id(), v.span); - } + fn visit_variant_data(&mut self, + variant_data: &'tcx hir::VariantData, + _: ast::Name, + _: &'tcx hir::Generics, + _parent_id: ast::NodeId, + span: Span) { + if self.tcx.hir.find(variant_data.id()).is_some() { + // VariantData that represent structs or tuples don't have a + // separate entry in the HIR map and checking them would error, + // so only check if this is an enum or union variant. + self.check_item(variant_data.id(), span); } + + intravisit::walk_struct_def(self, variant_data); } - fn visit_trait_item(&mut self, item: &hir::TraitItem) { + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { self.check_item(item.id, item.span); + intravisit::walk_trait_item(self, item); } - fn visit_impl_item(&mut self, item: &hir::ImplItem) { + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { self.check_item(item.id, item.span); + intravisit::walk_impl_item(self, item); + } + + fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) { + self.check_item(i.id, i.span); + intravisit::walk_foreign_item(self, i); + } + + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { + self.check_item(s.id, s.span); + intravisit::walk_struct_field(self, s); } } @@ -281,13 +311,15 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { for attr in self.tcx.get_attrs(def_id).iter() { if attr.check_name(ATTR_DIRTY_METADATA) { if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - self.assert_state(false, def_id, item_span); + if self.checked_attrs.insert(attr.id) { + self.assert_state(false, def_id, item_span); + } } } else if attr.check_name(ATTR_CLEAN_METADATA) { if check_config(self.tcx, attr) { - self.checked_attrs.insert(attr.id); - self.assert_state(true, def_id, item_span); + if self.checked_attrs.insert(attr.id) { + self.assert_state(true, def_id, item_span); + } } } } diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs index fe8cf72996e1..e769641a4cad 100644 --- a/src/librustc_incremental/persist/preds/mod.rs +++ b/src/librustc_incremental/persist/preds/mod.rs @@ -44,16 +44,18 @@ impl<'q> Predecessors<'q> { pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self { let tcx = hcx.tcx; - let collect_for_metadata = tcx.sess.opts.debugging_opts.incremental_cc || - tcx.sess.opts.debugging_opts.query_dep_graph; - // Find the set of "start nodes". These are nodes that we will // possibly query later. let is_output = |node: &DepNode| -> bool { match *node { DepNode::WorkProduct(_) => true, - DepNode::MetaData(ref def_id) => collect_for_metadata && def_id.is_local(), - + DepNode::MetaData(ref def_id) => { + // We do *not* create dep-nodes for the current crate's + // metadata anymore, just for metadata that we import/read + // from other crates. + debug_assert!(!def_id.is_local()); + false + } // if -Z query-dep-graph is passed, save more extended data // to enable better unit testing DepNode::TypeckTables(_) | @@ -75,6 +77,22 @@ impl<'q> Predecessors<'q> { .or_insert_with(|| hcx.hash(input).unwrap()); } + if tcx.sess.opts.debugging_opts.query_dep_graph { + // Not all inputs might have been reachable from an output node, + // but we still want their hash for our unit tests. + let hir_nodes = query.graph.all_nodes().iter().filter_map(|node| { + match node.data { + DepNode::Hir(_) => Some(&node.data), + _ => None, + } + }); + + for node in hir_nodes { + hashes.entry(node) + .or_insert_with(|| hcx.hash(node).unwrap()); + } + } + let bootstrap_outputs: Vec<&'q DepNode> = (0 .. graph.len_nodes()) .map(NodeIndex) diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 1591503865e8..1864009fbdf2 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -12,13 +12,12 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::ich::Fingerprint; +use rustc::middle::cstore::EncodedMetadataHash; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::{NodeIndex, INCOMING}; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::Encoder; -use std::hash::Hash; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; use std::path::PathBuf; @@ -32,10 +31,10 @@ use super::fs::*; use super::dirty_clean; use super::file_format; use super::work_product; -use calculate_svh::IchHasher; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, + metadata_hashes: &[EncodedMetadataHash], svh: Svh) { debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); @@ -56,16 +55,16 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let preds = Predecessors::new(&query, &mut hcx); let mut current_metadata_hashes = FxHashMap(); + // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, + // since metadata-encoding might add new entries to the + // DefIdDirectory (which is saved in the dep-graph file). if sess.opts.debugging_opts.incremental_cc || sess.opts.debugging_opts.query_dep_graph { - // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, - // since metadata-encoding might add new entries to the - // DefIdDirectory (which is saved in the dep-graph file). save_in(sess, metadata_hash_export_path(sess), |e| encode_metadata_hashes(tcx, svh, - &preds, + metadata_hashes, &mut builder, &mut current_metadata_hashes, e)); @@ -241,80 +240,16 @@ pub fn encode_dep_graph(preds: &Predecessors, pub fn encode_metadata_hashes(tcx: TyCtxt, svh: Svh, - preds: &Predecessors, + metadata_hashes: &[EncodedMetadataHash], builder: &mut DefIdDirectoryBuilder, current_metadata_hashes: &mut FxHashMap, encoder: &mut Encoder) -> io::Result<()> { - // For each `MetaData(X)` node where `X` is local, accumulate a - // hash. These are the metadata items we export. Downstream - // crates will want to see a hash that tells them whether we might - // have changed the metadata for a given item since they last - // compiled. - // - // (I initially wrote this with an iterator, but it seemed harder to read.) let mut serialized_hashes = SerializedMetadataHashes { - hashes: vec![], + hashes: metadata_hashes.to_vec(), index_map: FxHashMap() }; - for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() { - let index = NodeIndex(index); - let def_id = match *target.data { - DepNode::MetaData(def_id) if def_id.is_local() => def_id, - _ => continue, - }; - - // To create the hash for each item `X`, we don't hash the raw - // bytes of the metadata (though in principle we - // could). Instead, we walk the predecessors of `MetaData(X)` - // from the dep-graph. This corresponds to all the inputs that - // were read to construct the metadata. To create the hash for - // the metadata, we hash (the hash of) all of those inputs. - debug!("save: computing metadata hash for {:?}", def_id); - - // Create a vector containing a pair of (source-id, hash). - // The source-id is stored as a `DepNode`, where the u64 - // is the det. hash of the def-path. This is convenient - // because we can sort this to get a stable ordering across - // compilations, even if the def-ids themselves have changed. - let mut hashes: Vec<(DepNode, Fingerprint)> = - preds.reduced_graph - .depth_traverse(index, INCOMING) - .map(|index| preds.reduced_graph.node_data(index)) - .filter(|dep_node| HashContext::is_hashable(dep_node)) - .map(|dep_node| { - let hash_dep_node = dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))) - .unwrap(); - let hash = preds.hashes[dep_node]; - (hash_dep_node, hash) - }) - .collect(); - - hashes.sort(); - let mut state = IchHasher::new(); - hashes.hash(&mut state); - let hash = state.finish(); - - debug!("save: metadata hash for {:?} is {}", def_id, hash); - - if tcx.sess.opts.debugging_opts.incremental_dump_hash { - println!("metadata hash for {:?} is {}", def_id, hash); - for pred_index in preds.reduced_graph.depth_traverse(index, INCOMING) { - let dep_node = preds.reduced_graph.node_data(pred_index); - if HashContext::is_hashable(&dep_node) { - println!("metadata hash for {:?} depends on {:?} with hash {}", - def_id, dep_node, preds.hashes[dep_node]); - } - } - } - - serialized_hashes.hashes.push(SerializedMetadataHash { - def_index: def_id.index, - hash: hash, - }); - } - if tcx.sess.opts.debugging_opts.query_dep_graph { for serialized_hash in &serialized_hashes.hashes { let def_id = DefId::local(serialized_hash.def_index); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 37984e4c3718..3239dfb937b5 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -14,8 +14,9 @@ use locator; use schema; use rustc::dep_graph::DepTrackingMapConfig; -use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate}; -use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; +use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, + ExternCrate, NativeLibrary, LinkMeta, + LinkagePreference, LoadedMacro, EncodedMetadata}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; use rustc::session::Session; @@ -498,7 +499,8 @@ impl CrateStore for cstore::CStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec + reachable: &NodeSet) + -> EncodedMetadata { encoder::encode_metadata(tcx, self, link_meta, reachable) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a74ce3f65022..ffe68094c6af 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -12,10 +12,10 @@ use cstore; use index::Index; use schema::*; -use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary}; +use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, + EncodedMetadata, EncodedMetadataHash}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::hir::map::definitions::DefPathTable; -use rustc::ich; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; @@ -56,7 +56,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, - pub metadata_hashes: Vec<(DefIndex, ich::Fingerprint)>, + pub metadata_hashes: Vec, } macro_rules! encoder_methods { @@ -240,13 +240,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { + debug!("EntryBuilder::encode_item_variances({:?})", def_id); let tcx = self.tcx; self.lazy_seq_from_slice(&tcx.item_variances(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(&tcx.item_type(def_id)) + let ty = tcx.item_type(def_id); + debug!("EntryBuilder::encode_item_type({:?}) => {:?}", def_id, ty); + self.lazy(&ty) } /// Encode data for the given variant of the given ADT. The @@ -261,6 +264,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let def = tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; let def_id = variant.did; + debug!("EntryBuilder::encode_enum_variant_info({:?})", def_id); let data = VariantData { ctor_kind: variant.ctor_kind, @@ -307,6 +311,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { -> Entry<'tcx> { let tcx = self.tcx; let def_id = tcx.hir.local_def_id(id); + debug!("EntryBuilder::encode_info_for_mod({:?})", def_id); let data = ModData { reexports: match tcx.export_map.get(&id) { @@ -370,6 +375,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let field = &variant.fields[field_index]; let def_id = field.did; + debug!("EntryBuilder::encode_field({:?})", def_id); + let variant_id = tcx.hir.as_local_node_id(variant.did).unwrap(); let variant_data = tcx.hir.expect_variant_data(variant_id); @@ -394,6 +401,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { + debug!("EntryBuilder::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; let variant = tcx.lookup_adt_def(adt_def_id).struct_variant(); @@ -436,16 +444,19 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_generics(&mut self, def_id: DefId) -> Lazy { + debug!("EntryBuilder::encode_generics({:?})", def_id); let tcx = self.tcx; self.lazy(tcx.item_generics(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { + debug!("EntryBuilder::encode_predicates({:?})", def_id); let tcx = self.tcx; self.lazy(&tcx.item_predicates(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_trait_item({:?})", def_id); let tcx = self.tcx; let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -528,6 +539,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_impl_item({:?})", def_id); let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.hir.expect_impl_item(node_id); let impl_item = self.tcx.associated_item(def_id); @@ -614,11 +626,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_mir(&mut self, def_id: DefId) -> Option>> { + debug!("EntryBuilder::encode_mir({:?})", def_id); self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow())) } // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq { + debug!("EntryBuilder::encode_inherent_implementations({:?})", def_id); match self.tcx.maps.inherent_impls.borrow().get(&def_id) { None => LazySeq::empty(), Some(implementations) => { @@ -631,18 +645,19 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_stability(&mut self, def_id: DefId) -> Option> { + debug!("EntryBuilder::encode_stability({:?})", def_id); self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab)) } fn encode_deprecation(&mut self, def_id: DefId) -> Option> { + debug!("EntryBuilder::encode_deprecation({:?})", def_id); self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) } fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> { let tcx = self.tcx; - debug!("encoding info for item at {}", - tcx.sess.codemap().span_to_string(item.span)); + debug!("EntryBuilder::encode_info_for_item({:?})", def_id); let kind = match item.node { hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic, @@ -956,7 +971,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { -> Entry<'tcx> { let tcx = self.tcx; - debug!("writing foreign item {}", tcx.node_path_str(nitem.id)); + debug!("EntryBuilder::encode_info_for_foreign_item({:?})", def_id); let kind = match nitem.node { hir::ForeignItemFn(_, ref names, _) => { @@ -1065,6 +1080,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty_param(&mut self, (def_id, Untracked(has_default)): (DefId, Untracked)) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_ty_param({:?})", def_id); let tcx = self.tcx; Entry { kind: EntryKind::Type, @@ -1091,6 +1107,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_anon_ty({:?})", def_id); let tcx = self.tcx; Entry { kind: EntryKind::Type, @@ -1113,6 +1130,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_closure({:?})", def_id); let tcx = self.tcx; let data = ClosureData { @@ -1141,6 +1159,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { + // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because + // we really on the HashStable specialization for [Attribute] + // to properly filter things out. self.lazy_seq_from_slice(attrs) } } @@ -1442,14 +1463,15 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, link_meta: &LinkMeta, exported_symbols: &NodeSet) - -> Vec { + -> EncodedMetadata +{ let mut cursor = Cursor::new(vec![]); cursor.write_all(METADATA_HEADER).unwrap(); // Will be filed with the root position after encoding everything. cursor.write_all(&[0, 0, 0, 0]).unwrap(); - let root = { + let (root, metadata_hashes) = { let mut ecx = EncodeContext { opaque: opaque::Encoder::new(&mut cursor), tcx: tcx, @@ -1467,7 +1489,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Encode all the entries and extra information in the crate, // culminating in the `CrateRoot` which points to all of it. - ecx.encode_crate_root() + let root = ecx.encode_crate_root(); + (root, ecx.metadata_hashes) }; let mut result = cursor.into_inner(); @@ -1479,7 +1502,10 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result[header + 2] = (pos >> 8) as u8; result[header + 3] = (pos >> 0) as u8; - result + EncodedMetadata { + raw_data: result, + hashes: metadata_hashes, + } } pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions { diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 389ada12da81..01f948866b85 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -62,16 +62,16 @@ use schema::*; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ich::{StableHashingContext, Fingerprint}; +use rustc::middle::cstore::EncodedMetadataHash; use rustc::ty::TyCtxt; use syntax::ast; use std::ops::{Deref, DerefMut}; +use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_serialize::Encodable; -use rustc::dep_graph::DepNode; - /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { @@ -123,20 +123,36 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { data: DATA) where DATA: DepGraphRead { - let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); - data.read(self.tcx); - assert!(id.is_local()); let tcx: TyCtxt<'b, 'tcx, 'tcx> = self.ecx.tcx; + + // We don't track this since we are explicitly computing the incr. comp. + // hashes anyway. In theory we could do some tracking here and use it to + // avoid rehashing things (and instead cache the hashes) but it's + // unclear whether that would be a win since hashing is cheap enough. + let _task = tcx.dep_graph.in_ignore(); + + let compute_ich = (tcx.sess.opts.debugging_opts.query_dep_graph || + tcx.sess.opts.debugging_opts.incremental_cc) && + tcx.sess.opts.build_dep_graph(); + let ecx: &'x mut EncodeContext<'b, 'tcx> = &mut *self.ecx; let mut entry_builder = EntryBuilder { tcx: tcx, ecx: ecx, - hasher: StableHasher::new(), - hcx: StableHashingContext::new(tcx), + hcx: if compute_ich { + Some((StableHashingContext::new(tcx), StableHasher::new())) + } else { + None + } }; let entry = op(&mut entry_builder, data); + + if let Some((ref mut hcx, ref mut hasher)) = entry_builder.hcx { + entry.hash_stable(hcx, hasher); + } + let entry = entry_builder.ecx.lazy(&entry); entry_builder.finish(id); self.items.record(id, entry); @@ -245,21 +261,28 @@ impl DepGraphRead for FromId { pub struct EntryBuilder<'a, 'b: 'a, 'tcx: 'b> { pub tcx: TyCtxt<'b, 'tcx, 'tcx>, ecx: &'a mut EncodeContext<'b, 'tcx>, - hasher: StableHasher, - hcx: StableHashingContext<'b, 'tcx>, + hcx: Option<(StableHashingContext<'b, 'tcx>, StableHasher)>, } impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { pub fn finish(self, def_id: DefId) { - let hash = self.hasher.finish(); - self.ecx.metadata_hashes.push((def_id.index, hash)); + if let Some((_, hasher)) = self.hcx { + let hash = hasher.finish(); + self.ecx.metadata_hashes.push(EncodedMetadataHash { + def_index: def_id.index, + hash: hash, + }); + } } pub fn lazy(&mut self, value: &T) -> Lazy where T: Encodable + HashStable> { - value.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + value.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy(value) } @@ -267,22 +290,58 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { where I: IntoIterator, T: Encodable + HashStable> { - let items: Vec = iter.into_iter().collect(); - items.hash_stable(&mut self.hcx, &mut self.hasher); - self.ecx.lazy_seq(items) + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + let iter = iter.into_iter(); + let (lower_bound, upper_bound) = iter.size_hint(); + + if upper_bound == Some(lower_bound) { + lower_bound.hash_stable(hcx, hasher); + let mut num_items_hashed = 0; + let ret = self.ecx.lazy_seq(iter.inspect(|item| { + item.hash_stable(hcx, hasher); + num_items_hashed += 1; + })); + + // Sometimes items in a sequence are filtered out without being + // hashed (e.g. for &[ast::Attribute]) and this code path cannot + // handle that correctly, so we want to make sure we didn't hit + // it by accident. + if lower_bound != num_items_hashed { + bug!("Hashed a different number of items ({}) than expected ({})", + num_items_hashed, + lower_bound); + } + debug!("metadata-hash: {:?}", hasher); + ret + } else { + // Collect into a vec so we know the length of the sequence + let items: AccumulateVec<[T; 32]> = iter.collect(); + items.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + self.ecx.lazy_seq(items) + } + } else { + self.ecx.lazy_seq(iter) + } } pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq where T: Encodable + HashStable> { - slice.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + slice.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy_seq_ref(slice.iter()) } pub fn lazy_seq_ref_from_slice(&mut self, slice: &[&T]) -> LazySeq where T: Encodable + HashStable> { - slice.hash_stable(&mut self.hcx, &mut self.hasher); + if let Some((ref mut hcx, ref mut hasher)) = self.hcx { + slice.hash_stable(hcx, hasher); + debug!("metadata-hash: {:?}", hasher); + } self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 6ffa31c07270..53d6a9ec10df 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -14,6 +14,7 @@ use index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::ich::StableHashingContext; use rustc::middle::const_val::ConstVal; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; @@ -27,6 +28,7 @@ use syntax::symbol::Symbol; use syntax_pos::{self, Span}; use std::marker::PhantomData; +use std::mem; use rustc_data_structures::stable_hasher::{StableHasher, HashStable, StableHasherResult}; @@ -107,8 +109,8 @@ impl HashStable for Lazy { fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. } } @@ -164,8 +166,8 @@ impl HashStable for LazySeq { fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { - // There's nothing to do. Whatever got encoded within this Lazy<> - // wrapper has already been hashed. + // There's nothing to do. Whatever got encoded within this Lazy<> + // wrapper has already been hashed. } } @@ -240,6 +242,23 @@ pub struct Entry<'tcx> { pub mir: Option>>, } +impl_stable_hash_for!(struct Entry<'tcx> { + kind, + visibility, + span, + attributes, + children, + stability, + deprecation, + ty, + inherent_impls, + variances, + generics, + predicates, + ast, + mir +}); + #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub enum EntryKind<'tcx> { Const(u8), @@ -267,6 +286,69 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer, u8), } +impl<'a, 'tcx> HashStable> for EntryKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + EntryKind::ImmStatic | + EntryKind::MutStatic | + EntryKind::ForeignImmStatic | + EntryKind::ForeignMutStatic | + EntryKind::ForeignMod | + EntryKind::Field | + EntryKind::Type => { + // Nothing else to hash here. + } + EntryKind::Const(qualif) => { + qualif.hash_stable(hcx, hasher); + } + EntryKind::Enum(ref repr_options) => { + repr_options.hash_stable(hcx, hasher); + } + EntryKind::Variant(ref variant_data) => { + variant_data.hash_stable(hcx, hasher); + } + EntryKind::Struct(ref variant_data, ref repr_options) | + EntryKind::Union(ref variant_data, ref repr_options) => { + variant_data.hash_stable(hcx, hasher); + repr_options.hash_stable(hcx, hasher); + } + EntryKind::Fn(ref fn_data) | + EntryKind::ForeignFn(ref fn_data) => { + fn_data.hash_stable(hcx, hasher); + } + EntryKind::Mod(ref mod_data) => { + mod_data.hash_stable(hcx, hasher); + } + EntryKind::MacroDef(ref macro_def) => { + macro_def.hash_stable(hcx, hasher); + } + EntryKind::Closure(closure_data) => { + closure_data.hash_stable(hcx, hasher); + } + EntryKind::Trait(ref trait_data) => { + trait_data.hash_stable(hcx, hasher); + } + EntryKind::DefaultImpl(ref impl_data) | + EntryKind::Impl(ref impl_data) => { + impl_data.hash_stable(hcx, hasher); + } + EntryKind::Method(ref method_data) => { + method_data.hash_stable(hcx, hasher); + } + EntryKind::AssociatedType(associated_container) => { + associated_container.hash_stable(hcx, hasher); + } + EntryKind::AssociatedConst(associated_container, qualif) => { + associated_container.hash_stable(hcx, hasher); + qualif.hash_stable(hcx, hasher); + } + } + } +} + #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { pub reexports: LazySeq, diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 66380079a8b2..0ffa7a79408e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -443,7 +443,10 @@ fn archive_config<'a>(sess: &'a Session, } fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: &Path) { - let result = fs::File::create(out_filename).and_then(|mut f| f.write_all(&trans.metadata)); + let result = fs::File::create(out_filename).and_then(|mut f| { + f.write_all(&trans.metadata.raw_data) + }); + if let Err(e) = result { sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 574b345218be..f76e816bcf0c 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -36,6 +36,7 @@ use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; +use middle::cstore::EncodedMetadata; use rustc::ty::{self, Ty, TyCtxt}; use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; @@ -724,7 +725,8 @@ fn contains_null(s: &str) -> bool { } fn write_metadata(cx: &SharedCrateContext, - exported_symbols: &NodeSet) -> Vec { + exported_symbols: &NodeSet) + -> EncodedMetadata { use flate; #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -748,7 +750,10 @@ fn write_metadata(cx: &SharedCrateContext, }).max().unwrap(); if kind == MetadataKind::None { - return Vec::new(); + return EncodedMetadata { + raw_data: vec![], + hashes: vec![], + }; } let cstore = &cx.tcx().sess.cstore; @@ -761,7 +766,7 @@ fn write_metadata(cx: &SharedCrateContext, assert!(kind == MetadataKind::Compressed); let mut compressed = cstore.metadata_encoding_version().to_vec(); - compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); + compressed.extend_from_slice(&flate::deflate_bytes(&metadata.raw_data)); let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 5c3b17c88976..628d46f8e705 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -168,7 +168,7 @@ pub struct CrateTranslation { pub modules: Vec, pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, - pub metadata: Vec, + pub metadata: middle::cstore::EncodedMetadata, pub exported_symbols: back::symbol_export::ExportedSymbols, pub no_builtins: bool, pub windows_subsystem: Option, diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index 048ccb529a24..37c6ef58f5e5 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -38,8 +38,13 @@ enum EnumVisibility { A } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -pub enum EnumVisibility { A } +pub enum EnumVisibility { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + A +} @@ -56,7 +61,10 @@ enum EnumChangeNameCStyleVariant { #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeNameCStyleVariant { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] Variant1, + #[rustc_metadata_clean(cfg="cfail3")] Variant2Changed, } @@ -259,10 +267,13 @@ enum EnumChangeFieldTypeTupleStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeTupleStyleVariant { - Variant1(u32, u64), + Variant1(u32, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u64), } @@ -277,11 +288,16 @@ enum EnumChangeFieldTypeStructStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeFieldTypeStructStyleVariant { Variant1, - Variant2 { a: u32, b: u64 }, + Variant2 { + a: u32, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + b: u64 + }, } @@ -312,10 +328,16 @@ enum EnumChangeOrderTupleStyleVariant { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumChangeOrderTupleStyleVariant { - Variant1(u64, u32), + Variant1( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u64, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u32), } @@ -611,11 +633,23 @@ enum EnumSwapUsageTypeParameters { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageTypeParameters { - Variant1 { a: B }, - Variant2 { a: A }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: B + }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant2 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: A + }, } @@ -630,11 +664,23 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { - Variant1 { a: &'b u32 }, - Variant2 { b: &'a u32 }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: &'b u32 + }, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant2 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + b: &'a u32 + }, } @@ -653,10 +699,16 @@ mod change_field_type_indirectly_tuple_style { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum TupleStyle { - Variant1(FieldType) + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + FieldType + ) } } @@ -671,10 +723,16 @@ mod change_field_type_indirectly_struct_style { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] enum StructStyle { - Variant1 { a: FieldType } + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + Variant1 { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + a: FieldType + } } } diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs index 03e621fedbeb..1d26e6c07d15 100644 --- a/src/test/incremental/hashes/extern_mods.rs +++ b/src/test/incremental/hashes/extern_mods.rs @@ -53,9 +53,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_parameter_name(d: i64) -> i32; } @@ -70,9 +72,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_parameter_type(c: i32) -> i32; } @@ -87,9 +91,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_return_type(c: i32) -> i8; } @@ -104,9 +110,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn add_parameter(c: i32, d: i32) -> i32; } @@ -121,9 +129,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn add_return_type(c: i32) -> i32; } @@ -138,9 +148,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn make_function_variadic(c: i32, ...); } @@ -155,9 +167,11 @@ extern "C" { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern "rust-call" { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn change_calling_convention(c: i32); } @@ -172,9 +186,11 @@ extern { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn make_function_public(c: i32); } @@ -246,9 +262,11 @@ mod indirectly_change_parameter_type { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn indirectly_change_parameter_type(c: c_int); } } @@ -264,9 +282,11 @@ mod indirectly_change_return_type { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] extern { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] pub fn indirectly_change_return_type() -> c_int; } } diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index 93d94cd1a19c..2fe3f0d5d1fe 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -50,7 +50,7 @@ fn add_return_type() {} #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] // The type doesn't change, so metadata is the same #[rustc_metadata_clean(cfg="cfail3")] fn add_return_type() -> () {} @@ -154,7 +154,7 @@ fn lifetime_parameter() {} #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +// #[rustc_metadata_dirty(cfg="cfail2")] -- Unused lifetime params don't show up in the type? #[rustc_metadata_clean(cfg="cfail3")] fn lifetime_parameter<'a>() {} @@ -315,16 +315,16 @@ fn return_impl_trait() -> impl Clone { #[cfg(cfail1)] fn change_return_impl_trait() -> impl Clone { - 0 + 0u32 } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] // The actual type is the same, so: clean #[rustc_metadata_clean(cfg="cfail3")] fn change_return_impl_trait() -> impl Copy { - 0 + 0u32 } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index fd9ac61046e3..899aefa24a03 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -107,7 +107,7 @@ impl Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -126,7 +126,7 @@ impl Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -171,7 +171,7 @@ impl Foo { impl Foo { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_method_to_impl1(&self) { } @@ -219,9 +219,7 @@ impl Foo { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_clean(label="HirBody", cfg="cfail3")] - // At the moment we explicitly ignore argument names in metadata, since they - // are not used in downstream crates (except in rustdoc) - #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_name(&self, b: i64) { } } @@ -287,9 +285,7 @@ impl Foo { #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_dirty(label="HirBody", cfg="cfail2")] #[rustc_clean(label="HirBody", cfg="cfail3")] - // At the moment we explicitly ignore argument names in metadata, since they - // are not used in downstream crates (except in rustdoc) - #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn change_method_parameter_order(&self, b: i64, a: i64) { } } @@ -373,7 +369,7 @@ impl Foo { impl Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] // Apparently unused lifetimes don't show up in the type. #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } @@ -544,7 +540,7 @@ impl Bar { impl Bar { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_impl_parameter(&self) { } } @@ -565,7 +561,7 @@ impl Bar { impl Bar { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub fn add_trait_bound_to_impl_parameter(&self) { } } diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs index 2d79987823f2..17a5dc167836 100644 --- a/src/test/incremental/hashes/struct_defs.rs +++ b/src/test/incremental/hashes/struct_defs.rs @@ -62,9 +62,13 @@ struct TupleStructFieldType(i32); #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct TupleStructFieldType(u32); +struct TupleStructFieldType( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + u32 +); // Tuple Struct Add Field ------------------------------------------------------ @@ -77,7 +81,13 @@ struct TupleStructAddField(i32); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct TupleStructAddField(i32, u32); +struct TupleStructAddField( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + i32, + #[rustc_metadata_clean(cfg="cfail3")] + u32 +); // Tuple Struct Field Visibility ----------------------------------------------- @@ -101,9 +111,13 @@ struct RecordStructFieldType { x: f32 } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructFieldType { x: u64 } +struct RecordStructFieldType { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + x: u64 +} // Record Struct Field Name ---------------------------------------------------- @@ -129,7 +143,12 @@ struct RecordStructAddField { x: f32 } #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructAddField { x: f32, y: () } +struct RecordStructAddField { + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + x: f32, + #[rustc_metadata_clean(cfg="cfail3")] + y: () } // Record Struct Field Visibility ---------------------------------------------- @@ -142,7 +161,11 @@ struct RecordStructFieldVisibility { x: f32 } #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct RecordStructFieldVisibility { pub x: f32 } +struct RecordStructFieldVisibility { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + pub x: f32 +} // Add Lifetime Parameter ------------------------------------------------------ @@ -168,7 +191,14 @@ struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddLifetimeParameterBound<'a, 'b: 'a>(&'a f32, &'b f64); +struct AddLifetimeParameterBound<'a, 'b: 'a>( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'a f32, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'b f64 +); #[cfg(cfail1)] struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); @@ -178,7 +208,13 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64) +struct AddLifetimeParameterBoundWhereClause<'a, 'b>( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'a f32, + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + &'b f64) where 'b: 'a; @@ -192,7 +228,16 @@ struct AddTypeParameter(T1, T1); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameter(T1, T2); +struct AddTypeParameter( + // The field contains the parent's Generics, so it's dirty even though its + // type hasn't changed. + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T1, + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T2 +); // Add Type Parameter Bound ---------------------------------------------------- @@ -205,7 +250,11 @@ struct AddTypeParameterBound(T); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameterBound(T); +struct AddTypeParameterBound( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T +); #[cfg(cfail1)] @@ -216,7 +265,11 @@ struct AddTypeParameterBoundWhereClause(T); #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] -struct AddTypeParameterBoundWhereClause(T) where T: Sync; +struct AddTypeParameterBoundWhereClause( + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + T +) where T: Sync; // Empty struct ---------------------------------------------------------------- @@ -234,6 +287,7 @@ struct Visibility; #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub struct Visibility; @@ -252,9 +306,13 @@ mod tuple_struct_change_field_type_indirectly { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - struct TupleStruct(FieldType); + struct TupleStruct( + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + FieldType + ); } @@ -267,9 +325,11 @@ mod record_struct_change_field_type_indirectly { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] struct RecordStruct { + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] _x: FieldType } } diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 94698506ec53..61a2be054a51 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -100,7 +100,7 @@ trait TraitAddReturnType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -121,7 +121,7 @@ trait TraitChangeReturnType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -142,7 +142,7 @@ trait TraitAddParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -164,7 +164,7 @@ trait TraitChangeMethodParameterName { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. @@ -194,7 +194,7 @@ trait TraitChangeMethodParameterType { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -215,7 +215,7 @@ trait TraitChangeMethodParameterTypeRef { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParameterTypeRef { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -236,7 +236,7 @@ trait TraitChangeMethodParametersOrder { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeMethodParametersOrder { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -257,9 +257,13 @@ trait TraitAddMethodDefaultImplementation { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddMethodDefaultImplementation { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] fn method() { } } @@ -293,7 +297,7 @@ trait TraitChangeModeSelfRefToMut { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeModeSelfRefToMut { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -335,7 +339,7 @@ trait TraitChangeModeSelfOwnToRef { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeModeSelfOwnToRef { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -356,7 +360,7 @@ trait TraitAddUnsafeModifier { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddUnsafeModifier { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -377,7 +381,7 @@ trait TraitAddExternModifier { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddExternModifier { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -398,7 +402,7 @@ trait TraitChangeExternCToRustIntrinsic { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeExternCToRustIntrinsic { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -419,7 +423,7 @@ trait TraitAddTypeParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddTypeParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -440,12 +444,12 @@ trait TraitAddLifetimeParameterToMethod { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddLifetimeParameterToMethod { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] // Unused lifetimes don't seem to show up in type? #[rustc_metadata_clean(cfg="cfail3")] fn method<'a>(); } @@ -465,7 +469,7 @@ trait TraitAddTraitBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddTraitBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -486,7 +490,7 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddBuiltinBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -507,7 +511,7 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -528,7 +532,7 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondTraitBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -549,7 +553,7 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -570,7 +574,7 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -585,7 +589,12 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { // Add associated type ------------------------------------------------------------ #[cfg(cfail1)] trait TraitAddAssociatedType { - fn mathod(); + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } #[cfg(not(cfail1))] @@ -596,7 +605,7 @@ trait TraitAddAssociatedType { trait TraitAddAssociatedType { type Associated; - fn mathod(); + fn method(); } @@ -606,9 +615,12 @@ trait TraitAddAssociatedType { trait TraitAddTraitBoundToAssociatedType { type Associated; - fn mathod(); + fn method(); } + +// Apparently the type bound contributes to the predicates of the trait, but +// does not change the associated item itself. #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] @@ -617,11 +629,11 @@ trait TraitAddTraitBoundToAssociatedType { trait TraitAddTraitBoundToAssociatedType { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type Associated: ReferencedTrait0; - fn mathod(); + fn method(); } @@ -631,7 +643,7 @@ trait TraitAddTraitBoundToAssociatedType { trait TraitAddLifetimeBoundToAssociatedType<'a> { type Associated; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] @@ -642,11 +654,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { trait TraitAddLifetimeBoundToAssociatedType<'a> { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] type Associated: 'a; - fn mathod(); + fn method(); } @@ -656,18 +668,22 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { trait TraitAddDefaultToAssociatedType { type Associated; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddDefaultToAssociatedType { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] type Associated = ReferenceType0; - fn mathod(); + fn method(); } @@ -675,7 +691,7 @@ trait TraitAddDefaultToAssociatedType { // Add associated constant -------------------------------------------------------- #[cfg(cfail1)] trait TraitAddAssociatedConstant { - fn mathod(); + fn method(); } #[cfg(not(cfail1))] @@ -686,7 +702,7 @@ trait TraitAddAssociatedConstant { trait TraitAddAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } @@ -696,18 +712,26 @@ trait TraitAddAssociatedConstant { trait TraitAddInitializerToAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitAddInitializerToAssociatedConstant { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] const Value: u32 = 1; - fn mathod(); + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } @@ -717,13 +741,13 @@ trait TraitAddInitializerToAssociatedConstant { trait TraitChangeTypeOfAssociatedConstant { const Value: u32; - fn mathod(); + fn method(); } #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeTypeOfAssociatedConstant { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -732,7 +756,11 @@ trait TraitChangeTypeOfAssociatedConstant { #[rustc_metadata_clean(cfg="cfail3")] const Value: f64; - fn mathod(); + #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_clean(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn method(); } @@ -1111,9 +1139,6 @@ trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } - -// EDIT: Some more cases ---------------------------------------------------------- - // Change return type of method indirectly by modifying a use statement------------ mod change_return_type_of_method_indirectly_use { #[cfg(cfail1)] @@ -1123,7 +1148,7 @@ mod change_return_type_of_method_indirectly_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeReturnType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1145,7 +1170,7 @@ mod change_method_parameter_type_indirectly_by_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeArgType { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1167,7 +1192,7 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameter { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -1190,7 +1215,7 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameterWhere { #[rustc_dirty(label="Hir", cfg="cfail2")] diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs index 30e376f04fb8..06c8eb6a878f 100644 --- a/src/test/incremental/hashes/trait_impls.rs +++ b/src/test/incremental/hashes/trait_impls.rs @@ -120,7 +120,7 @@ impl ChangeMethodBodyTraitInlined for Foo { #[rustc_metadata_clean(cfg="cfail3")] #[inline] fn method_name() { - () + panic!() } } @@ -144,7 +144,7 @@ pub trait ChangeMethodSelfnessTrait { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeMethodSelfnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -176,16 +176,14 @@ pub trait RemoveMethodSelfnessTrait { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl RemoveMethodSelfnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn method_name() { - () - } + fn method_name() {} } // Change Method Selfmutness ----------------------------------------------------------- @@ -208,16 +206,14 @@ pub trait ChangeMethodSelfmutnessTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeMethodSelfmutnessTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_dirty(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - fn method_name(&mut self) { - () - } + fn method_name(&mut self) {} } // Change item kind ----------------------------------------------------------- @@ -317,16 +313,20 @@ impl ChangeHasValueTrait for Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] pub trait ChangeHasValueTrait { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] fn method_name() { } } #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeHasValueTrait for Foo { fn method_name() { } @@ -346,32 +346,16 @@ impl AddDefaultTrait for Foo { #[cfg(not(cfail1))] #[rustc_dirty(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl AddDefaultTrait for Foo { + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] default fn method_name() { } } -// Remove default - -pub trait RemoveDefaultTrait { - fn method_name(); -} - -#[cfg(cfail1)] -impl RemoveDefaultTrait for Foo { - default fn method_name() { } -} - -#[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] -#[rustc_metadata_clean(cfg="cfail3")] -impl RemoveDefaultTrait for Foo { - fn method_name() { } -} - // Add arguments #[cfg(cfail1)] @@ -392,7 +376,7 @@ pub trait AddArgumentTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl AddArgumentTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -422,7 +406,7 @@ pub trait ChangeArgumentTypeTrait { #[cfg(not(cfail1))] #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] impl ChangeArgumentTypeTrait for Foo { #[rustc_dirty(label="Hir", cfg="cfail2")] @@ -504,7 +488,7 @@ impl AddLifetimeBoundToImplParameter for T { impl AddLifetimeBoundToImplParameter for T { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn id(self) -> Self { self } } @@ -529,7 +513,7 @@ impl AddTraitBoundToImplParameter for T { impl AddTraitBoundToImplParameter for T { #[rustc_clean(label="Hir", cfg="cfail2")] #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn id(self) -> Self { self } } diff --git a/src/test/incremental/unchecked_dirty_clean_metadata.rs b/src/test/incremental/unchecked_dirty_clean_metadata.rs index 4017b4d4ba9a..917c2c9dbce4 100644 --- a/src/test/incremental/unchecked_dirty_clean_metadata.rs +++ b/src/test/incremental/unchecked_dirty_clean_metadata.rs @@ -33,13 +33,3 @@ fn main() { } } -struct _Struct { - #[rustc_metadata_dirty(cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute - _field1: i32, - - #[rustc_metadata_clean(cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked #[rustc_dirty]/#[rustc_clean] attribute - _field2: i32, -} - From dd7dfe56a9e0d095c670a84f9e827fa9689aad97 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Apr 2017 18:14:54 +0200 Subject: [PATCH 448/905] Fix invalid associated type rendering in rustdoc --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/html/format.rs | 115 ++++++++++++++++++---------- src/test/rustdoc/assoc-item-cast.rs | 26 +++++++ 3 files changed, 101 insertions(+), 42 deletions(-) create mode 100644 src/test/rustdoc/assoc-item-cast.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac72d7d29a24..2511560e8726 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2277,7 +2277,7 @@ impl Clean for hir::PathParameters { #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct PathSegment { pub name: String, - pub params: PathParameters + pub params: PathParameters, } impl Clean for hir::PathSegment { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index ffef42bc3d27..0f47265a1aa6 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -470,10 +470,22 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { /// rendering function with the necessary arguments for linking to a local path. fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, print_all: bool, use_absolute: bool, is_not_debug: bool) -> fmt::Result { - let last = path.segments.last().unwrap(); - let rel_root = match &*path.segments[0].name { - "self" => Some("./".to_string()), - _ => None, + let empty = clean::PathSegment { + name: String::new(), + params: clean::PathParameters::Parenthesized { + inputs: Vec::new(), + output: None, + } + }; + let last = path.segments.last() + .unwrap_or(&empty); + let rel_root = if path.segments.is_empty() { + None + } else { + match &*path.segments[0].name { + "self" => Some("./".to_string()), + _ => None, + } }; if print_all { @@ -487,10 +499,9 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, root.push_str(&seg.name); root.push_str("/"); if is_not_debug { - write!(w, "{}::", - root, - seg.name)?; + write!(w, "{}::", + root, + seg.name)?; } else { write!(w, "{}::", seg.name)?; } @@ -516,7 +527,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, match href(did) { Some((_, _, fqp)) => format!("{}::{}", fqp[..fqp.len()-1].join("::"), - HRef::new(did, fqp.last().unwrap())), + HRef::new(did, fqp.last() + .unwrap_or(&String::new()))), None => format!("{}", HRef::new(did, &last.name)), } } else { @@ -528,7 +540,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, match href(did) { Some((_, _, fqp)) => format!("{:?}::{:?}", fqp[..fqp.len()-1].join("::"), - HRef::new(did, fqp.last().unwrap())), + HRef::new(did, fqp.last() + .unwrap_or(&String::new()))), None => format!("{:?}", HRef::new(did, &last.name)), } } else { @@ -801,45 +814,65 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool, } Ok(()) } - // It's pretty unsightly to look at `::C` in output, and - // we've got hyperlinking on our side, so try to avoid longer - // notation as much as possible by making `C` a hyperlink to trait - // `B` to disambiguate. - // - // FIXME: this is still a lossy conversion and there should probably - // be a better way of representing this in general? Most of - // the ugliness comes from inlining across crates where - // everything comes in as a fully resolved QPath (hard to - // look at). - clean::QPath { - ref name, - ref self_type, - trait_: box clean::ResolvedPath { did, ref typarams, .. }, - } => { - if f.alternate() { - write!(f, "{:#}::", self_type)?; - } else { - write!(f, "{}::", self_type)?; - } - let path = clean::Path::singleton(name.clone()); - resolved_path(f, did, &path, true, use_absolute, is_not_debug)?; - - // FIXME: `typarams` are not rendered, and this seems bad? - drop(typarams); - Ok(()) - } clean::QPath { ref name, ref self_type, ref trait_ } => { + let should_show_cast = match *trait_ { + box clean::ResolvedPath { .. } => { + let path = clean::Path::singleton(name.clone()); + !path.segments.is_empty() && &format!("{:#}", trait_) != "()" && + &format!("{:#}", self_type) != "Self" + } + _ => true, + }; if f.alternate() { if is_not_debug { - write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{:#} as {:#}>::", self_type, trait_)? + } else { + write!(f, "{:#}::", self_type)? + } } else { - write!(f, "<{:#?} as {:#?}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{:#?} as {:#?}>::", self_type, trait_)? + } else { + write!(f, "{:#?}::", self_type)? + } } } else { if is_not_debug { - write!(f, "<{} as {}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{} as {}>::", self_type, trait_)? + } else { + write!(f, "{}::", self_type)? + } } else { - write!(f, "<{:?} as {:?}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{:?} as {:?}>::", self_type, trait_)? + } else { + write!(f, "{:?}::", self_type)? + } + } + }; + match *trait_ { + // It's pretty unsightly to look at `::C` in output, and + // we've got hyperlinking on our side, so try to avoid longer + // notation as much as possible by making `C` a hyperlink to trait + // `B` to disambiguate. + // + // FIXME: this is still a lossy conversion and there should probably + // be a better way of representing this in general? Most of + // the ugliness comes from inlining across crates where + // everything comes in as a fully resolved QPath (hard to + // look at). + box clean::ResolvedPath { did, ref typarams, .. } => { + let path = clean::Path::singleton(name.clone()); + resolved_path(f, did, &path, true, use_absolute, is_not_debug)?; + + // FIXME: `typarams` are not rendered, and this seems bad? + drop(typarams); + Ok(()) + } + _ => { + write!(f, "{}", name) } } } diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs new file mode 100644 index 000000000000..24f31b5b1040 --- /dev/null +++ b/src/test/rustdoc/assoc-item-cast.rs @@ -0,0 +1,26 @@ +// 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. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +pub trait Expression { + type SqlType; +} + +pub trait AsExpression { + type Expression: Expression; + fn as_expression(self) -> Self::Expression; +} + +// @has foo/type.AsExprOf.html +// @has - '//*[@class="rust typedef"]' 'type AsExprOf = >::Expression;' +pub type AsExprOf = >::Expression; From 71a9e106690627e657a466938e578608d8bcd04a Mon Sep 17 00:00:00 2001 From: kennytm Date: Wed, 12 Apr 2017 22:51:32 +0800 Subject: [PATCH 449/905] Fixed invalid 128-bit division on 32-bit target. Fixed issue #41228. Added test cases to cover all special-cased branches of udivmodti4. --- src/libcompiler_builtins/lib.rs | 2 +- src/test/run-pass/i128.rs | 5 ++++ src/test/run-pass/u128.rs | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 58aba11e4394..09b3d6395070 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -180,7 +180,7 @@ pub mod reimpls { sr = sr.wrapping_add(1); // 1 <= sr <= u64::bits() - 1 - q = n.wrapping_shl(64u32.wrapping_sub(sr)); + q = n.wrapping_shl(128u32.wrapping_sub(sr)); r = n.wrapping_shr(sr); } else { if d.high() == 0 { diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index dc4f0774b977..c5057f70c065 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -104,4 +104,9 @@ fn main() { assert_eq!(l.checked_sub(l), Some(0)); assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127)); assert_eq!(o.checked_shl(b(128)), None); + + // https://github.com/rust-lang/rust/issues/41228 + assert_eq!(b(-87559967289969187895646876466835277875_i128) / + b(84285771033834995895337664386045050880_i128), + -1i128); } diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index ac3dfcdfde15..cfd616c56b4f 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -77,4 +77,49 @@ fn main() { assert_eq!(o.checked_sub(b(18)), None); assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127)); assert_eq!(o.checked_shl(b(128)), None); + + // Test cases for all udivmodti4 branches. + // case "0X/0X" + assert_eq!(b(0x69545bd57727c050_u128) / + b(0x3283527a3350d88c_u128), + 2u128); + // case "0X/KX" + assert_eq!(b(0x0_8003c9c50b473ae6_u128) / + b(0x1_283e8838c30fa8f4_u128), + 0u128); + // case "K0/K0" + assert_eq!(b(0xc43f42a207978720_u128 << 64) / + b(0x098e62b74c23cf1a_u128 << 64), + 20u128); + // case "KK/K0" for power-of-two D. + assert_eq!(b(0xa9008fb6c9d81e42_0e25730562a601c8_u128) / + b(1u128 << 120), + 169u128); + // case "KK/K0" with N >= D (https://github.com/rust-lang/rust/issues/41228). + assert_eq!(b(0xe4d26e59f0640328_06da5b06efe83a41_u128) / + b(0x330fcb030ea4447c_u128 << 64), + 4u128); + assert_eq!(b(3u128 << 64 | 1) / + b(3u128 << 64), + 1u128); + // case "KK/K0" with N < D. + assert_eq!(b(0x6655c9fb66ca2884_e2d1dfd470158c62_u128) / + b(0xb35b667cab7e355b_u128 << 64), + 0u128); + // case "KX/0K" for power-of-two D. + assert_eq!(b(0x3e49dd84feb2df59_7b2f97d93a253969_u128) / + b(1u128 << 4), + 0x03e49dd84feb2df5_97b2f97d93a25396_u128); + // case "KX/0K" in general. + assert_eq!(b(0x299692b3a1dae5bd_6162e6f489d2620e_u128) / + b(0x900b6f027571d6f7_u128), + 0x49e95f54b0442578_u128); + // case "KX/KK" with N >= D. + assert_eq!(b(0xc7b889180b67b07d_bc1a3c88783d35b5_u128) / + b(0x1d7e69f53160b9e2_60074771e852f244_u128), + 6u128); + // case "KX/KK" with N < D. + assert_eq!(b(0x679289ac23bb334f_36144401cf882172_u128) / + b(0x7b0b271b64865f05_f54a7b72746c062f_u128), + 0u128); } From fa437f49af90e1a78771f2262d51ddd01b668199 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Apr 2017 12:36:43 -0400 Subject: [PATCH 450/905] do not consult union-find during `fudge_regions_if_ok` --- src/librustc/infer/fudge.rs | 16 ++++------------ src/librustc/infer/type_variable.rs | 14 +++----------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index ab0ff32dcc3e..72b23a3bc181 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -135,19 +135,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { ty } - Some(info) => { + Some(&origin) => { // This variable was created during the - // fudging; it was mapped the root - // `root_vid`. There are now two - // possibilities: either the root was creating - // during the fudging too, in which case we - // want a fresh variable, or it was not, in - // which case we can return it. - if self.type_variables.contains_key(&info.root_vid) { - self.infcx.next_ty_var(info.root_origin) - } else { - self.infcx.tcx.mk_var(info.root_vid) - } + // fudging. Recreate it with a fresh variable + // here. + self.infcx.next_ty_var(origin) } } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index a32404c1ac51..34bb9feb5c92 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -67,12 +67,7 @@ pub enum TypeVariableOrigin { Generalized(ty::TyVid), } -pub type TypeVariableMap = FxHashMap; - -pub struct TypeVariableInfo { - pub root_vid: ty::TyVid, - pub root_origin: TypeVariableOrigin, -} +pub type TypeVariableMap = FxHashMap; struct TypeVariableData<'tcx> { value: TypeVariableValue<'tcx>, @@ -294,8 +289,6 @@ impl<'tcx> TypeVariableTable<'tcx> { /// along with their origin. pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap { let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); - let eq_relations = &mut self.eq_relations; - let values = &self.values; actions_since_snapshot .iter() @@ -304,9 +297,8 @@ impl<'tcx> TypeVariableTable<'tcx> { _ => None, }) .map(|vid| { - let root_vid = eq_relations.find(vid); - let root_origin = values.get(vid.index as usize).origin.clone(); - (vid, TypeVariableInfo { root_vid, root_origin }) + let origin = self.values.get(vid.index as usize).origin.clone(); + (vid, origin) }) .collect() } From 1cc7621dec567ded8965fd6c01d80104cfec4d68 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Apr 2017 12:51:19 -0400 Subject: [PATCH 451/905] simplify code to remove now unused "stack" and fix comments --- src/librustc/infer/combine.rs | 133 ++++++++++------------------ src/librustc/infer/type_variable.rs | 7 +- 2 files changed, 51 insertions(+), 89 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 03ed654e3cce..b73079b02bdd 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -47,7 +47,6 @@ use ty::relate::{RelateResult, TypeRelation}; use traits::PredicateObligations; use syntax::ast; -use syntax::util::small_vector::SmallVector; use syntax_pos::Span; #[derive(Clone)] @@ -174,6 +173,15 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Glb::new(self, a_is_expected) } + /// Here dir is either EqTo, SubtypeOf, or SupertypeOf. The + /// idea is that we should ensure that the type `a_ty` is equal + /// to, a subtype of, or a supertype of (respectively) the type + /// to which `b_vid` is bound. + /// + /// Since `b_vid` has not yet been instantiated with a type, we + /// will first instantiate `b_vid` with a *generalized* version + /// of `a_ty`. Generalization introduces other inference + /// variables wherever subtyping could occur. pub fn instantiate(&mut self, a_ty: Ty<'tcx>, dir: RelationDir, @@ -183,92 +191,49 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { { use self::RelationDir::*; - // We use SmallVector here instead of Vec because this code is hot and - // it's rare that the stack length exceeds 1. - let mut stack = SmallVector::new(); - stack.push((a_ty, dir, b_vid)); - loop { - // For each turn of the loop, we extract a tuple - // - // (a_ty, dir, b_vid) - // - // to relate. Here dir is either SubtypeOf or - // SupertypeOf. The idea is that we should ensure that - // the type `a_ty` is a subtype or supertype (respectively) of the - // type to which `b_vid` is bound. - // - // If `b_vid` has not yet been instantiated with a type - // (which is always true on the first iteration, but not - // necessarily true on later iterations), we will first - // instantiate `b_vid` with a *generalized* version of - // `a_ty`. Generalization introduces other inference - // variables wherever subtyping could occur (at time of - // this writing, this means replacing free regions with - // region variables). - let (a_ty, dir, b_vid) = match stack.pop() { - None => break, - Some(e) => e, - }; - // Get the actual variable that b_vid has been inferred to - let (b_vid, b_ty) = { - let mut variables = self.infcx.type_variables.borrow_mut(); - let b_vid = variables.root_var(b_vid); - (b_vid, variables.probe_root(b_vid)) - }; + // Get the actual variable that b_vid has been inferred to + debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_none()); - debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", - a_ty, - dir, - b_vid); + debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); - // Check whether `vid` has been instantiated yet. If not, - // make a generalized form of `ty` and instantiate with - // that. - // - // FIXME(#18653) -- we need to generalize nested type - // variables too. - let b_ty = match b_ty { - Some(t) => t, // ...already instantiated. - None => { // ...not yet instantiated: - // Generalize type if necessary. - let generalized_ty = match dir { - EqTo => self.generalize(a_ty, b_vid, false), - SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), - }?; - debug!("instantiate(a_ty={:?}, dir={:?}, \ - b_vid={:?}, generalized_ty={:?})", - a_ty, dir, b_vid, - generalized_ty); - self.infcx.type_variables - .borrow_mut() - .instantiate(b_vid, generalized_ty); - generalized_ty - } - }; + // Generalize type of `a_ty` appropriately depending on the + // direction. As an example, assume: + // + // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an + // inference variable, + // - and `dir` == `SubtypeOf`. + // + // Then the generalized form `b_ty` would be `&'?2 ?3`, where + // `'?2` and `?3` are fresh region/type inference + // variables. (Down below, we will relate `a_ty <: b_ty`, + // adding constraints like `'x: '?2` and `?1 <: ?3`.) + let b_ty = self.generalize(a_ty, b_vid, dir == EqTo)?; + debug!("instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", + a_ty, dir, b_vid, b_ty); + self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty); - // The original triple was `(a_ty, dir, b_vid)` -- now we have - // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`: - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - match dir { - EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), - SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), - SupertypeOf => self.sub(a_is_expected).relate_with_variance( - ty::Contravariant, &a_ty, &b_ty), - }?; - } + // Finally, relate `b_ty` to `a_ty`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + match dir { + EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), + SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), + SupertypeOf => self.sub(a_is_expected).relate_with_variance( + ty::Contravariant, &a_ty, &b_ty), + }?; Ok(()) } /// Attempts to generalize `ty` for the type variable `for_vid`. /// This checks for cycle -- that is, whether the type `ty` - /// references `for_vid`. If `make_region_vars` is true, it will - /// also replace all regions with fresh variables. Returns - /// `TyError` in the case of a cycle, `Ok` otherwise. + /// references `for_vid`. If `is_eq_relation` is false, it will + /// also replace all regions/unbound-type-variables with fresh + /// variables. Returns `TyError` in the case of a cycle, `Ok` + /// otherwise. /// /// Preconditions: /// @@ -276,16 +241,14 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { fn generalize(&self, ty: Ty<'tcx>, for_vid: ty::TyVid, - make_region_vars: bool) + is_eq_relation: bool) -> RelateResult<'tcx, Ty<'tcx>> { - debug_assert!(self.infcx.type_variables.borrow_mut().root_var(for_vid) == for_vid); - let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), - make_region_vars: make_region_vars, + is_eq_relation: is_eq_relation, cycle_detected: false }; let u = ty.fold_with(&mut generalize); @@ -301,7 +264,7 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, span: Span, for_vid_sub_root: ty::TyVid, - make_region_vars: bool, + is_eq_relation: bool, cycle_detected: bool, } @@ -332,7 +295,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx self.fold_ty(u) } None => { - if self.make_region_vars { + if !self.is_eq_relation { let origin = variables.origin(vid); let new_var_id = variables.new_var(false, origin, None); let u = self.tcx().mk_var(new_var_id); @@ -379,7 +342,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx ty::ReScope(..) | ty::ReVar(..) | ty::ReFree(..) => { - if !self.make_region_vars { + if self.is_eq_relation { return r; } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 34bb9feb5c92..4ae2a8026409 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -151,11 +151,10 @@ impl<'tcx> TypeVariableTable<'tcx> { /// Instantiates `vid` with the type `ty`. /// - /// Precondition: `vid` must be a root in the unification table - /// and has not previously been instantiated. + /// Precondition: `vid` must not have been previously instantiated. pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { - debug_assert!(self.root_var(vid) == vid); - debug_assert!(self.probe(vid).is_none()); + let vid = self.root_var(vid); + debug_assert!(self.probe_root(vid).is_none()); let old_value = { let vid_data = &mut self.values[vid.index as usize]; From cb3c4d022a048d9c4d1306eaacd9b72303f1871a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:03:04 +0200 Subject: [PATCH 452/905] rustc_trans: don't emit ZST allocas that are only assigned to. --- src/librustc_trans/mir/analyze.rs | 3 +- src/librustc_trans/mir/mod.rs | 20 +++---------- src/librustc_trans/mir/operand.rs | 18 +++++++++++- src/librustc_trans/mir/rvalue.rs | 49 +++++++++++++++++-------------- 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index a3968650043b..889f9dc4cded 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -19,7 +19,6 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common; use super::MirContext; -use super::rvalue; pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let mir = mircx.mir; @@ -93,7 +92,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { if let mir::Lvalue::Local(index) = *lvalue { self.mark_assigned(index); - if !rvalue::rvalue_creates_operand(rvalue) { + if !self.cx.rvalue_creates_operand(rvalue) { self.mark_as_lvalue(index); } } else { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index c51e1fb00280..99d8cd594ecd 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,17 +11,16 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; use rustc::infer::TransNormalize; -use rustc::ty::TypeFoldable; use session::config::FullDebugInfo; use base; use builder::Builder; -use common::{self, CrateContext, C_null, Funclet}; +use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::{self, Instance}; use abi::FnType; @@ -171,23 +170,12 @@ enum LocalRef<'tcx> { impl<'tcx> LocalRef<'tcx> { fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>, - ty: ty::Ty<'tcx>) -> LocalRef<'tcx> { + ty: Ty<'tcx>) -> LocalRef<'tcx> { if common::type_is_zero_size(ccx, ty) { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - let llty = type_of::type_of(ccx, ty); - let val = if common::type_is_imm_pair(ccx, ty) { - let fields = llty.field_types(); - OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) - } else { - OperandValue::Immediate(C_null(llty)) - }; - let op = OperandRef { - val: val, - ty: ty - }; - LocalRef::Operand(Some(op)) + LocalRef::Operand(Some(OperandRef::new_zst(ccx, ty))) } else { LocalRef::Operand(None) } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 771a88238b2b..c31142323c85 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -16,7 +16,7 @@ use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; use base; -use common; +use common::{self, CrateContext, C_null}; use builder::Builder; use value::Value; use type_of; @@ -79,6 +79,22 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> { } impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) -> OperandRef<'tcx> { + assert!(common::type_is_zero_size(ccx, ty)); + let llty = type_of::type_of(ccx, ty); + let val = if common::type_is_imm_pair(ccx, ty) { + let fields = llty.field_types(); + OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) + } else { + OperandValue::Immediate(C_null(llty)) + }; + OperandRef { + val: val, + ty: ty + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> ValueRef { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 8f7cb914c473..aa41720d717a 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -158,7 +158,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } _ => { - assert!(rvalue_creates_operand(rvalue)); + assert!(self.rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); bcx @@ -171,7 +171,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { - assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -466,8 +466,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - bug!("cannot generate operand from rvalue {:?}", rvalue); - + // According to `rvalue_creates_operand`, only ZST + // aggregate rvalues are allowed to be operands. + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + (bcx, OperandRef::new_zst(self.ccx, self.monomorphize(&ty))) } } } @@ -650,26 +652,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { OperandValue::Pair(val, of) } -} -pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> 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::Box(..) | - mir::Rvalue::Use(..) => // (*) - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => - false, + 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::Box(..) | + mir::Rvalue::Use(..) => // (*) + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + let ty = self.monomorphize(&ty); + common::type_is_zero_size(self.ccx, ty) + } + } + + // (*) this is only true if the type is suitable } - - // (*) this is only true if the type is suitable } #[derive(Copy, Clone)] From 9b5c577dbd45ff3b11f9d7aab6990cc1ee9194fb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:08:09 +0200 Subject: [PATCH 453/905] rustc_trans: avoid a separate entry BB if START_BLOCK has no backedges. --- src/librustc_trans/debuginfo/metadata.rs | 3 +- src/librustc_trans/mir/mod.rs | 17 +++++---- src/test/codegen/naked-functions.rs | 47 +++++++++++++++++++----- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ccb693aa41f4..2d1c95114ebd 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -784,7 +784,8 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, }; debug!("compile_unit_metadata: {:?}", compile_unit_name); - let producer = format!("rustc version {}", + // 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 compile_unit_name = compile_unit_name.as_ptr(); diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 99d8cd594ecd..3d8c5085462a 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -195,15 +195,17 @@ pub fn trans_mir<'a, 'tcx: 'a>( debug!("fn_ty: {:?}", fn_ty); let debug_context = debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir); - let bcx = Builder::new_block(ccx, llfn, "entry-block"); + let bcx = Builder::new_block(ccx, llfn, "start"); let cleanup_kinds = analyze::cleanup_kinds(&mir); - // Allocate a `Block` for every basic block + // 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_bcxs: IndexVec = mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK { - bcx.build_sibling_block("start").llbb() + if bb == mir::START_BLOCK && !reentrant_start_block { + bcx.llbb() } else { bcx.build_sibling_block(&format!("{:?}", bb)).llbb() } @@ -289,9 +291,10 @@ pub fn trans_mir<'a, 'tcx: 'a>( .collect() }; - // Branch to the START block - let start_bcx = mircx.blocks[mir::START_BLOCK]; - bcx.br(start_bcx); + // Branch to the START block, if it's not the entry block. + if reentrant_start_block { + bcx.br(mircx.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 diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 9de74f72005e..9883ca6b35d0 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -20,7 +20,8 @@ #[no_mangle] #[naked] fn naked_empty() { - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret void } // CHECK: Function Attrs: naked uwtable @@ -28,9 +29,10 @@ fn naked_empty() { #[naked] // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}}) fn naked_with_args(a: isize) { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret void } // CHECK: Function Attrs: naked uwtable @@ -38,7 +40,8 @@ fn naked_with_args(a: isize) { #[no_mangle] #[naked] fn naked_with_return() -> isize { - // CHECK: ret i{{[0-9]+}} 0 + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret i{{[0-9]+}} 0 0 } @@ -47,9 +50,10 @@ fn naked_with_return() -> isize { #[no_mangle] #[naked] fn naked_with_args_and_return(a: isize) -> isize { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} a } @@ -58,14 +62,37 @@ fn naked_with_args_and_return(a: isize) -> isize { #[no_mangle] #[naked] fn naked_recursive() { - // CHECK: call void @naked_empty() + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: call void @naked_empty() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb1 + // CHECK: bb1: + naked_empty(); - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb2 + // CHECK: bb2: + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb3 + // CHECK: bb3: + + // CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb4 + // CHECK: bb4: + naked_with_args( - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) naked_with_args_and_return( - // CHECK: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) naked_with_return() ) ); + // CHECK-NEXT: ret void } From 768e9029413c6fa3857cf8ba7d943bb297a58ee3 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 15 Mar 2017 21:27:40 -0500 Subject: [PATCH 454/905] First attempt at global_asm! macro --- src/librustc/hir/def.rs | 6 +- src/librustc/hir/intravisit.rs | 1 + src/librustc/hir/lowering.rs | 8 +++ src/librustc/hir/map/def_collector.rs | 1 + src/librustc/hir/map/mod.rs | 1 + src/librustc/hir/mod.rs | 9 +++ src/librustc/hir/print.rs | 5 ++ src/librustc/ich/impls_hir.rs | 13 ++++ src/librustc/middle/reachable.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 3 +- src/librustc_metadata/decoder.rs | 1 + src/librustc_metadata/encoder.rs | 2 + src/librustc_metadata/schema.rs | 1 + src/librustc_privacy/lib.rs | 13 +++- src/librustc_resolve/build_reduced_graph.rs | 2 + src/librustc_resolve/lib.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 1 + src/librustc_save_analysis/lib.rs | 1 + src/librustc_trans/collector.rs | 1 + src/librustc_typeck/collect.rs | 1 + src/librustc_typeck/variance/constraints.rs | 1 + src/librustc_typeck/variance/terms.rs | 1 + src/librustdoc/visit_ast.rs | 1 + src/libsyntax/ast.rs | 12 ++++ src/libsyntax/ext/expand.rs | 1 + src/libsyntax/feature_gate.rs | 6 ++ src/libsyntax/fold.rs | 10 ++++ src/libsyntax/print/pprust.rs | 5 ++ src/libsyntax/visit.rs | 6 ++ src/libsyntax_ext/global_asm.rs | 66 +++++++++++++++++++++ src/libsyntax_ext/lib.rs | 2 + 31 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 src/libsyntax_ext/global_asm.rs diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 7bab4a8d725d..771031db0c04 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -57,6 +57,8 @@ pub enum Def { // Macro namespace Macro(DefId, MacroKind), + GlobalAsm(DefId), + // Both namespaces Err, } @@ -144,7 +146,8 @@ impl Def { Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | - Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => { + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) | + Def::GlobalAsm(id) => { id } @@ -185,6 +188,7 @@ impl Def { Def::Label(..) => "label", Def::SelfTy(..) => "self type", Def::Macro(..) => "macro", + Def::GlobalAsm(..) => "global asm", Def::Err => "unresolved item", } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2c8b145f126c..9615ed4af069 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -474,6 +474,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } + ItemGlobalAsm(_) => {} ItemTy(ref typ, ref type_parameters) => { visitor.visit_id(item.id); visitor.visit_ty(typ); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 30fec50d4eb6..c86aaa7bf672 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -646,6 +646,13 @@ impl<'a> LoweringContext<'a> { } } + fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P { + P(hir::GlobalAsm { + asm: ga.asm, + ctxt: ga.ctxt, + }) + } + fn lower_variant(&mut self, v: &Variant) -> hir::Variant { Spanned { node: hir::Variant_ { @@ -1288,6 +1295,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), + ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)), ItemKind::Ty(ref t, ref generics) => { hir::ItemTy(self.lower_ty(t), self.lower_generics(generics)) } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index c1417f718b27..7ff5152c71a2 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -109,6 +109,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { DefPathData::ValueNs(i.ident.name.as_str()), ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), + ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(ref view_path) => { match view_path.node { ViewPathGlob(..) => {} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index cfafec00ae20..48b8a819fff0 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1077,6 +1077,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemFn(..) => "fn", ItemMod(..) => "mod", ItemForeignMod(..) => "foreign mod", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "ty", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0da405d1821d..562b58844409 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1495,6 +1495,12 @@ pub struct ForeignMod { pub items: HirVec, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct GlobalAsm { + pub asm: Symbol, + pub ctxt: SyntaxContext, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: HirVec, @@ -1686,6 +1692,8 @@ pub enum Item_ { ItemMod(Mod), /// An external module ItemForeignMod(ForeignMod), + /// Module-level inline assembly (from global_asm!) + ItemGlobalAsm(P), /// A type alias, e.g. `type Foo = Bar` ItemTy(P, Generics), /// An enum definition, e.g. `enum Foo {C, D}` @@ -1720,6 +1728,7 @@ impl Item_ { ItemFn(..) => "function", ItemMod(..) => "module", ItemForeignMod(..) => "foreign module", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "type alias", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 4a5a35aa82ca..5144f75b1a36 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -633,6 +633,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + hir::ItemGlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global asm"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()? + } hir::ItemTy(ref ty, ref params) => { self.ibox(indent_unit)?; self.ibox(0)?; diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 9cf8a0693d36..5b8dc96f013c 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1014,6 +1014,19 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput { is_indirect }); +impl<'a, 'tcx> HashStable> for hir::GlobalAsm { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::GlobalAsm { + asm, + ctxt: _ + } = *self; + + asm.hash_stable(hcx, hasher); + } +} + impl<'a, 'tcx> HashStable> for hir::InlineAsm { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index e5dd48534a6a..63455f94cedf 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -267,7 +267,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {} + hir::ItemUnion(..) | hir::ItemDefaultImpl(..) | + hir::ItemGlobalAsm(..) => {} } } hir_map::NodeTraitItem(trait_method) => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8037570d24a8..b9938a04047c 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -314,7 +314,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemUse(..) | hir::ItemMod(..) | hir::ItemDefaultImpl(..) | - hir::ItemForeignMod(..) => { + hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index cdbecb3ae2e4..3498be9dfdf3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -429,6 +429,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Trait(_) => Def::Trait(did), EntryKind::Enum(..) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), + EntryKind::GlobalAsm => Def::GlobalAsm(did), EntryKind::ForeignMod | EntryKind::Impl(_) | diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ffe68094c6af..50ebf6737a8d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -677,6 +677,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis))); } hir::ItemForeignMod(_) => EntryKind::ForeignMod, + hir::ItemGlobalAsm(..) => EntryKind::GlobalAsm, hir::ItemTy(..) => EntryKind::Type, hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)), hir::ItemStruct(ref struct_def, _) => { @@ -917,6 +918,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemDefaultImpl(..) | diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 53d6a9ec10df..ae20dd1a554b 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -267,6 +267,7 @@ pub enum EntryKind<'tcx> { ForeignImmStatic, ForeignMutStatic, ForeignMod, + GlobalAsm, Type, Enum(ReprOptions), Field, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 300848fe8f25..92f7e48b6be4 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -160,7 +160,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { self.prev_level } // Other `pub` items inherit levels from parents - _ => { + hir::ItemConst(..) | hir::ItemEnum(..) | hir::ItemExternCrate(..) | + hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) | + hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemTrait(..) | + hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => { if item.vis == hir::Public { self.prev_level } else { None } } }; @@ -212,7 +215,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } } - _ => {} + hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | + hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemDefaultImpl(..) => {} } // Mark all items in interfaces of reachable items as reachable @@ -225,6 +230,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemUse(..) => {} // The interface is empty hir::ItemDefaultImpl(..) => {} + // The interface is empty + hir::ItemGlobalAsm(..) => {} // Visit everything hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { @@ -1092,6 +1099,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> hir::ItemMod(..) => {} // Checked in resolve hir::ItemUse(..) => {} + // No subitems + hir::ItemGlobalAsm(..) => {} // Subitems of these items have inherited publicity hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a15431afc164..80f853778c74 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -268,6 +268,8 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, imported_binding); } + ItemKind::GlobalAsm(..) => {} + ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root ItemKind::Mod(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c94f63329d1f..6ba214f20f98 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1709,7 +1709,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> { // do nothing, these are just around to be encoded } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3fd0ce45e361..3e8f7e11b6b4 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | + Def::GlobalAsm(_) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 44615071a56a..d822f7bea3a3 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -701,6 +701,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::SelfTy(..) | Def::Label(..) | Def::Macro(..) | + Def::GlobalAsm(..) | Def::Err => None, } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 500802a4135d..479c5b5a1d94 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -811,6 +811,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemDefaultImpl(..) | hir::ItemTrait(..) | diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 77ab076eba38..a7f9b66f659c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1074,6 +1074,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemTrait(..) | ItemMod(..) | ItemForeignMod(..) | + ItemGlobalAsm(..) | ItemExternCrate(..) | ItemUse(..) => { span_bug!( diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f0f543fa6f23..1bde1eea37c3 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -113,6 +113,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => {} diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 36352f50e440..890414e317c6 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -251,6 +251,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => {} } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c89ec5bbe15b..4252f2981ed6 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -373,6 +373,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } // If we're inlining, skip private items. _ if self.inlining && item.vis != hir::Public => {} + hir::ItemGlobalAsm(..) => {} hir::ItemExternCrate(ref p) => { let cstore = &self.cx.sess().cstore; om.extern_crates.push(ExternCrate { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c6a3e8a2dedc..131adfe47afd 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1585,6 +1585,15 @@ pub struct ForeignMod { pub items: Vec, } +/// Global inline assembly +/// +/// aka module-level assembly or file-scoped assembly +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub struct GlobalAsm { + pub asm: Symbol, + pub ctxt: SyntaxContext, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec, @@ -1812,6 +1821,8 @@ pub enum ItemKind { /// /// E.g. `extern {}` or `extern "C" {}` ForeignMod(ForeignMod), + /// Module-level inline assembly (from `global_asm!()`) + GlobalAsm(P), /// A type alias (`type` or `pub type`). /// /// E.g. `type Foo = Bar;` @@ -1864,6 +1875,7 @@ impl ItemKind { ItemKind::Fn(..) => "function", ItemKind::Mod(..) => "module", ItemKind::ForeignMod(..) => "foreign module", + ItemKind::GlobalAsm(..) => "global asm", ItemKind::Ty(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1b3352f73ade..48bfc050223a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1039,6 +1039,7 @@ impl<'feat> ExpansionConfig<'feat> { feature_tests! { fn enable_quotes = quote, fn enable_asm = asm, + fn enable_global_asm = global_asm, fn enable_log_syntax = log_syntax, fn enable_concat_idents = concat_idents, fn enable_trace_macros = trace_macros, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 08762ccf04bd..70e4f7a42b68 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -346,6 +346,9 @@ declare_features! ( // Hack to document `-Z linker-flavor` in The Unstable Book (active, linker_flavor, "1.18.0", Some(41142)), + + // Allows module-level inline assembly by way of global_asm!() + (active, global_asm, "1.18.0", Some(35119)), ); declare_features! ( @@ -982,6 +985,9 @@ pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; +pub const EXPLAIN_GLOBAL_ASM: &'static str = + "module-level inline assembly is experimental and subject to change"; + pub const EXPLAIN_LOG_SYNTAX: &'static str = "`log_syntax!` is not stable enough for use and is subject to change"; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 92e25b00e0ac..a6ab8e10d9f9 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -140,6 +140,10 @@ pub trait Folder : Sized { noop_fold_foreign_mod(nm, self) } + fn fold_global_asm(&mut self, ga: P) -> P { + noop_fold_global_asm(ga, self) + } + fn fold_variant(&mut self, v: Variant) -> Variant { noop_fold_variant(v, self) } @@ -412,6 +416,11 @@ pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, } } +pub fn noop_fold_global_asm(ga: P, + _: &mut T) -> P { + ga +} + pub fn noop_fold_variant(v: Variant, fld: &mut T) -> Variant { Spanned { node: Variant_ { @@ -867,6 +876,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), + ItemKind::GlobalAsm(ga) => ItemKind::GlobalAsm(folder.fold_global_asm(ga)), ItemKind::Ty(t, generics) => { ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics)) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e7feff2b79fc..433ba3d3693f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1267,6 +1267,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + ast::ItemKind::GlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global_asm!"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()?; + } ast::ItemKind::Ty(ref ty, ref params) => { self.ibox(INDENT_UNIT)?; self.ibox(0)?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index b5e9a1892acc..bae1c56db007 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -58,6 +58,7 @@ pub trait Visitor<'ast>: Sized { } fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) { walk_foreign_item(self, i) } + fn visit_global_asm(&mut self, ga: &'ast GlobalAsm) { walk_global_asm(self, ga) } fn visit_item(&mut self, i: &'ast Item) { walk_item(self, i) } fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } @@ -253,6 +254,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::ForeignMod(ref foreign_module) => { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } + ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga), ItemKind::Ty(ref typ, ref type_parameters) => { visitor.visit_ty(typ); visitor.visit_generics(type_parameters) @@ -464,6 +466,10 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a walk_list!(visitor, visit_attribute, &foreign_item.attrs); } +pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { + // Empty! +} + pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyParamBound) { match *bound { TraitTyParamBound(ref typ, ref modifier) => { diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs new file mode 100644 index 000000000000..d322d138f04c --- /dev/null +++ b/src/libsyntax_ext/global_asm.rs @@ -0,0 +1,66 @@ +// 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. + +/// Module-level assembly support. +/// +/// The macro defined here allows you to specify "top-level", +/// "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 +/// LLVM's `module asm "some assembly here"`. All of LLVM's caveats +/// therefore apply. + +use syntax::ast; +use syntax::ext::base; +use syntax::ext::base::*; +use syntax::codemap; +use syntax::feature_gate; +use syntax::ptr::P; +use syntax::symbol::Symbol; +use syntax_pos::Span; +use syntax::tokenstream; + +use syntax::util::small_vector::SmallVector; + +pub const MACRO: &'static str = "global_asm"; + +pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) -> Box { + if !cx.ecfg.enable_global_asm() { + feature_gate::emit_feature_err(&cx.parse_sess, + MACRO, + sp, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_GLOBAL_ASM); + return DummyResult::any(sp); + } + + let mut p = cx.new_parser_from_tts(tts); + let (asm, _) = match expr_to_string(cx, + panictry!(p.parse_expr()), + "inline assembly must be a string literal") { + Some((s, st)) => (s, st), + None => return DummyResult::any(sp), + }; + + MacEager::items(SmallVector::one(P(ast::Item { + ident: ast::Ident::with_empty_ctxt(Symbol::intern("")), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::GlobalAsm(P(ast::GlobalAsm { + asm: asm, + ctxt: cx.backtrace(), + })), + vis: ast::Visibility::Inherited, + span: sp, + }))) +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 1e9b112b6df5..e35e79df5852 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -38,6 +38,7 @@ mod concat_idents; mod env; mod format; mod format_foreign; +mod global_asm; mod log_syntax; mod trace_macros; @@ -99,6 +100,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, module_path: expand_mod, asm: asm::expand_asm, + global_asm: global_asm::expand_global_asm, cfg: cfg::expand_cfg, concat: concat::expand_syntax_ext, concat_idents: concat_idents::expand_syntax_ext, From 6bcd5b0980921a90367a3f8c4fbcd5b15fc4b3a5 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Thu, 16 Mar 2017 22:16:40 -0500 Subject: [PATCH 455/905] Expand _ into explicit variants in match --- src/librustc_typeck/collect.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a7f9b66f659c..649353d52f6a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -490,8 +490,10 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. - hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { - } + hir::ItemExternCrate(_) | + hir::ItemUse(..) | + hir::ItemMod(_) | + hir::ItemGlobalAsm(_) => {} hir::ItemForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { let def_id = tcx.hir.local_def_id(item.id); @@ -543,12 +545,12 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, - _ => { + } + hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, + } } } From 70fcff631821c4225d38315d7d85de92dbc477be Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 10:03:52 -0500 Subject: [PATCH 456/905] Add new TransItem for global_asm trans --- src/librustc_trans/asm.rs | 8 ++++++++ src/librustc_trans/collector.rs | 10 +++++++++- src/librustc_trans/partitioning.rs | 25 +++++++++++++++---------- src/librustc_trans/symbol_map.rs | 5 ++++- src/librustc_trans/trans_item.rs | 28 ++++++++++++++++++++++++++-- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 3e270b7928eb..577d6798ec3f 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -124,3 +124,11 @@ pub fn trans_inline_asm<'a, 'tcx>( llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1)); } } + +pub fn trans_global_asm<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ga: &hir::GlobalAsm) { + let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); + unsafe { + llvm::LLVMSetModuleInlineAsm(ccx.llmod(), asm.as_ptr()); + } +} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 479c5b5a1d94..ba2b807d5a01 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -349,6 +349,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, collect_neighbours(scx, instance, &mut neighbors); } + TransItem::GlobalAsm(..) => { + recursion_depth_reset = None; + } } record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map); @@ -811,7 +814,6 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemForeignMod(..) | - hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemDefaultImpl(..) | hir::ItemTrait(..) | @@ -841,6 +843,12 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { } } } + hir::ItemGlobalAsm(..) => { + debug!("RootCollector: ItemGlobalAsm({})", + def_id_to_string(self.scx.tcx(), + self.scx.tcx().hir.local_def_id(item.id))); + self.output.push(TransItem::GlobalAsm(item.id)); + } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", def_id_to_string(self.scx.tcx(), diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 90ce40cfbcf8..4973181202ee 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -185,15 +185,16 @@ impl<'tcx> CodegenUnit<'tcx> { symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); let exported = match item { - TransItem::Fn(ref instance) => { - let node_id = - scx.tcx().hir.as_local_node_id(instance.def_id()); + TransItem::Fn(ref instance) => { + let node_id = + scx.tcx().hir.as_local_node_id(instance.def_id()); node_id.map(|node_id| exported_symbols.contains(&node_id)) - .unwrap_or(false) - } - TransItem::Static(node_id) => { + .unwrap_or(false) + } + TransItem::Static(node_id) => { exported_symbols.contains(&node_id) - } + } + TransItem::GlobalAsm(..) => true, }; exported.hash(&mut state); } @@ -243,7 +244,9 @@ impl<'tcx> CodegenUnit<'tcx> { TransItem::Fn(instance) => { tcx.hir.as_local_node_id(instance.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { + Some(node_id) + } } } } @@ -338,7 +341,8 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, None => { match trans_item { TransItem::Fn(..) | - TransItem::Static(..) => llvm::ExternalLinkage, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => llvm::ExternalLinkage, } } }; @@ -483,7 +487,8 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't Some(def_id) } - TransItem::Static(node_id) => Some(tcx.hir.local_def_id(node_id)), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 1b48e131b720..36c3981e3a6f 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -99,7 +99,10 @@ impl<'tcx> SymbolMap<'tcx> { TransItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => { + Some(node_id) + } }.map(|node_id| { tcx.hir.span(node_id) }) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 410e3f30be73..f5556bb8382f 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -14,6 +14,7 @@ //! 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; @@ -38,7 +39,8 @@ use std::iter; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { Fn(Instance<'tcx>), - Static(NodeId) + Static(NodeId), + GlobalAsm(NodeId), } /// Describes how a translation item will be instantiated in object files. @@ -89,6 +91,14 @@ impl<'a, 'tcx> TransItem<'tcx> { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") } } + TransItem::GlobalAsm(node_id) => { + let item = ccx.tcx().hir.expect_item(node_id); + if let hir::ItemGlobalAsm(ref ga) = item.node { + asm::trans_global_asm(ccx, ga); + } else { + span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") + } + } TransItem::Fn(instance) => { let _task = ccx.tcx().dep_graph.in_task( DepNode::TransCrateItem(instance.def_id())); // (*) @@ -123,6 +133,7 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(instance) => { TransItem::predefine_fn(ccx, instance, linkage, &symbol_name); } + TransItem::GlobalAsm(..) => {} } debug!("END PREDEFINING '{} ({})' in cgu {}", @@ -185,6 +196,10 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = scx.tcx().hir.local_def_id(node_id); symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) } + TransItem::GlobalAsm(node_id) => { + let def_id = scx.tcx().hir.local_def_id(node_id); + format!("global_asm_{:?}", def_id) + } } } @@ -202,6 +217,7 @@ impl<'a, 'tcx> TransItem<'tcx> { } } TransItem::Static(..) => InstantiationMode::GloballyShared, + TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared, } } @@ -210,7 +226,8 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(ref instance) => { instance.substs.types().next().is_some() } - TransItem::Static(..) => false, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => false, } } @@ -218,6 +235,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = match *self { TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), + TransItem::GlobalAsm(..) => return None, }; let attributes = tcx.get_attrs(def_id); @@ -249,6 +267,9 @@ impl<'a, 'tcx> TransItem<'tcx> { let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, + TransItem::GlobalAsm(..) => { + "global_asm".to_string() + } }; fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -273,6 +294,9 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Static(id) => { format!("Static({:?})", id) } + TransItem::GlobalAsm(id) => { + format!("GlobalAsm({:?})", id) + } } } } From 7be5043fd99308135bcd0443f8af6d7e012e4148 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 29 Mar 2017 23:32:20 -0500 Subject: [PATCH 457/905] Ensure walk_item visits GlobalAsm NodeId Travis failures indicated the OuterVisitor#visit_item method caused a panic. The Visitor's inner visitor actually relies on the visitor visiting every item's NodeId. I forgot to perform that call in the ItemGlobalAsm match arm, leading to build breakage. The fix is simple: call visit_id(...) for ItemGlobalAsm --- src/librustc/hir/intravisit.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9615ed4af069..2b0d53b2bc35 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -474,7 +474,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } - ItemGlobalAsm(_) => {} + ItemGlobalAsm(_) => { + visitor.visit_id(item.id); + } ItemTy(ref typ, ref type_parameters) => { visitor.visit_id(item.id); visitor.visit_ty(typ); From 9240054b3ee5690b6c75bebdb6316a14bdd46340 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 19:50:23 -0500 Subject: [PATCH 458/905] Expose LLVM appendModuleInlineAsm --- src/librustc_llvm/ffi.rs | 1 + src/librustc_trans/asm.rs | 2 +- src/rustllvm/RustWrapper.cpp | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 32c9183ece99..402166cc13fd 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -507,6 +507,7 @@ extern "C" { /// See Module::setModuleInlineAsm. pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); + pub fn LLVMRustAppendModuleInlineAsm(M: ModuleRef, Asm: *const c_char); /// See llvm::LLVMTypeKind::getTypeID. pub fn LLVMRustGetTypeKind(Ty: TypeRef) -> TypeKind; diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 577d6798ec3f..92cbd004206e 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -129,6 +129,6 @@ pub fn trans_global_asm<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ga: &hir::GlobalAsm) { let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); unsafe { - llvm::LLVMSetModuleInlineAsm(ccx.llmod(), asm.as_ptr()); + llvm::LLVMRustAppendModuleInlineAsm(ccx.llmod(), asm.as_ptr()); } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5ab786f40b93..c24867224ea8 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -312,6 +312,10 @@ extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, HasSideEffects, IsAlignStack, fromRust(Dialect))); } +extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) { + unwrap(M)->appendModuleInlineAsm(StringRef(Asm)); +} + typedef DIBuilder *LLVMRustDIBuilderRef; typedef struct LLVMOpaqueMetadata *LLVMRustMetadataRef; From 4b9de4cc6327b8c72716b1102a7db4f0858a76db Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 10:02:14 -0500 Subject: [PATCH 459/905] Update unstable book with global_asm feature --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/asm.md | 2 + src/doc/unstable-book/src/global_asm.md | 78 +++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/doc/unstable-book/src/global_asm.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 54e602a81db7..8221d22eaac7 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -83,6 +83,7 @@ - [future_atomic_orderings](future-atomic-orderings.md) - [generic_param_attrs](generic-param-attrs.md) - [get_type_id](get-type-id.md) +- [global_asm](global_asm.md) - [heap_api](heap-api.md) - [i128](i128.md) - [i128_type](i128-type.md) diff --git a/src/doc/unstable-book/src/asm.md b/src/doc/unstable-book/src/asm.md index 032d9d812402..5e68be633e7a 100644 --- a/src/doc/unstable-book/src/asm.md +++ b/src/doc/unstable-book/src/asm.md @@ -189,3 +189,5 @@ constraints, etc. [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions +If you need more power and don't mind losing some of the niceties of +`asm!`, check out [global_asm](global_asm.html). diff --git a/src/doc/unstable-book/src/global_asm.md b/src/doc/unstable-book/src/global_asm.md new file mode 100644 index 000000000000..f092a4ad6640 --- /dev/null +++ b/src/doc/unstable-book/src/global_asm.md @@ -0,0 +1,78 @@ +# `global_asm` + +The tracking issue for this feature is: [#35119] + +[#35119]: https://github.com/rust-lang/rust/issues/35119 + +------------------------ + +The `global_asm!` macro allows the programmer to write arbitrary +assembly outside the scope of a function body, passing it through +`rustc` and `llvm` to the assembler. The macro is a no-frills +interface to LLVM's concept of [module-level inline assembly]. That is, +all caveats applicable to LLVM's module-level inline assembly apply +to `global_asm!`. + +[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly + +`global_asm!` fills a role not currently satisfied by either `asm!` +or `#[naked]` functions. The programmer has _all_ features of the +assembler at their disposal. The linker will expect to resolve any +symbols defined in the inline assembly, modulo any symbols marked as +external. It also means syntax for directives and assembly follow the +conventions of the assembler in your toolchain. + +A simple usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# you also need relevant target_arch cfgs +global_asm!(include_str("something_neato.s")); +``` + +And a more complicated usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + +pub mod sally { + global_asm!(r#" + .global foo + foo: + jmp baz + "#); + + #[no_mangle] + pub unsafe extern "C" fn baz() {} +} + +// the symbols `foo` and `bar` are global, no matter where +// `global_asm!` was used. +extern "C" { + fn foo(); + fn bar(); +} + +pub mod harry { + global_asm!(r#" + .global bar + bar: + jmp quux + "#); + + #[no_mangle] + pub unsafe extern "C" fn quux() {} +} +``` + +You may use `global_asm!` multiple times, anywhere in your crate, in +whatever way suits you. The effect is as if you concatenated all +usages and placed the larger, single usage in the crate root. + +------------------------ + +If you don't need quite as much power and flexibility as +`global_asm!` provides, and you don't mind restricting your inline +assembly to `fn` bodies only, you might try the [asm](asm.html) +feature instead. From da0742c0707225c796c1710d5f97b58a5bc5a864 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 23:47:25 -0500 Subject: [PATCH 460/905] Add global_asm tests --- src/doc/unstable-book/src/global_asm.md | 2 +- src/librustc_driver/test.rs | 1 + src/libsyntax/feature_gate.rs | 2 +- src/test/codegen/foo.s | 3 + src/test/codegen/global_asm.rs | 73 +++++++++++++++ src/test/codegen/global_asm_include.rs | 68 ++++++++++++++ src/test/codegen/global_asm_x2.rs | 90 +++++++++++++++++++ .../compile-fail/feature-gate-global_asm.rs | 15 ++++ src/test/run-pass/empty_global_asm.rs | 28 ++++++ src/test/run-pass/simple_global_asm.rs | 27 ++++++ 10 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 src/test/codegen/foo.s create mode 100644 src/test/codegen/global_asm.rs create mode 100644 src/test/codegen/global_asm_include.rs create mode 100644 src/test/codegen/global_asm_x2.rs create mode 100644 src/test/compile-fail/feature-gate-global_asm.rs create mode 100644 src/test/run-pass/empty_global_asm.rs create mode 100644 src/test/run-pass/simple_global_asm.rs diff --git a/src/doc/unstable-book/src/global_asm.md b/src/doc/unstable-book/src/global_asm.md index f092a4ad6640..44921aa309f8 100644 --- a/src/doc/unstable-book/src/global_asm.md +++ b/src/doc/unstable-book/src/global_asm.md @@ -27,7 +27,7 @@ A simple usage looks like this: ```rust,ignore # #![feature(global_asm)] # you also need relevant target_arch cfgs -global_asm!(include_str("something_neato.s")); +global_asm!(include_str!("something_neato.s")); ``` And a more complicated usage looks like this: diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index af2416f787ea..44e291a44c77 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -233,6 +233,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => None, hir::ItemEnum(..) | diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 70e4f7a42b68..8b62416dcbdb 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -986,7 +986,7 @@ pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; pub const EXPLAIN_GLOBAL_ASM: &'static str = - "module-level inline assembly is experimental and subject to change"; + "`global_asm!` is not stable enough for use and is subject to change"; pub const EXPLAIN_LOG_SYNTAX: &'static str = "`log_syntax!` is not stable enough for use and is subject to change"; diff --git a/src/test/codegen/foo.s b/src/test/codegen/foo.s new file mode 100644 index 000000000000..304d82aa0c65 --- /dev/null +++ b/src/test/codegen/foo.s @@ -0,0 +1,3 @@ +.global foo +foo: + jmp baz diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs new file mode 100644 index 000000000000..5bd0c1b4076e --- /dev/null +++ b/src/test/codegen/global_asm.rs @@ -0,0 +1,73 @@ +// 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. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// this regex will capture the correct unconditional branch inst. +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs new file mode 100644 index 000000000000..401b1fad566d --- /dev/null +++ b/src/test/codegen/global_asm_include.rs @@ -0,0 +1,68 @@ +// 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. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(include_str!("foo.s")); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs new file mode 100644 index 000000000000..8b59165e9e61 --- /dev/null +++ b/src/test/codegen/global_asm_x2.rs @@ -0,0 +1,90 @@ +// 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. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] +#[no_std] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +// any other global_asm will be appended to this first block, so: +// CHECK-LABEL: bar +// CHECK: module asm "{{[[:space:]]+}}jmp quux" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} + +// no checks here; this has been appended to the first occurrence +global_asm!(r#" + .global bar +bar: + jmp quux +"#); + +extern "C" { + fn bar(); +} + +#[no_mangle] +pub unsafe extern "C" fn quux() {} diff --git a/src/test/compile-fail/feature-gate-global_asm.rs b/src/test/compile-fail/feature-gate-global_asm.rs new file mode 100644 index 000000000000..0560abb6af49 --- /dev/null +++ b/src/test/compile-fail/feature-gate-global_asm.rs @@ -0,0 +1,15 @@ +// 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-global_asm + +global_asm!(""); //~ ERROR `global_asm!` is not stable + +fn main() {} diff --git a/src/test/run-pass/empty_global_asm.rs b/src/test/run-pass/empty_global_asm.rs new file mode 100644 index 000000000000..db73da2747f9 --- /dev/null +++ b/src/test/run-pass/empty_global_asm.rs @@ -0,0 +1,28 @@ +// 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(global_asm)] + +#[cfg(target_arch = "x86")] +global_asm!(""); + +#[cfg(target_arch = "x86_64")] +global_asm!(""); + +#[cfg(target_arch = "arm")] +global_asm!(""); + +#[cfg(target_arch = "aarch64")] +global_asm!(""); + +#[cfg(target_arch = "mips")] +global_asm!(""); + +fn main() {} diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs new file mode 100644 index 000000000000..a5ffe607fdf8 --- /dev/null +++ b/src/test/run-pass/simple_global_asm.rs @@ -0,0 +1,27 @@ +// 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(global_asm)] + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern { + fn foo(); +} + +#[no_mangle] +pub extern fn baz() {} + +fn main() {} From 24a89a015e93afb473c267dbddc5c856d62a639c Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 5 Apr 2017 22:12:02 -0500 Subject: [PATCH 461/905] Replace ExpnId with SyntaxContext --- src/libsyntax_ext/global_asm.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index d322d138f04c..dc67e1c45f6e 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -21,7 +21,6 @@ use syntax::ast; use syntax::ext::base; use syntax::ext::base::*; -use syntax::codemap; use syntax::feature_gate; use syntax::ptr::P; use syntax::symbol::Symbol; From 7ec27ae63d762234ad768fb605bd40bbbc52c7a0 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 1 Apr 2017 19:33:45 -0700 Subject: [PATCH 462/905] Add ToOwned::clone_into (unstable as toowned_clone_into) to_owned generalizes clone; this generalizes clone_from. Use to_owned to give it a default impl. Customize the impl for [T], str, and T:Clone. Use it in Cow::clone_from to reuse resources when cloning Owned into Owned. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../unstable-book/src/toowned-clone-into.md | 7 ++++ src/libcollections/borrow.rs | 38 +++++++++++++++++++ src/libcollections/slice.rs | 13 +++++++ src/libcollections/str.rs | 6 +++ src/libcollections/tests/cow_str.rs | 10 +++++ src/libcollections/vec.rs | 11 +----- 7 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 src/doc/unstable-book/src/toowned-clone-into.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9ce097e78a4e..2e9810c438d0 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -193,6 +193,7 @@ - [thread_local](thread-local.md) - [thread_local_internals](thread-local-internals.md) - [thread_local_state](thread-local-state.md) +- [toowned_clone_into](toowned-clone-into.md) - [trace_macros](trace-macros.md) - [trusted_len](trusted-len.md) - [try_from](try-from.md) diff --git a/src/doc/unstable-book/src/toowned-clone-into.md b/src/doc/unstable-book/src/toowned-clone-into.md new file mode 100644 index 000000000000..eccc7e0e4dda --- /dev/null +++ b/src/doc/unstable-book/src/toowned-clone-into.md @@ -0,0 +1,7 @@ +# `toowned_clone_into` + +The tracking issue for this feature is: [#41263] + +[#41263]: https://github.com/rust-lang/rust/issues/41263 + +------------------------ diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 65056121f05a..0de52b6696fc 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -60,6 +60,29 @@ pub trait ToOwned { /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn to_owned(&self) -> Self::Owned; + + /// Uses borrowed data to replace owned data, usually by cloning. + /// + /// This is borrow-generalized version of `Clone::clone_from`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(toowned_clone_into)] + /// let mut s: String = String::new(); + /// "hello".clone_into(&mut s); + /// + /// let mut v: Vec = Vec::new(); + /// [1, 2][..].clone_into(&mut v); + /// ``` + #[unstable(feature = "toowned_clone_into", + reason = "recently added", + issue = "41263")] + fn clone_into(&self, target: &mut Self::Owned) { + *target = self.to_owned(); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -70,6 +93,10 @@ impl ToOwned for T fn to_owned(&self) -> T { self.clone() } + + fn clone_into(&self, target: &mut T) { + target.clone_from(self); + } } /// A clone-on-write smart pointer. @@ -141,6 +168,17 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> } } } + + fn clone_from(&mut self, source: &Cow<'a, B>) { + if let Owned(ref mut dest) = *self { + if let Owned(ref o) = *source { + o.borrow().clone_into(dest); + return; + } + } + + *self = source.clone(); + } } impl<'a, B: ?Sized> Cow<'a, B> diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6cff315a6ccd..f7e0f0395e7f 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1527,6 +1527,19 @@ impl ToOwned for [T] { fn to_owned(&self) -> Vec { panic!("not available with cfg(test)") } + + fn clone_into(&self, target: &mut Vec) { + // drop anything in target that will not be overwritten + target.truncate(self.len()); + let len = target.len(); + + // reuse the contained values' allocations/resources. + target.clone_from_slice(&self[..len]); + + // target.len <= self.len due to the truncate above, so the + // slice here is always in-bounds. + target.extend_from_slice(&self[len..]); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c37a4fa6b557..8d4b3a247e29 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -199,6 +199,12 @@ impl ToOwned for str { 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. diff --git a/src/libcollections/tests/cow_str.rs b/src/libcollections/tests/cow_str.rs index b29245121daa..aa87ee84b3e9 100644 --- a/src/libcollections/tests/cow_str.rs +++ b/src/libcollections/tests/cow_str.rs @@ -139,3 +139,13 @@ fn check_cow_add_assign_str() { assert_eq!("Hi, World!", owned); assert_eq!("Hello, World!", borrowed); } + +#[test] +fn check_cow_clone_from() { + let mut c1: Cow = Cow::Owned(String::with_capacity(25)); + let s: String = "hi".to_string(); + assert!(s.capacity() < 25); + let c2: Cow = Cow::Owned(s); + c1.clone_from(&c2); + assert!(c1.into_owned().capacity() >= 25); +} \ No newline at end of file diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c258ac2bdea9..3d11b4f80fb6 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1396,16 +1396,7 @@ impl Clone for Vec { } fn clone_from(&mut self, other: &Vec) { - // drop anything in self that will not be overwritten - self.truncate(other.len()); - let len = self.len(); - - // reuse the contained values' allocations/resources. - self.clone_from_slice(&other[..len]); - - // self.len <= other.len due to the truncate above, so the - // slice here is always in-bounds. - self.extend_from_slice(&other[len..]); + other.as_slice().clone_into(self); } } From a50737051abdc943f96c6e89a732fd00e58248e8 Mon Sep 17 00:00:00 2001 From: alexey zabelin Date: Wed, 12 Apr 2017 20:46:44 -0400 Subject: [PATCH 463/905] Fix old docs #41158 --- src/doc/grammar.md | 8 ++++++++ src/libsyntax/parse/parser.rs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 8e803aff4d6f..239afd41f023 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -780,6 +780,14 @@ never_type : "!" ; **FIXME:** grammar? +### Type parameter bounds + +```antlr +bound := ty_bound | lt_bound +lt_bound := lifetime +ty_bound := [?] [ for ] simple_path +``` + ### Self types **FIXME:** grammar? diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3b928ea93c78..5cacb0da9e5d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4066,7 +4066,7 @@ impl<'a> Parser<'a> { }).emit(); } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) @@ -4107,7 +4107,7 @@ impl<'a> Parser<'a> { self.parse_ty_param_bounds_common(true) } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec { let mut lifetimes = Vec::new(); From f84cc0c0d0ff24e4cce5d05be3afd0347eb9d012 Mon Sep 17 00:00:00 2001 From: projektir Date: Wed, 12 Apr 2017 21:33:49 -0400 Subject: [PATCH 464/905] Updating docs for std::rc::Rc --- src/liballoc/rc.rs | 66 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 561ccaa5ef5c..fed718e9be4c 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -922,18 +922,29 @@ impl From for Rc { } } -/// A weak version of [`Rc`][rc]. +/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Rc`]`>`. /// -/// `Weak` pointers do not count towards determining if the inner value -/// should be dropped. +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. /// -/// The typical way to obtain a `Weak` pointer is to call -/// [`Rc::downgrade`][downgrade]. +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Rc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Rc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Rc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. /// -/// See the [module-level documentation](./index.html) for more details. +/// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. /// -/// [rc]: struct.Rc.html -/// [downgrade]: struct.Rc.html#method.downgrade +/// [`Rc`]: struct.Rc.html +/// [`Rc::downgrade`]: struct.Rc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -948,14 +959,11 @@ impl !marker::Sync for Weak {} impl, U: ?Sized> CoerceUnsized> for Weak {} impl Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -980,13 +988,13 @@ impl Weak { } impl Weak { - /// Upgrades the `Weak` pointer to an [`Rc`][rc], if possible. + /// Attempts to upgrade the `Weak` pointer to an [`Rc`], extending + /// the lifetime of the value if successful. /// - /// Returns [`None`][option] if the strong count has reached zero and the - /// inner value was destroyed. + /// Returns [`None`] if the value has since been dropped. /// - /// [rc]: struct.Rc.html - /// [option]: ../../std/option/enum.Option.html + /// [`Rc`]: struct.Rc.html + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -1021,8 +1029,6 @@ impl Weak { impl Drop for Weak { /// Drops the `Weak` pointer. /// - /// This will decrement the weak reference count. - /// /// # Examples /// /// ``` @@ -1061,10 +1067,7 @@ impl Drop for Weak { #[stable(feature = "rc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// weak reference count. + /// Makes a clone of the `Weak` pointer that points to the same value. /// /// # Examples /// @@ -1091,14 +1094,11 @@ impl fmt::Debug for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// From cdedecb7baa55a7e9c1aa78d5d7313b94e3e84b1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 12 Apr 2017 20:48:18 -0700 Subject: [PATCH 465/905] travis: Enable rust-analysis package for more targets This commit enables the `rust-analysis` package to be produced for all targets that are part of the `dist-*` suite of docker images on Travis. Currently these packages are showing up with `available = false` in the `channel-rust-nightly.toml` manifest where we'd prefer to have them show up for all targets. Unfortunately rustup isn't handling the `available = false` section well right now, so this should also inadvertently fix the nightly regression. --- src/bootstrap/step.rs | 1 + src/ci/docker/cross/Dockerfile | 1 + src/ci/docker/dist-android/Dockerfile | 1 + src/ci/docker/dist-fuchsia/Dockerfile | 2 +- src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile | 3 ++- src/ci/docker/dist-x86_64-musl/Dockerfile | 3 ++- 6 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 596cbcf01bb8..bdc2a30663cb 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -700,6 +700,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("dist-analysis", "analysis") + .default(build.config.extended) .dep(|s| s.name("dist-std")) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 7c1984410078..02d4eaf534ac 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -74,6 +74,7 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ ENV STAGING_DIR=/tmp ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ --target=$TARGETS \ --musl-root-arm=/usr/local/arm-linux-musleabi \ --musl-root-armhf=/usr/local/arm-linux-musleabihf \ diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 31f4b8b777be..99c176aa820c 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -42,6 +42,7 @@ ENV TARGETS=$TARGETS,armv7-linux-androideabi ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ + --enable-extended \ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ --i686-linux-android-ndk=/android/ndk-x86-9 \ diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index 4a401bbb3031..294460ed7604 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -44,5 +44,5 @@ ENV \ ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia -ENV RUST_CONFIGURE_ARGS --target=$TARGETS +ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index d2727cbdb350..1ef3e569cb4b 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -31,7 +31,8 @@ RUN curl -o /usr/local/bin/sccache \ ENV RUST_CONFIGURE_ARGS \ --target=i686-unknown-linux-musl,i586-unknown-linux-gnu \ - --musl-root-i686=/musl-i686 + --musl-root-i686=/musl-i686 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index a41c0cca3b5f..f462ccbb9119 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -31,7 +31,8 @@ RUN curl -o /usr/local/bin/sccache \ ENV RUST_CONFIGURE_ARGS \ --target=x86_64-unknown-linux-musl \ - --musl-root-x86_64=/musl-x86_64 + --musl-root-x86_64=/musl-x86_64 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our From 63a074791e587fa2cbb9d1b2bfdd08e08a001d9f Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Fri, 7 Apr 2017 09:46:34 -0500 Subject: [PATCH 466/905] Make simple_global_asm even simpler Windows builder croaked. This change tries to fix that by actually calling the global_asm-defined function so the symbol doesn't get optimized away, if that is in fact what was happening. Additionally, we provide an empty main() for non-x86 arches. --- src/librustc/ich/impls_hir.rs | 3 +++ src/librustc_metadata/schema.rs | 1 + src/test/run-pass/simple_global_asm.rs | 8 +++++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 5b8dc96f013c..82e03a9fddc3 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -881,6 +881,7 @@ impl<'a, 'tcx> HashStable> for hir::Item { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemEnum(..) | hir::ItemStruct(..) | @@ -925,6 +926,7 @@ impl_stable_hash_for!(enum hir::Item_ { ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), ItemMod(module), ItemForeignMod(foreign_mod), + ItemGlobalAsm(global_asm), ItemTy(ty, generics), ItemEnum(enum_def, generics), ItemStruct(variant_data, generics), @@ -1083,6 +1085,7 @@ impl_stable_hash_for!(enum hir::def::Def { Upvar(def_id, index, expr_id), Label(node_id), Macro(def_id, macro_kind), + GlobalAsm(def_id), Err }); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index ae20dd1a554b..6cd35f1335ed 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -298,6 +298,7 @@ impl<'a, 'tcx> HashStable> for EntryKind<'tcx> { EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignMod | + EntryKind::GlobalAsm | EntryKind::Field | EntryKind::Type => { // Nothing else to hash here. diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs index a5ffe607fdf8..ac2cacf3db21 100644 --- a/src/test/run-pass/simple_global_asm.rs +++ b/src/test/run-pass/simple_global_asm.rs @@ -9,19 +9,21 @@ // except according to those terms. #![feature(global_asm)] +#![feature(naked_functions)] #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] global_asm!(r#" .global foo foo: - jmp baz + ret "#); extern { fn foo(); } -#[no_mangle] -pub extern fn baz() {} +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +fn main() { unsafe { foo(); } } +#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] fn main() {} From 14eac29753efd5a5e8ded83a2c8ae8e44e914320 Mon Sep 17 00:00:00 2001 From: alexey zabelin Date: Thu, 13 Apr 2017 09:53:22 -0400 Subject: [PATCH 467/905] Address the PR review --- src/doc/grammar.md | 3 +-- src/libsyntax/parse/parser.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 239afd41f023..3fbf9f06d99f 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -761,8 +761,6 @@ closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|' [ ':' bound-list ] [ '->' type ] lifetime-list := lifetime | lifetime ',' lifetime-list arg-list := ident ':' type | ident ':' type ',' arg-list -bound-list := bound | bound '+' bound-list -bound := path | lifetime ``` ### Never type @@ -786,6 +784,7 @@ never_type : "!" ; bound := ty_bound | lt_bound lt_bound := lifetime ty_bound := [?] [ for ] simple_path +bound-list := bound | bound '+' bound-list '+' ? ``` ### Self types diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5cacb0da9e5d..0fddbca72cdc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4066,7 +4066,7 @@ impl<'a> Parser<'a> { }).emit(); } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. + // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) @@ -4107,7 +4107,7 @@ impl<'a> Parser<'a> { self.parse_ty_param_bounds_common(true) } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. + // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec { let mut lifetimes = Vec::new(); From 368d56010ae91a8b136c9eea5821ff3e5a7b79d3 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 12 Apr 2017 19:04:57 -0400 Subject: [PATCH 468/905] Rename compiler_barrier to compiler_fence This addresses concerns raised following the merge of #41092. Specifically: > The naming of these seems surprising: the multithreaded functions (and > both the single and multithreaded intrinsics themselves) are fences, > but this is a barrier. It's not incorrect, but the latter is both > inconsistent with the existing functions and slightly confusing with > another type in std (e.g., `Barrier`). `compiler_fence` carries the same semantic implication that this is a compiler-only operation, while being more in line with the fence/barrier concepts already in use in `std`. --- src/doc/unstable-book/src/SUMMARY.md | 2 +- ...ompiler-barriers.md => compiler-fences.md} | 20 +++++++++---------- src/libcore/sync/atomic.rs | 12 +++++------ 3 files changed, 17 insertions(+), 17 deletions(-) rename src/doc/unstable-book/src/{compiler-barriers.md => compiler-fences.md} (86%) diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 54e602a81db7..b0cb444beaf7 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -38,7 +38,7 @@ - [collections](collections.md) - [collections_range](collections-range.md) - [command_envs](command-envs.md) -- [compiler_barriers](compiler-barriers.md) +- [compiler_fences](compiler-fences.md) - [compiler_builtins](compiler-builtins.md) - [compiler_builtins_lib](compiler-builtins-lib.md) - [concat_idents](concat-idents.md) diff --git a/src/doc/unstable-book/src/compiler-barriers.md b/src/doc/unstable-book/src/compiler-fences.md similarity index 86% rename from src/doc/unstable-book/src/compiler-barriers.md rename to src/doc/unstable-book/src/compiler-fences.md index 827447f0bd51..b1e36ab13d5a 100644 --- a/src/doc/unstable-book/src/compiler-barriers.md +++ b/src/doc/unstable-book/src/compiler-fences.md @@ -1,4 +1,4 @@ -# `compiler_barriers` +# `compiler_fences` The tracking issue for this feature is: [#41091] @@ -6,7 +6,7 @@ The tracking issue for this feature is: [#41091] ------------------------ -The `compiler_barriers` feature exposes the `compiler_barrier` function +The `compiler_fences` feature exposes the `compiler_fence` function in `std::sync::atomic`. This function is conceptually similar to C++'s `atomic_signal_fence`, which can currently only be accessed in nightly Rust using the `atomic_singlethreadfence_*` instrinsic functions in @@ -17,18 +17,18 @@ Rust using the `atomic_singlethreadfence_*` instrinsic functions in unsafe { asm!("" ::: "memory" : "volatile") }; ``` -A `compiler_barrier` restricts the kinds of memory re-ordering the +A `compiler_fence` restricts the kinds of memory re-ordering the compiler is allowed to do. Specifically, depending on the given ordering semantics, the compiler may be disallowed from moving reads or writes from before or after the call to the other side of the call to -`compiler_barrier`. Note that it does **not** prevent the *hardware* +`compiler_fence`. Note that it does **not** prevent the *hardware* from doing such re-ordering. This is not a problem in a single-threaded, execution context, but when other threads may modify memory at the same time, stronger synchronization primitives are required. ## Examples -`compiler_barrier` is generally only useful for preventing a thread from +`compiler_fence` is generally only useful for preventing a thread from racing *with itself*. That is, if a given thread is executing one piece of code, and is then interrupted, and starts executing code elsewhere (while still in the same thread, and conceptually still on the same @@ -37,7 +37,7 @@ handler is registered. In more low-level code, such situations can also arise when handling interrupts, when implementing green threads with pre-emption, etc. -To give a straightforward example of when a `compiler_barrier` is +To give a straightforward example of when a `compiler_fence` is necessary, consider the following example: ```rust @@ -67,14 +67,14 @@ remember that the compiler is free to swap the stores to after `IS_READY` is updated, then the signal handler will see `IS_READY=1`, but `IMPORTANT_VARIABLE=0`. -Using a `compiler_barrier`, we can remedy this situation: +Using a `compiler_fence`, we can remedy this situation: ```rust -#![feature(compiler_barriers)] +#![feature(compiler_fences)] # use std::sync::atomic::{AtomicBool, AtomicUsize}; # use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; # use std::sync::atomic::Ordering; -use std::sync::atomic::compiler_barrier; +use std::sync::atomic::compiler_fence; static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; @@ -82,7 +82,7 @@ static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; fn main() { IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); // prevent earlier writes from being moved beyond this point - compiler_barrier(Ordering::Release); + compiler_fence(Ordering::Release); IS_READY.store(true, Ordering::Relaxed); } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 0c70524ead24..fad58deecd4c 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1591,11 +1591,11 @@ pub fn fence(order: Ordering) { } -/// A compiler memory barrier. +/// A compiler memory fence. /// -/// `compiler_barrier` does not emit any machine code, but prevents the compiler from re-ordering +/// `compiler_fence` does not emit any machine code, but prevents the compiler from re-ordering /// memory operations across this point. Which reorderings are disallowed is dictated by the given -/// [`Ordering`]. Note that `compiler_barrier` does *not* introduce inter-thread memory +/// [`Ordering`]. Note that `compiler_fence` does *not* introduce inter-thread memory /// synchronization; for that, a [`fence`] is needed. /// /// The re-ordering prevented by the different ordering semantics are: @@ -1617,15 +1617,15 @@ pub fn fence(order: Ordering) { /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed #[inline] -#[unstable(feature = "compiler_barriers", issue = "41091")] -pub fn compiler_barrier(order: Ordering) { +#[unstable(feature = "compiler_fences", issue = "41091")] +pub fn compiler_fence(order: Ordering) { unsafe { match order { Acquire => intrinsics::atomic_singlethreadfence_acq(), Release => intrinsics::atomic_singlethreadfence_rel(), AcqRel => intrinsics::atomic_singlethreadfence_acqrel(), SeqCst => intrinsics::atomic_singlethreadfence(), - Relaxed => panic!("there is no such thing as a relaxed barrier"), + Relaxed => panic!("there is no such thing as a relaxed compiler fence"), __Nonexhaustive => panic!("invalid memory ordering"), } } From 2a3355920777956d537db7a0f4c278a280af9abb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 11 Apr 2017 11:58:25 -0700 Subject: [PATCH 469/905] rustbuild: Fix recompilation of stage0 tools dir This commit knocks out a longstanding FIXME in rustbuild which should correctly recompile stage0 compiletest and such whenever libstd itself changes. The solution implemented here was to implement a notion of "order only" dependencies and then add a new dependency stage for clearing out the tools dir, using order-only deps to ensure that it happens correctly. The dependency drawing for tools is a bit wonky now but I think this'll get the job done. Closes #39396 --- src/bootstrap/compile.rs | 33 ++++++-- src/bootstrap/step.rs | 176 +++++++++++++++++++++++++++++++-------- 2 files changed, 167 insertions(+), 42 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index eeec7eb029e5..bddd570a13d2 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -275,6 +275,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) { cargo.env("CFG_DEFAULT_AR", s); } build.run(&mut cargo); + update_mtime(build, &librustc_stamp(build, compiler, target)); } /// Same as `std_link`, only for librustc @@ -305,6 +306,12 @@ fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") } +/// Cargo's output path for librustc in a given stage, compiled by a particular +/// compiler for the specified target. +fn librustc_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") +} + fn compiler_file(compiler: &Path, file: &str) -> PathBuf { let out = output(Command::new(compiler) .arg(format!("-print-file-name={}", file))); @@ -407,6 +414,23 @@ fn add_to_sysroot(out_dir: &Path, sysroot_dst: &Path) { } } +/// Build a tool in `src/tools` +/// +/// This will build the specified tool with the specified `host` compiler in +/// `stage` into the normal cargo output directory. +pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) { + let compiler = Compiler::new(stage, &build.config.build); + + let stamp = match mode { + Mode::Libstd => libstd_stamp(build, &compiler, target), + Mode::Libtest => libtest_stamp(build, &compiler, target), + Mode::Librustc => librustc_stamp(build, &compiler, target), + _ => panic!(), + }; + let out_dir = build.cargo_out(&compiler, Mode::Tool, target); + build.clear_if_dirty(&out_dir, &stamp); +} + /// Build a tool in `src/tools` /// /// This will build the specified tool with the specified `host` compiler in @@ -416,15 +440,6 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) { let compiler = Compiler::new(stage, &build.config.build); - // FIXME: need to clear out previous tool and ideally deps, may require - // isolating output directories or require a pseudo shim step to - // clear out all the info. - // - // Maybe when libstd is compiled it should clear out the rustc of the - // corresponding stage? - // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); - // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); - let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build"); let mut dir = build.src.join(tool); if !dir.exists() { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index bdc2a30663cb..6008fa81c665 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -26,7 +26,7 @@ //! along with the actual implementation elsewhere. You can find more comments //! about how to define rules themselves below. -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, HashMap}; use std::mem; use check::{self, TestKind}; @@ -533,34 +533,44 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { // // Tools used during the build system but not shipped rules.build("tool-rustbook", "src/tools/rustbook") - .dep(|s| s.name("librustc")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("librustc-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "rustbook")); rules.build("tool-error-index", "src/tools/error_index_generator") - .dep(|s| s.name("librustc")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("librustc-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator")); rules.build("tool-tidy", "src/tools/tidy") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "tidy")); rules.build("tool-linkchecker", "src/tools/linkchecker") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker")); rules.build("tool-cargotest", "src/tools/cargotest") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "cargotest")); rules.build("tool-compiletest", "src/tools/compiletest") - .dep(|s| s.name("libtest")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libtest-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "compiletest")); rules.build("tool-build-manifest", "src/tools/build-manifest") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest")); rules.build("tool-qemu-test-server", "src/tools/qemu-test-server") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-server")); rules.build("tool-qemu-test-client", "src/tools/qemu-test-client") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client")); rules.build("tool-cargo", "cargo") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .dep(|s| s.stage(0).host(s.target).name("openssl")) .dep(move |s| { // Cargo depends on procedural macros, which requires a full host @@ -572,7 +582,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); rules.build("tool-rls", "rls") .host(true) - .dep(|s| s.name("librustc")) + .dep(|s| s.name("librustc-tool")) + .dep(|s| s.stage(0).host(s.target).name("openssl")) .dep(move |s| { // rls, like cargo, uses procedural macros s.name("librustc-link") @@ -581,6 +592,25 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { }) .run(move |s| compile::tool(build, s.stage, s.target, "rls")); + // "pseudo rule" which represents completely cleaning out the tools dir in + // one stage. This needs to happen whenever a dependency changes (e.g. + // libstd, libtest, librustc) and all of the tool compilations above will + // be sequenced after this rule. + rules.build("maybe-clean-tools", "path/to/nowhere") + .after("librustc-tool") + .after("libtest-tool") + .after("libstd-tool"); + + rules.build("librustc-tool", "path/to/nowhere") + .dep(|s| s.name("librustc")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Librustc)); + rules.build("libtest-tool", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libtest)); + rules.build("libstd-tool", "path/to/nowhere") + .dep(|s| s.name("libstd")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libstd)); + // ======================================================================== // Documentation targets rules.doc("doc-book", "src/doc/book") @@ -828,6 +858,11 @@ struct Rule<'a> { /// Whether this rule is only for the build triple, not anything in hosts or /// targets. only_build: bool, + + /// A list of "order only" dependencies. This rules does not actually + /// depend on these rules, but if they show up in the dependency graph then + /// this rule must be executed after all these rules. + after: Vec<&'a str>, } #[derive(PartialEq)] @@ -851,6 +886,7 @@ impl<'a> Rule<'a> { host: false, only_host_build: false, only_build: false, + after: Vec::new(), } } } @@ -870,6 +906,11 @@ impl<'a, 'b> RuleBuilder<'a, 'b> { self } + fn after(&mut self, step: &'a str) -> &mut Self { + self.rule.after.push(step); + self + } + fn run(&mut self, f: F) -> &mut Self where F: Fn(&Step<'a>) + 'a, { @@ -1153,31 +1194,52 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? /// From the top level targets `steps` generate a topological ordering of /// all steps needed to run those steps. fn expand(&self, steps: &[Step<'a>]) -> Vec> { + // First up build a graph of steps and their dependencies. The `nodes` + // map is a map from step to a unique number. The `edges` map is a + // map from these unique numbers to a list of other numbers, + // representing dependencies. + let mut nodes = HashMap::new(); + nodes.insert(Step::noop(), 0); + let mut edges = HashMap::new(); + edges.insert(0, HashSet::new()); + for step in steps { + self.build_graph(step.clone(), &mut nodes, &mut edges); + } + + // Now that we've built up the actual dependency graph, draw more + // dependency edges to satisfy the `after` dependencies field for each + // rule. + self.satisfy_after_deps(&nodes, &mut edges); + + // And finally, perform a topological sort to return a list of steps to + // execute. let mut order = Vec::new(); - let mut added = HashSet::new(); - added.insert(Step::noop()); - for step in steps.iter().cloned() { - self.fill(step, &mut order, &mut added); + let mut visited = HashSet::new(); + visited.insert(0); + let idx_to_node = nodes.iter().map(|p| (*p.1, p.0)).collect::>(); + for idx in nodes.values() { + self.topo_sort(*idx, &idx_to_node, &edges, &mut visited, &mut order); } return order } - /// Performs topological sort of dependencies rooted at the `step` - /// specified, pushing all results onto the `order` vector provided. + /// Builds the dependency graph rooted at `step`. /// - /// In other words, when this method returns, the `order` vector will - /// contain a list of steps which if executed in order will eventually - /// complete the `step` specified as well. - /// - /// The `added` set specified here is the set of steps that are already - /// present in `order` (and hence don't need to be added again). - fn fill(&self, - step: Step<'a>, - order: &mut Vec>, - added: &mut HashSet>) { - if !added.insert(step.clone()) { - return + /// The `nodes` and `edges` maps are filled out according to the rule + /// described by `step.name`. + fn build_graph(&self, + step: Step<'a>, + nodes: &mut HashMap, usize>, + edges: &mut HashMap>) -> usize { + use std::collections::hash_map::Entry; + + let idx = nodes.len(); + match nodes.entry(step.clone()) { + Entry::Vacant(e) => { e.insert(idx); } + Entry::Occupied(e) => return *e.get(), } + + let mut deps = Vec::new(); for dep in self.rules[step.name].deps.iter() { let dep = dep(&step); if dep.name.starts_with("default:") { @@ -1189,13 +1251,61 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? let host = self.build.config.host.iter().any(|h| h == dep.target); let rules = self.rules.values().filter(|r| r.default); for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) { - self.fill(dep.name(rule.name), order, added); + deps.push(self.build_graph(dep.name(rule.name), nodes, edges)); } } else { - self.fill(dep, order, added); + deps.push(self.build_graph(dep, nodes, edges)); } } - order.push(step); + + edges.entry(idx).or_insert(HashSet::new()).extend(deps); + return idx + } + + /// Given a dependency graph with a finished list of `nodes`, fill out more + /// dependency `edges`. + /// + /// This is the step which satisfies all `after` listed dependencies in + /// `Rule` above. + fn satisfy_after_deps(&self, + nodes: &HashMap, usize>, + edges: &mut HashMap>) { + // Reverse map from the name of a step to the node indices that it + // appears at. + let mut name_to_idx = HashMap::new(); + for (step, &idx) in nodes { + name_to_idx.entry(step.name).or_insert(Vec::new()).push(idx); + } + + for (step, idx) in nodes { + if *step == Step::noop() { + continue + } + for after in self.rules[step.name].after.iter() { + // This is the critical piece of an `after` dependency. If the + // dependency isn't actually in our graph then no edge is drawn, + // only if it's already present do we draw the edges. + if let Some(idxs) = name_to_idx.get(after) { + edges.get_mut(idx).unwrap() + .extend(idxs.iter().cloned()); + } + } + } + } + + fn topo_sort(&self, + cur: usize, + nodes: &HashMap>, + edges: &HashMap>, + visited: &mut HashSet, + order: &mut Vec>) { + if !visited.insert(cur) { + return + } + for dep in edges[&cur].iter() { + self.topo_sort(*dep, nodes, edges, visited, order); + } + order.push(nodes[&cur].clone()); } } From 03b0d995564b26a2ca9ccf0ded8a6fd375dd9412 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 13 Apr 2017 21:27:35 +0300 Subject: [PATCH 470/905] rustc_typeck: consolidate adjustment composition Fixes #41213. --- src/librustc/ty/adjustment.rs | 2 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/coercion.rs | 38 +++++--------- src/librustc_typeck/check/method/confirm.rs | 8 +-- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 55 +++++++++++++++------ src/test/run-pass/issue-41213.rs | 32 ++++++++++++ 7 files changed, 92 insertions(+), 47 deletions(-) create mode 100644 src/test/run-pass/issue-41213.rs diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index d8ca30477205..1d7100a7a4e4 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -33,7 +33,7 @@ pub enum Adjust<'tcx> { /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, - // Go from a non-capturing closure to an fn pointer. + /// Go from a non-capturing closure to an fn pointer. ClosureFnPointer, /// Go from a mut raw pointer to a const raw pointer. diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index f9bc947a9735..9c5870c12aad 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -100,7 +100,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { - self.write_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); + self.apply_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); return Some(CallStep::Builtin); } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a5acd0c7e530..de7a579ba10e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -712,13 +712,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.commit_if_ok(|_| { let ok = coerce.coerce(&[expr], source, target)?; let adjustment = self.register_infer_ok_obligations(ok); - if !adjustment.is_identity() { - debug!("Success, coerced with {:?}", adjustment); - if self.tables.borrow().adjustments.get(&expr.id).is_some() { - bug!("expr already has an adjustment on it!"); - } - self.write_adjustment(expr.id, adjustment); - } + self.apply_adjustment(expr.id, adjustment); // We should now have added sufficient adjustments etc to // ensure that the type of expression, post-adjustment, is @@ -780,9 +774,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = self.tcx.mk_fn_ptr(fty); for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) { - // No adjustments can produce a fn item, so this should never trip. - assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); - self.write_adjustment(expr.id, Adjustment { + // The only adjustment that can produce an fn item is + // `NeverToAny`, so this should always be valid. + self.apply_adjustment(expr.id, Adjustment { kind: Adjust::ReifyFnPointer, target: fn_ptr }); @@ -803,9 +797,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match result { Ok(ok) => { let adjustment = self.register_infer_ok_obligations(ok); - if !adjustment.is_identity() { - self.write_adjustment(new.id, adjustment); - } + self.apply_adjustment(new.id, adjustment); return Ok(adjustment.target); } Err(e) => first_error = Some(e), @@ -825,7 +817,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { - // Reborrow that we can safely ignore. + // Reborrow that we can safely ignore, because + // the next adjustment can only be a DerefRef + // which will be merged into it. mutbl_adj == mt_orig.mutbl } _ => false, @@ -858,19 +852,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Ok(ok) => { let adjustment = self.register_infer_ok_obligations(ok); - if !adjustment.is_identity() { - let mut tables = self.tables.borrow_mut(); - for expr in exprs { - let expr = expr.as_coercion_site(); - if let Some(&mut Adjustment { - kind: Adjust::NeverToAny, - ref mut target - }) = tables.adjustments.get_mut(&expr.id) { - *target = adjustment.target; - continue; - } - tables.adjustments.insert(expr.id, adjustment); - } + for expr in exprs { + let expr = expr.as_coercion_site(); + self.apply_adjustment(expr.id, adjustment); } Ok(adjustment.target) } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 73f6cd76290a..28ac335cf195 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -143,7 +143,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let target = target.adjust_for_autoref(self.tcx, autoref); // Write out the final adjustment. - self.write_adjustment(self.self_expr.id, Adjustment { + self.apply_adjustment(self.self_expr.id, Adjustment { kind: Adjust::DerefRef { autoderefs: pick.autoderefs, autoref: autoref, @@ -433,7 +433,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { for (i, &expr) in exprs.iter().rev().enumerate() { debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr); - // Count autoderefs. + // Count autoderefs. We don't need to fix up the autoref - the parent + // expression will fix them up for us. let adjustment = self.tables.borrow().adjustments.get(&expr.id).cloned(); match adjustment { Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => { @@ -464,7 +465,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // expects. This is annoying and horrible. We // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. - let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned(); + let adj = self.tables.borrow_mut().adjustments.remove(&base_expr.id); let (autoderefs, unsize, adjusted_base_ty) = match adj { Some(Adjustment { kind: Adjust::DerefRef { autoderefs, autoref, unsize }, @@ -537,6 +538,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // a preference for mut let method_call = ty::MethodCall::expr(expr.id); if self.tables.borrow().method_map.contains_key(&method_call) { + self.tables.borrow_mut().adjustments.remove(&base_expr.id); let method = self.try_overloaded_deref(expr.span, Some(&base_expr), self.node_ty(base_expr.id), diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 4085a171bbef..9ecf0ffa71eb 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -299,7 +299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.write_adjustment(self_expr.id, Adjustment { + self.apply_adjustment(self_expr.id, Adjustment { kind: Adjust::DerefRef { autoderefs: autoderefs, autoref: autoref, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c995b7e92843..dc221a93f134 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,7 @@ use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; use rustc::ty::{MethodCall, MethodCallee}; -use rustc::ty::adjustment; +use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; @@ -108,6 +108,7 @@ use util::common::{ErrorReported, indenter}; use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap}; use std::cell::{Cell, RefCell}; +use std::collections::hash_map::Entry; use std::cmp; use std::mem::replace; use std::ops::{self, Deref}; @@ -1637,12 +1638,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn write_autoderef_adjustment(&self, + pub fn apply_autoderef_adjustment(&self, node_id: ast::NodeId, derefs: usize, adjusted_ty: Ty<'tcx>) { - self.write_adjustment(node_id, adjustment::Adjustment { - kind: adjustment::Adjust::DerefRef { + self.apply_adjustment(node_id, Adjustment { + kind: Adjust::DerefRef { autoderefs: derefs, autoref: None, unsize: false @@ -1651,16 +1652,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - pub fn write_adjustment(&self, - node_id: ast::NodeId, - adj: adjustment::Adjustment<'tcx>) { - debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj); + pub fn apply_adjustment(&self, node_id: ast::NodeId, adj: Adjustment<'tcx>) { + debug!("apply_adjustment(node_id={}, adj={:?})", node_id, adj); if adj.is_identity() { return; } - self.tables.borrow_mut().adjustments.insert(node_id, adj); + match self.tables.borrow_mut().adjustments.entry(node_id) { + Entry::Vacant(entry) => { entry.insert(adj); }, + Entry::Occupied(mut entry) => { + debug!(" - composing on top of {:?}", entry.get()); + let composed_kind = match (entry.get().kind, adj.kind) { + // Applying any adjustment on top of a NeverToAny + // is a valid NeverToAny adjustment, because it can't + // be reached. + (Adjust::NeverToAny, _) => Adjust::NeverToAny, + (Adjust::DerefRef { + autoderefs: 1, + autoref: Some(AutoBorrow::Ref(..)), + unsize: false + }, Adjust::DerefRef { autoderefs, .. }) if autoderefs > 0 => { + // A reborrow has no effect before a dereference. + adj.kind + } + // FIXME: currently we never try to compose autoderefs + // and ReifyFnPointer/UnsafeFnPointer, but we could. + _ => + bug!("while adjusting {}, can't compose {:?} and {:?}", + node_id, entry.get(), adj) + }; + *entry.get_mut() = Adjustment { + kind: composed_kind, + target: adj.target + }; + } + } } /// Basically whenever we are converting from a type scheme into @@ -2302,7 +2329,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("try_index_step: success, using built-in indexing"); // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. assert!(!unsize); - self.write_autoderef_adjustment(base_expr.id, autoderefs, adjusted_ty); + self.apply_autoderef_adjustment(base_expr.id, autoderefs, adjusted_ty); return Some((tcx.types.usize, ty)); } _ => {} @@ -2685,8 +2712,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "expression with never type wound up being adjusted"); let adj_ty = self.next_diverging_ty_var( TypeVariableOrigin::AdjustmentType(expr.span)); - self.write_adjustment(expr.id, adjustment::Adjustment { - kind: adjustment::Adjust::NeverToAny, + self.apply_adjustment(expr.id, Adjustment { + kind: Adjust::NeverToAny, target: adj_ty }); ty = adj_ty; @@ -2917,7 +2944,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = self.field_ty(expr.span, field, substs); if self.tcx.vis_is_accessible_from(field.vis, self.body_id) { autoderef.finalize(lvalue_pref, &[base]); - self.write_autoderef_adjustment(base.id, autoderefs, base_t); + self.apply_autoderef_adjustment(base.id, autoderefs, base_t); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -3041,7 +3068,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field_ty) = field { autoderef.finalize(lvalue_pref, &[base]); - self.write_autoderef_adjustment(base.id, autoderefs, base_t); + self.apply_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } } diff --git a/src/test/run-pass/issue-41213.rs b/src/test/run-pass/issue-41213.rs new file mode 100644 index 000000000000..d4755020fef2 --- /dev/null +++ b/src/test/run-pass/issue-41213.rs @@ -0,0 +1,32 @@ +// 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. + +enum A { + A1, + A2, + A3, +} + +enum B { + B1(String, String), + B2(String, String), +} + +fn main() { + let a = A::A1; + loop { + let _ctor = match a { + A::A3 => break, + A::A1 => B::B1, + A::A2 => B::B2, + }; + break; + } +} From d64de94efa8a2aeb1a104c367be1b5c03b148987 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 13 Apr 2017 20:11:29 +0200 Subject: [PATCH 471/905] Update std::collections' docs to use iterator (etc.) boilerplate This greatly improves consistency. --- src/libcollections/binary_heap.rs | 32 ++++++++++++--- src/libcollections/btree/map.rs | 64 ++++++++++++++++++++++++++---- src/libcollections/btree/set.rs | 38 ++++++++++-------- src/libcollections/linked_list.rs | 24 +++++++++-- src/libcollections/vec_deque.rs | 32 +++++++++++++-- src/libstd/collections/hash/map.rs | 56 ++++++++++++++++++++++---- src/libstd/collections/hash/set.rs | 56 ++++++++++++++++++++++---- 7 files changed, 252 insertions(+), 50 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index efa96ca468e0..0fad377c6b25 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -218,10 +218,14 @@ pub struct BinaryHeap { data: Vec, } -/// A container object that represents the result of the [`peek_mut`] method -/// on `BinaryHeap`. See its documentation for details. +/// Object representing a mutable reference to the greatest item on a +/// `BinaryHeap`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See +/// its documentation for more. /// /// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap, @@ -971,7 +975,13 @@ impl<'a, T> Drop for Hole<'a, T> { } } -/// `BinaryHeap` iterator. +/// An iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.BinaryHeap.html#method.iter +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { iter: slice::Iter<'a, T>, @@ -1027,7 +1037,13 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} -/// An iterator that moves out of a `BinaryHeap`. +/// An owning iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { @@ -1076,7 +1092,13 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -/// An iterator that drains a `BinaryHeap`. +/// A draining iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.BinaryHeap.html#method.drain +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "drain", since = "1.6.0")] #[derive(Debug)] pub struct Drain<'a, T: 'a> { diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index b30700c3f694..e7e91a2fcaad 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -262,7 +262,13 @@ impl super::Recover for BTreeMap } } -/// An iterator over a `BTreeMap`'s entries. +/// An iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`iter`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.BTreeMap.html#method.iter +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { range: Range<'a, K, V>, @@ -276,7 +282,13 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Iter<'a, K, V> { } } -/// A mutable iterator over a `BTreeMap`'s entries. +/// A mutable iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.BTreeMap.html#method.iter_mut +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, K: 'a, V: 'a> { @@ -284,7 +296,13 @@ pub struct IterMut<'a, K: 'a, V: 'a> { length: usize, } -/// An owning iterator over a `BTreeMap`'s entries. +/// An owning iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.BTreeMap.html#method.into_iter +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { front: Handle, marker::Edge>, @@ -303,7 +321,13 @@ impl fmt::Debug for IntoIter { } } -/// An iterator over a `BTreeMap`'s keys. +/// An iterator over the keys of a `BTreeMap`. +/// +/// This `struct` is created by the [`keys`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.BTreeMap.html#method.keys +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -316,7 +340,13 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Keys<'a, K, V> { } } -/// An iterator over a `BTreeMap`'s values. +/// An iterator over the values of a `BTreeMap`. +/// +/// This `struct` is created by the [`values`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.BTreeMap.html#method.values +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -329,14 +359,26 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Values<'a, K, V> } } -/// A mutable iterator over a `BTreeMap`'s values. +/// A mutable iterator over the values of a `BTreeMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.BTreeMap.html#method.values_mut +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "map_values_mut", since = "1.10.0")] #[derive(Debug)] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } -/// An iterator over a sub-range of `BTreeMap`'s entries. +/// An iterator over a sub-range of entries in a `BTreeMap`. +/// +/// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`range`]: struct.BTreeMap.html#method.range +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "btree_range", since = "1.17.0")] pub struct Range<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -350,7 +392,13 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> } } -/// A mutable iterator over a sub-range of `BTreeMap`'s entries. +/// A mutable iterator over a sub-range of entries in a `BTreeMap`. +/// +/// This `struct` is created by the [`range_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`range_mut`]: struct.BTreeMap.html#method.range_mut +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 9dbb61379379..37c7581e5f47 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -74,9 +74,10 @@ pub struct BTreeSet { map: BTreeMap, } -/// An iterator over a `BTreeSet`'s items. +/// An iterator over the items of a `BTreeSet`. /// -/// This structure is created by the [`iter`] method on [`BTreeSet`]. +/// This `struct` is created by the [`iter`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`iter`]: struct.BTreeSet.html#method.iter @@ -94,21 +95,23 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { } } -/// An owning iterator over a `BTreeSet`'s items. +/// An owning iterator over the items of a `BTreeSet`. /// -/// This structure is created by the `into_iter` method on [`BTreeSet`] -/// [`BTreeSet`] (provided by the `IntoIterator` trait). +/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html +/// [`into_iter`]: struct.BTreeSet.html#method.into_iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IntoIter { iter: ::btree_map::IntoIter, } -/// An iterator over a sub-range of `BTreeSet`'s items. +/// An iterator over a sub-range of items in a `BTreeSet`. /// -/// This structure is created by the [`range`] method on [`BTreeSet`]. +/// This `struct` is created by the [`range`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`range`]: struct.BTreeSet.html#method.range @@ -118,9 +121,10 @@ pub struct Range<'a, T: 'a> { iter: ::btree_map::Range<'a, T, ()>, } -/// A lazy iterator producing elements in the set difference (in-order). +/// A lazy iterator producing elements in the difference of `BTreeSet`s. /// -/// This structure is created by the [`difference`] method on [`BTreeSet`]. +/// This `struct` is created by the [`difference`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`difference`]: struct.BTreeSet.html#method.difference @@ -139,10 +143,10 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> { } } -/// A lazy iterator producing elements in the set symmetric difference (in-order). +/// A lazy iterator producing elements in the symmetric difference of `BTreeSet`s. /// -/// This structure is created by the [`symmetric_difference`] method on -/// [`BTreeSet`]. +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`BTreeSet`]. See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference @@ -161,9 +165,10 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> { } } -/// A lazy iterator producing elements in the set intersection (in-order). +/// A lazy iterator producing elements in the intersection of `BTreeSet`s. /// -/// This structure is created by the [`intersection`] method on [`BTreeSet`]. +/// This `struct` is created by the [`intersection`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`intersection`]: struct.BTreeSet.html#method.intersection @@ -182,9 +187,10 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> { } } -/// A lazy iterator producing elements in the set union (in-order). +/// A lazy iterator producing elements in the union of `BTreeSet`s. /// -/// This structure is created by the [`union`] method on [`BTreeSet`]. +/// This `struct` is created by the [`union`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`union`]: struct.BTreeSet.html#method.union diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 1b3eeb837d90..eabf7e47f004 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -56,7 +56,13 @@ struct Node { element: T, } -/// An iterator over references to the elements of a `LinkedList`. +/// An iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`iter`] method on [`LinkedList`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.LinkedList.html#method.iter +/// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { head: Option>>, @@ -82,7 +88,13 @@ impl<'a, T> Clone for Iter<'a, T> { } } -/// An iterator over mutable references to the elements of a `LinkedList`. +/// A mutable iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`LinkedList`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.LinkedList.html#method.iter_mut +/// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { list: &'a mut LinkedList, @@ -100,7 +112,13 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { } } -/// An iterator over the elements of a `LinkedList`. +/// An owning iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.LinkedList.html#method.into_iter +/// [`LinkedList`]: struct.LinkedList.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index f1ea0010e98c..7fe11c71d240 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1890,7 +1890,13 @@ fn count(tail: usize, head: usize, size: usize) -> usize { (head.wrapping_sub(tail)) & (size - 1) } -/// `VecDeque` iterator. +/// An iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.VecDeque.html#method.iter +/// [`VecDeque`]: struct.VecDeque.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { ring: &'a [T], @@ -1971,7 +1977,13 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { impl<'a, T> FusedIterator for Iter<'a, T> {} -/// `VecDeque` mutable iterator. +/// A mutable iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut +/// [`VecDeque`]: struct.VecDeque.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { ring: &'a mut [T], @@ -2047,7 +2059,13 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} -/// A by-value `VecDeque` iterator +/// An owning iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`into_iter`] method on [`VecDeque`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.VecDeque.html#method.into_iter +/// [`VecDeque`]: struct.VecDeque.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -2097,7 +2115,13 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -/// A draining `VecDeque` iterator +/// A draining iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.VecDeque.html#method.drain +/// [`VecDeque`]: struct.VecDeque.html #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { after_tail: usize, diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a06299eaefe0..e7c7ba64099b 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1333,7 +1333,13 @@ impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap } } -/// HashMap iterator. +/// An iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashMap.html#method.iter +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { inner: table::Iter<'a, K, V>, @@ -1356,19 +1362,37 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { } } -/// HashMap mutable values iterator. +/// A mutable iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashMap.html#method.iter_mut +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { inner: table::IterMut<'a, K, V>, } -/// HashMap move iterator. +/// An owning iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.HashMap.html#method.into_iter +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { pub(super) inner: table::IntoIter, } -/// HashMap keys iterator. +/// An iterator over the keys of a `HashMap`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.HashMap.html#method.keys +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1391,7 +1415,13 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Keys<'a, K, V> { } } -/// HashMap values iterator. +/// An iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.HashMap.html#method.values +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1414,13 +1444,25 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Values<'a, K, V> { } } -/// HashMap drain iterator. +/// A draining iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.HashMap.html#method.drain +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { pub(super) inner: table::Drain<'a, K, V>, } -/// Mutable HashMap values iterator. +/// A mutable iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.HashMap.html#method.values_mut +/// [`HashMap`]: struct.HashMap.html #[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ac0d15472c1b..86e819b99fb4 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -856,25 +856,49 @@ impl<'a, 'b, T, S> Sub<&'b HashSet> for &'a HashSet } } -/// HashSet iterator +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`iter`]: struct.HashSet.html#method.iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a> { iter: Keys<'a, K, ()>, } -/// HashSet move iterator +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`into_iter`]: struct.HashSet.html#method.into_iter #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { iter: map::IntoIter, } -/// HashSet drain iterator +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`drain`]: struct.HashSet.html#method.drain #[stable(feature = "rust1", since = "1.0.0")] pub struct Drain<'a, K: 'a> { iter: map::Drain<'a, K, ()>, } -/// Intersection iterator +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`intersection`]: struct.HashSet.html#method.intersection #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set @@ -883,7 +907,13 @@ pub struct Intersection<'a, T: 'a, S: 'a> { other: &'a HashSet, } -/// Difference iterator +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`difference`]: struct.HashSet.html#method.difference #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set @@ -892,13 +922,25 @@ pub struct Difference<'a, T: 'a, S: 'a> { other: &'a HashSet, } -/// Symmetric difference iterator. +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference #[stable(feature = "rust1", since = "1.0.0")] pub struct SymmetricDifference<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, } -/// Set union iterator. +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`union`]: struct.HashSet.html#method.union #[stable(feature = "rust1", since = "1.0.0")] pub struct Union<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, From d688c4d806c6272c6b7a60dbed2aa329641fbf93 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 13 Apr 2017 21:30:59 +0200 Subject: [PATCH 472/905] Various fixes throughout std::collections' docs * Added links where possible (limited because of facading) * Changed references to methods from `foo()` to `foo` in module docs * Changed references to methods from `HashMap::foo` to just `foo` in top-level docs for `HashMap` and the `default` doc for `DefaultHasher` * Various small other fixes --- src/libcollections/binary_heap.rs | 7 +++- src/libcollections/btree/set.rs | 2 +- src/libcollections/linked_list.rs | 4 +- src/libcollections/vec_deque.rs | 13 +++++-- src/libstd/collections/hash/map.rs | 37 +++++++++--------- src/libstd/collections/hash/set.rs | 61 ++++++++++++++++++++---------- src/libstd/collections/mod.rs | 56 +++++++++++++-------------- 7 files changed, 106 insertions(+), 74 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 0fad377c6b25..89d9576cba2a 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -20,11 +20,12 @@ //! //! This is a larger example that implements [Dijkstra's algorithm][dijkstra] //! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph]. -//! It shows how to use `BinaryHeap` with custom types. +//! It shows how to use [`BinaryHeap`] with custom types. //! //! [dijkstra]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm //! [sssp]: http://en.wikipedia.org/wiki/Shortest_path_problem //! [dir_graph]: http://en.wikipedia.org/wiki/Directed_graph +//! [`BinaryHeap`]: struct.BinaryHeap.html //! //! ``` //! use std::cmp::Ordering; @@ -438,7 +439,7 @@ impl BinaryHeap { /// given `BinaryHeap`. Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future + /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future /// insertions are expected. /// /// # Panics @@ -456,6 +457,8 @@ impl BinaryHeap { /// assert!(heap.capacity() >= 100); /// heap.push(4); /// ``` + /// + /// [`reserve`]: #method.reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.data.reserve_exact(additional); diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 37c7581e5f47..ffca6964c5fd 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -734,7 +734,7 @@ impl IntoIterator for BTreeSet { type Item = T; type IntoIter = IntoIter; - /// Gets an iterator for moving out the BtreeSet's contents. + /// Gets an iterator for moving out the `BTreeSet`'s contents. /// /// # Examples /// diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index eabf7e47f004..bfb03a5b23f1 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -636,12 +636,12 @@ impl LinkedList { /// Splits the list into two at the given index. Returns everything after the given index, /// including the index. /// + /// This operation should compute in O(n) time. + /// /// # Panics /// /// Panics if `at > len`. /// - /// This operation should compute in O(n) time. - /// /// # Examples /// /// ``` diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 7fe11c71d240..7b8f4f4c6c82 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -46,10 +46,15 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of /// `VecDeque` is a growable ring buffer, which can be used as a double-ended /// queue efficiently. /// -/// The "default" usage of this type as a queue is to use `push_back` to add to -/// the queue, and `pop_front` to remove from the queue. `extend` and `append` +/// The "default" usage of this type as a queue is to use [`push_back`] to add to +/// the queue, and [`pop_front`] to remove from the queue. [`extend`] and [`append`] /// push onto the back in this manner, and iterating over `VecDeque` goes front /// to back. +/// +/// [`push_back`]: #method.push_back +/// [`pop_front`]: #method.pop_front +/// [`extend`]: #method.extend +/// [`append`]: #method.append #[stable(feature = "rust1", since = "1.0.0")] pub struct VecDeque { // tail and head are pointers into the buffer. Tail always points @@ -506,7 +511,7 @@ impl VecDeque { /// given `VecDeque`. Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future + /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future /// insertions are expected. /// /// # Panics @@ -522,6 +527,8 @@ impl VecDeque { /// buf.reserve_exact(10); /// assert!(buf.capacity() >= 11); /// ``` + /// + /// [`reserve`]: #method.reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.reserve(additional); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e7c7ba64099b..9e71ec1d25df 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -235,9 +235,8 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// attacks such as HashDoS. /// /// The hashing algorithm can be replaced on a per-`HashMap` basis using the -/// [`HashMap::default`], [`HashMap::with_hasher`], and -/// [`HashMap::with_capacity_and_hasher`] methods. Many alternative algorithms -/// are available on crates.io, such as the [`fnv`] crate. +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many +/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. /// /// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although /// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. @@ -339,9 +338,9 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html /// [`RefCell`]: ../../std/cell/struct.RefCell.html /// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`HashMap::default`]: #method.default -/// [`HashMap::with_hasher`]: #method.with_hasher -/// [`HashMap::with_capacity_and_hasher`]: #method.with_capacity_and_hasher +/// [`default`]: #method.default +/// [`with_hasher`]: #method.with_hasher +/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher /// [`fnv`]: https://crates.io/crates/fnv /// /// ``` @@ -373,7 +372,7 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// } /// ``` /// -/// A HashMap with fixed list of elements can be initialized from an array: +/// A `HashMap` with fixed list of elements can be initialized from an array: /// /// ``` /// use std::collections::HashMap; @@ -654,12 +653,13 @@ impl HashMap } } - /// Creates an empty `HashMap` with the specified capacity, using `hasher` + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` /// to hash the keys. /// /// The hash map will be able to hold at least `capacity` elements without /// reallocating. If `capacity` is 0, the hash map will not allocate. - /// Warning: `hasher` is normally randomly generated, and + /// + /// Warning: `hash_builder` is normally randomly generated, and /// is designed to allow HashMaps to be resistant to attacks that /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. @@ -686,7 +686,9 @@ impl HashMap } } - /// Returns a reference to the map's hasher. + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { &self.hash_builder @@ -849,7 +851,7 @@ impl HashMap } /// An iterator visiting all keys in arbitrary order. - /// Iterator element type is `&'a K`. + /// The iterator element type is `&'a K`. /// /// # Examples /// @@ -871,7 +873,7 @@ impl HashMap } /// An iterator visiting all values in arbitrary order. - /// Iterator element type is `&'a V`. + /// The iterator element type is `&'a V`. /// /// # Examples /// @@ -893,7 +895,7 @@ impl HashMap } /// An iterator visiting all values mutably in arbitrary order. - /// Iterator element type is `&'a mut V`. + /// The iterator element type is `&'a mut V`. /// /// # Examples /// @@ -920,7 +922,7 @@ impl HashMap } /// An iterator visiting all key-value pairs in arbitrary order. - /// Iterator element type is `(&'a K, &'a V)`. + /// The iterator element type is `(&'a K, &'a V)`. /// /// # Examples /// @@ -943,7 +945,7 @@ impl HashMap /// An iterator visiting all key-value pairs in arbitrary order, /// with mutable references to the values. - /// Iterator element type is `(&'a K, &'a mut V)`. + /// The iterator element type is `(&'a K, &'a mut V)`. /// /// # Examples /// @@ -2408,10 +2410,9 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { - /// Creates a new `DefaultHasher` using [`DefaultHasher::new`]. See - /// [`DefaultHasher::new`] documentation for more information. + /// Creates a new `DefaultHasher` using [`new`]. See its documentation for more. /// - /// [`DefaultHasher::new`]: #method.new + /// [`new`]: #method.new fn default() -> DefaultHasher { DefaultHasher::new() } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 86e819b99fb4..e56470c617f8 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -25,10 +25,10 @@ use super::map::{self, HashMap, Keys, RandomState}; // to get rid of it properly. /// An implementation of a hash set using the underlying representation of a -/// HashMap where the value is (). +/// `HashMap` where the value is (). /// -/// As with the `HashMap` type, a `HashSet` requires that the elements -/// implement the `Eq` and `Hash` traits. This can frequently be achieved by +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by /// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, /// it is important that the following property holds: /// @@ -40,9 +40,9 @@ use super::map::{self, HashMap, Keys, RandomState}; /// /// /// It is a logic error for an item to be modified in such a way that the -/// item's hash, as determined by the `Hash` trait, or its equality, as -/// determined by the `Eq` trait, changes while it is in the set. This is -/// normally only possible through `Cell`, `RefCell`, global state, I/O, or +/// item's hash, as determined by the [`Hash`] trait, or its equality, as +/// determined by the [`Eq`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or /// unsafe code. /// /// # Examples @@ -75,8 +75,8 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// /// The easiest way to use `HashSet` with a custom type is to derive -/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the -/// future be implied by `Eq`. +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`], this will in the +/// future be implied by [`Eq`]. /// /// ``` /// use std::collections::HashSet; @@ -99,7 +99,7 @@ use super::map::{self, HashMap, Keys, RandomState}; /// } /// ``` /// -/// HashSet with fixed list of elements can be initialized from an array: +/// A `HashSet` with fixed list of elements can be initialized from an array: /// /// ``` /// use std::collections::HashSet; @@ -110,6 +110,13 @@ use super::map::{self, HashMap, Keys, RandomState}; /// // use the values stored in the set /// } /// ``` +/// +/// [`Cell`]: ../../std/cell/struct.Cell.html +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`HashMap`]: struct.HashMap.html +/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html #[derive(Clone)] @@ -181,7 +188,7 @@ impl HashSet HashSet { map: HashMap::with_hasher(hasher) } } - /// Creates an empty HashSet with with the specified capacity, using + /// Creates an empty `HashSet` with with the specified capacity, using /// `hasher` to hash the keys. /// /// The hash set will be able to hold at least `capacity` elements without @@ -208,7 +215,9 @@ impl HashSet HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } } - /// Returns a reference to the set's hasher. + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { self.map.hasher() @@ -271,7 +280,7 @@ impl HashSet } /// An iterator visiting all elements in arbitrary order. - /// Iterator element type is &'a T. + /// The iterator element type is `&'a T`. /// /// # Examples /// @@ -291,7 +300,7 @@ impl HashSet Iter { iter: self.map.keys() } } - /// Visit the values representing the difference, + /// Visits the values representing the difference, /// i.e. the values that are in `self` but not in `other`. /// /// # Examples @@ -322,7 +331,7 @@ impl HashSet } } - /// Visit the values representing the symmetric difference, + /// Visits the values representing the symmetric difference, /// i.e. the values that are in `self` or in `other` but not in both. /// /// # Examples @@ -350,7 +359,7 @@ impl HashSet SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } } - /// Visit the values representing the intersection, + /// Visits the values representing the intersection, /// i.e. the values that are both in `self` and `other`. /// /// # Examples @@ -376,7 +385,7 @@ impl HashSet } } - /// Visit the values representing the union, + /// Visits the values representing the union, /// i.e. all the values in `self` or `other`, without duplicates. /// /// # Examples @@ -460,7 +469,7 @@ impl HashSet /// Returns `true` if the set contains a value. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. /// /// # Examples @@ -472,6 +481,9 @@ impl HashSet /// assert_eq!(set.contains(&1), true); /// assert_eq!(set.contains(&4), false); /// ``` + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "rust1", since = "1.0.0")] pub fn contains(&self, value: &Q) -> bool where T: Borrow, @@ -483,8 +495,11 @@ impl HashSet /// Returns a reference to the value in the set, if any, that is equal to the given value. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "set_recovery", since = "1.9.0")] pub fn get(&self, value: &Q) -> Option<&T> where T: Borrow, @@ -596,7 +611,7 @@ impl HashSet /// present in the set. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. /// /// # Examples @@ -610,6 +625,9 @@ impl HashSet /// assert_eq!(set.remove(&2), true); /// assert_eq!(set.remove(&2), false); /// ``` + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, value: &Q) -> bool where T: Borrow, @@ -621,8 +639,11 @@ impl HashSet /// Removes and returns the value in the set, if any, that is equal to the given one. /// /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the value type. + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html #[stable(feature = "set_recovery", since = "1.9.0")] pub fn take(&mut self, value: &Q) -> Option where T: Borrow, diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 8884d0688b8b..73acf69c72cd 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -157,29 +157,29 @@ //! information to do this itself. Therefore, it is up to us programmers to give //! it hints. //! -//! Any `with_capacity()` constructor will instruct the collection to allocate +//! Any `with_capacity` constructor will instruct the collection to allocate //! enough space for the specified number of elements. Ideally this will be for //! exactly that many elements, but some implementation details may prevent //! this. [`Vec`] and [`VecDeque`] can be relied on to allocate exactly the -//! requested amount, though. Use `with_capacity()` when you know exactly how many +//! requested amount, though. Use `with_capacity` when you know exactly how many //! elements will be inserted, or at least have a reasonable upper-bound on that //! number. //! -//! When anticipating a large influx of elements, the `reserve()` family of +//! When anticipating a large influx of elements, the `reserve` family of //! methods can be used to hint to the collection how much room it should make -//! for the coming items. As with `with_capacity()`, the precise behavior of +//! for the coming items. As with `with_capacity`, the precise behavior of //! these methods will be specific to the collection of interest. //! //! For optimal performance, collections will generally avoid shrinking //! themselves. If you believe that a collection will not soon contain any more -//! elements, or just really need the memory, the `shrink_to_fit()` method prompts +//! elements, or just really need the memory, the `shrink_to_fit` method prompts //! the collection to shrink the backing array to the minimum size capable of //! holding its elements. //! //! Finally, if ever you're interested in what the actual capacity of the -//! collection is, most collections provide a `capacity()` method to query this +//! collection is, most collections provide a `capacity` method to query this //! information on demand. This can be useful for debugging purposes, or for -//! use with the `reserve()` methods. +//! use with the `reserve` methods. //! //! ## Iterators //! @@ -194,11 +194,11 @@ //! //! All of the standard collections provide several iterators for performing //! bulk manipulation of their contents. The three primary iterators almost -//! every collection should provide are `iter()`, `iter_mut()`, and `into_iter()`. +//! every collection should provide are `iter`, `iter_mut`, and `into_iter`. //! Some of these are not provided on collections where it would be unsound or //! unreasonable to provide them. //! -//! `iter()` provides an iterator of immutable references to all the contents of a +//! `iter` provides an iterator of immutable references to all the contents of a //! collection in the most "natural" order. For sequence collections like [`Vec`], //! this means the items will be yielded in increasing order of index starting //! at 0. For ordered collections like [`BTreeMap`], this means that the items @@ -214,8 +214,8 @@ //! } //! ``` //! -//! `iter_mut()` provides an iterator of *mutable* references in the same order as -//! `iter()`. This is great for mutating all the contents of the collection. +//! `iter_mut` provides an iterator of *mutable* references in the same order as +//! `iter`. This is great for mutating all the contents of the collection. //! //! ``` //! let mut vec = vec![1, 2, 3, 4]; @@ -224,12 +224,12 @@ //! } //! ``` //! -//! `into_iter()` transforms the actual collection into an iterator over its +//! `into_iter` transforms the actual collection into an iterator over its //! contents by-value. This is great when the collection itself is no longer -//! needed, and the values are needed elsewhere. Using `extend()` with `into_iter()` +//! needed, and the values are needed elsewhere. Using `extend` with `into_iter` //! is the main way that contents of one collection are moved into another. -//! `extend()` automatically calls `into_iter()`, and takes any `T: `[`IntoIterator`]. -//! Calling `collect()` on an iterator itself is also a great way to convert one +//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`]. +//! Calling `collect` on an iterator itself is also a great way to convert one //! collection into another. Both of these methods should internally use the //! capacity management tools discussed in the previous section to do this as //! efficiently as possible. @@ -248,9 +248,9 @@ //! ``` //! //! Iterators also provide a series of *adapter* methods for performing common -//! threads to sequences. Among the adapters are functional favorites like `map()`, -//! `fold()`, `skip()` and `take()`. Of particular interest to collections is the -//! `rev()` adapter, that reverses any iterator that supports this operation. Most +//! threads to sequences. Among the adapters are functional favorites like `map`, +//! `fold`, `skip` and `take`. Of particular interest to collections is the +//! `rev` adapter, that reverses any iterator that supports this operation. Most //! collections provide reversible iterators as the way to iterate over them in //! reverse order. //! @@ -263,27 +263,27 @@ //! //! Several other collection methods also return iterators to yield a sequence //! of results but avoid allocating an entire collection to store the result in. -//! This provides maximum flexibility as `collect()` or `extend()` can be called to +//! This provides maximum flexibility as `collect` or `extend` can be called to //! "pipe" the sequence into any collection if desired. Otherwise, the sequence //! can be looped over with a `for` loop. The iterator can also be discarded //! after partial use, preventing the computation of the unused items. //! //! ## Entries //! -//! The `entry()` API is intended to provide an efficient mechanism for +//! The `entry` API is intended to provide an efficient mechanism for //! manipulating the contents of a map conditionally on the presence of a key or //! not. The primary motivating use case for this is to provide efficient //! accumulator maps. For instance, if one wishes to maintain a count of the //! number of times each key has been seen, they will have to perform some //! conditional logic on whether this is the first time the key has been seen or -//! not. Normally, this would require a `find()` followed by an `insert()`, +//! not. Normally, this would require a `find` followed by an `insert`, //! effectively duplicating the search effort on each insertion. //! //! When a user calls `map.entry(&key)`, the map will search for the key and //! then yield a variant of the `Entry` enum. //! //! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case -//! the only valid operation is to `insert()` a value into the entry. When this is +//! the only valid operation is to `insert` a value into the entry. When this is //! done, the vacant entry is consumed and converted into a mutable reference to //! the value that was inserted. This allows for further manipulation of the //! value beyond the lifetime of the search itself. This is useful if complex @@ -291,14 +291,14 @@ //! just inserted. //! //! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, -//! the user has several options: they can `get()`, `insert()` or `remove()` the +//! the user has several options: they can `get`, `insert` or `remove` the //! value of the occupied entry. Additionally, they can convert the occupied //! entry into a mutable reference to its value, providing symmetry to the -//! vacant `insert()` case. +//! vacant `insert` case. //! //! ### Examples //! -//! Here are the two primary ways in which `entry()` is used. First, a simple +//! Here are the two primary ways in which `entry` is used. First, a simple //! example where the logic performed on the values is trivial. //! //! #### Counting the number of times each character in a string occurs @@ -322,7 +322,7 @@ //! ``` //! //! When the logic to be performed on the value is more complex, we may simply -//! use the `entry()` API to ensure that the value is initialized and perform the +//! use the `entry` API to ensure that the value is initialized and perform the //! logic afterwards. //! //! #### Tracking the inebriation of customers at a bar @@ -360,7 +360,7 @@ //! //! # Insert and complex keys //! -//! If we have a more complex key, calls to `insert()` will +//! If we have a more complex key, calls to `insert` will //! not update the value of the key. For example: //! //! ``` @@ -451,7 +451,7 @@ pub mod hash_map { #[stable(feature = "rust1", since = "1.0.0")] pub mod hash_set { //! An implementation of a hash set using the underlying representation of a - //! HashMap where the value is (). + //! `HashMap` where the value is (). #[stable(feature = "rust1", since = "1.0.0")] pub use super::hash::set::*; } From 89ac8654e19b123132c82eb9f81ed3ba9bb3eb33 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 13 Apr 2017 22:48:49 +0200 Subject: [PATCH 473/905] Various consistency and phrasing fixes in std::collections' docs * Changed btree_map's and hash_map's Entry (etc.) docs to be consistent * Changed VecDeque's type and module summary sentences to be consistent with each other as well as with other summary sentences in the module * Changed HashMap's and HashSet's summary sentences to be less redundantly phrased and also more consistant with the other summary sentences in the module * Also, added an example to Bound --- src/libcollections/btree/map.rs | 13 ++++++++----- src/libcollections/lib.rs | 17 +++++++++++++++++ src/libcollections/vec_deque.rs | 6 ++---- src/libstd/collections/hash/map.rs | 16 ++++++++-------- src/libstd/collections/hash/set.rs | 3 +-- src/libstd/collections/mod.rs | 6 ++---- 6 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index e7e91a2fcaad..b986c0275502 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -420,18 +420,19 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for RangeMut<'a, K, } /// A view into a single entry in a map, which may either be vacant or occupied. -/// This enum is constructed from the [`entry`] method on [`BTreeMap`]. +/// +/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. /// /// [`BTreeMap`]: struct.BTreeMap.html /// [`entry`]: struct.BTreeMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { - /// A vacant `Entry` + /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), - /// An occupied `Entry` + /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), @@ -451,7 +452,8 @@ impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { } } -/// A vacant `Entry`. It is part of the [`Entry`] enum. +/// A view into a vacant entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] @@ -473,7 +475,8 @@ impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { } } -/// An occupied `Entry`. It is part of the [`Entry`] enum. +/// A view into an occupied entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 99afd08e8118..4ff54095bd35 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -135,6 +135,23 @@ mod std { } /// An endpoint of a range of keys. +/// # Examples +/// +/// ``` +/// 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()); +/// ``` #[stable(feature = "collections_bound", since = "1.17.0")] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub enum Bound { diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 7b8f4f4c6c82..2ce3b92843bd 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! `VecDeque` is a double-ended queue, which is implemented with the help of a -//! growing ring buffer. +//! A double-ended queue implemented with a growable ring buffer. //! //! This queue has `O(1)` amortized inserts and removals from both ends of the //! container. It also has `O(1)` indexing like a vector. The contained elements @@ -43,8 +42,7 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (32 - 1); // Largest possible power of #[cfg(target_pointer_width = "64")] const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of two -/// `VecDeque` is a growable ring buffer, which can be used as a double-ended -/// queue efficiently. +/// A double-ended queue implemented with a growable ring buffer. /// /// The "default" usage of this type as a queue is to use [`push_back`] to add to /// the queue, and [`pop_front`] to remove from the queue. [`extend`] and [`append`] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 9e71ec1d25df..eacb59d375a5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -215,8 +215,7 @@ const DISPLACEMENT_THRESHOLD: usize = 128; // 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing // hashing with buckets. -/// A hash map implementation which uses linear probing with Robin Hood bucket -/// stealing. +/// A hash map implemented with linear probing and Robin Hood bucket stealing. /// /// By default, `HashMap` uses a hashing algorithm selected to provide /// resistance against HashDoS attacks. The algorithm is randomly seeded, and a @@ -1511,19 +1510,20 @@ impl<'a, K, V> InternalEntry> { } } -/// A view into a single location in a map, which may be vacant or occupied. -/// This enum is constructed from the [`entry`] method on [`HashMap`]. +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. /// /// [`HashMap`]: struct.HashMap.html /// [`entry`]: struct.HashMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { - /// An occupied Entry. + /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), - /// A vacant Entry. + /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), @@ -1547,7 +1547,7 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { } } -/// A view into a single occupied location in a HashMap. +/// A view into an occupied entry in a `HashMap`. /// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html @@ -1567,7 +1567,7 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { } } -/// A view into a single empty location in a HashMap. +/// A view into a vacant entry in a `HashMap`. /// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e56470c617f8..e3fad2850257 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -24,8 +24,7 @@ use super::map::{self, HashMap, Keys, RandomState}; // for `bucket.val` in the case of HashSet. I suppose we would need HKT // to get rid of it properly. -/// An implementation of a hash set using the underlying representation of a -/// `HashMap` where the value is (). +/// A hash set implemented as a `HashMap` where the value is `()`. /// /// As with the [`HashMap`] type, a `HashSet` requires that the elements /// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 73acf69c72cd..506bf717337b 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -442,16 +442,14 @@ mod hash; #[stable(feature = "rust1", since = "1.0.0")] pub mod hash_map { - //! A hash map implementation which uses linear probing with Robin - //! Hood bucket stealing. + //! A hash map implemented with linear probing and Robin Hood bucket stealing. #[stable(feature = "rust1", since = "1.0.0")] pub use super::hash::map::*; } #[stable(feature = "rust1", since = "1.0.0")] pub mod hash_set { - //! An implementation of a hash set using the underlying representation of a - //! `HashMap` where the value is (). + //! A hash set implemented as a `HashMap` where the value is `()`. #[stable(feature = "rust1", since = "1.0.0")] pub use super::hash::set::*; } From 537eb45b9d8f547046ae060d4c115e408fd66fdf Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 13 Apr 2017 14:34:32 -0400 Subject: [PATCH 474/905] Update various bookshelf repositories. The book and the reference have both had changes lately; this integrates them upstream. --- src/doc/book | 2 +- src/doc/reference | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book b/src/doc/book index a2c56870d4dc..beea82b9230c 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit a2c56870d4dc589237102cc5e0fe7b9ebd0d14a1 +Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 diff --git a/src/doc/reference b/src/doc/reference index acedc32cacae..b060f732145f 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit acedc32cacae80cf2f4925753a4ce7f7ffd7c86a +Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d From 15507bcb648964752db0d7fd37c4487780a7a5a4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 11:48:19 -0400 Subject: [PATCH 475/905] remove `metadata_*` from `SharedCrateContext` No good reason for them to be in there. --- src/librustc_trans/base.rs | 37 ++++++++++++++++++++--------------- src/librustc_trans/context.rs | 19 +----------------- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f76e816bcf0c..fd8beab92f5e 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -32,7 +32,7 @@ use assert_module_sources; use back::link; use back::linker::LinkerInfo; use back::symbol_export::{self, ExportedSymbols}; -use llvm::{Linkage, ValueRef, Vector, get_param}; +use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param}; use llvm; use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; @@ -56,7 +56,7 @@ use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; use consts; -use context::{SharedCrateContext, CrateContextList}; +use context::{self, SharedCrateContext, CrateContextList}; use debuginfo; use declare; use machine; @@ -726,9 +726,13 @@ fn contains_null(s: &str) -> bool { fn write_metadata(cx: &SharedCrateContext, exported_symbols: &NodeSet) - -> EncodedMetadata { + -> (ContextRef, ModuleRef, EncodedMetadata) { use flate; + let (metadata_llcx, metadata_llmod) = unsafe { + context::create_context_and_module(cx.sess(), "metadata") + }; + #[derive(PartialEq, Eq, PartialOrd, Ord)] enum MetadataKind { None, @@ -750,10 +754,10 @@ fn write_metadata(cx: &SharedCrateContext, }).max().unwrap(); if kind == MetadataKind::None { - return EncodedMetadata { + return (metadata_llcx, metadata_llmod, EncodedMetadata { raw_data: vec![], hashes: vec![], - }; + }); } let cstore = &cx.tcx().sess.cstore; @@ -761,19 +765,19 @@ fn write_metadata(cx: &SharedCrateContext, cx.link_meta(), exported_symbols); if kind == MetadataKind::Uncompressed { - return metadata; + return (metadata_llcx, metadata_llmod, metadata); } assert!(kind == MetadataKind::Compressed); let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata.raw_data)); - let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed); - let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); + let llmeta = C_bytes_in_context(metadata_llcx, &compressed); + let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false); let name = cx.metadata_symbol_name(); let buf = CString::new(name).unwrap(); let llglobal = unsafe { - llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf.as_ptr()) + llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr()) }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); @@ -787,9 +791,9 @@ fn write_metadata(cx: &SharedCrateContext, // metadata doesn't get loaded into memory. let directive = format!(".section {}", section_name); let directive = CString::new(directive).unwrap(); - llvm::LLVMSetModuleInlineAsm(cx.metadata_llmod(), directive.as_ptr()) + llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr()) } - return metadata; + return (metadata_llcx, metadata_llmod, metadata); } /// Find any symbols that are defined in one compilation unit, but not declared @@ -1070,16 +1074,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, exported_symbols, check_overflow); // Translate the metadata. - let metadata = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(&shared_ccx, shared_ccx.exported_symbols()) - }); + let (metadata_llcx, metadata_llmod, metadata) = + time(tcx.sess.time_passes(), "write metadata", || { + write_metadata(&shared_ccx, shared_ccx.exported_symbols()) + }); let metadata_module = ModuleTranslation { name: link::METADATA_MODULE_NAME.to_string(), symbol_name_hash: 0, // we always rebuild metadata, at least for now source: ModuleSource::Translated(ModuleLlvm { - llcx: shared_ccx.metadata_llcx(), - llmod: shared_ccx.metadata_llmod(), + llcx: metadata_llcx, + llmod: metadata_llmod, }), }; let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 98fbb64fd554..f080cd3eccfc 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -65,9 +65,6 @@ pub struct Stats { /// crate, so it must not contain references to any LLVM data structures /// (aside from metadata-related ones). pub struct SharedCrateContext<'a, 'tcx: 'a> { - metadata_llmod: ModuleRef, - metadata_llcx: ContextRef, - exported_symbols: NodeSet, link_meta: LinkMeta, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -347,7 +344,7 @@ pub fn is_pie_binary(sess: &Session) -> bool { !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC } -unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { +pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { let llcx = llvm::LLVMContextCreate(); let mod_name = CString::new(mod_name).unwrap(); let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); @@ -409,10 +406,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { exported_symbols: NodeSet, check_overflow: bool) -> SharedCrateContext<'b, 'tcx> { - let (metadata_llcx, metadata_llmod) = unsafe { - create_context_and_module(&tcx.sess, "metadata") - }; - // 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 @@ -459,8 +452,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; SharedCrateContext { - metadata_llmod: metadata_llmod, - metadata_llcx: metadata_llcx, exported_symbols: exported_symbols, link_meta: link_meta, empty_param_env: tcx.empty_parameter_environment(), @@ -492,14 +483,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP) } - pub fn metadata_llmod(&self) -> ModuleRef { - self.metadata_llmod - } - - pub fn metadata_llcx(&self) -> ContextRef { - self.metadata_llcx - } - pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { &self.exported_symbols } From b078ecefcde4d090ac2d365c5ee0d1314de7a341 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 12:07:25 -0400 Subject: [PATCH 476/905] rewrite to pass a ref, not slice + index --- src/librustc_trans/context.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index f080cd3eccfc..99ffd789286b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -266,10 +266,7 @@ impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans. pub struct CrateContext<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccxs: &'a [LocalCrateContext<'tcx>], - /// The index of `local` in `local_ccxs`. This is used in - /// `maybe_iter(true)` to identify the original `LocalCrateContext`. - index: usize, + local_ccx: &'a LocalCrateContext<'tcx>, } impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { @@ -298,8 +295,7 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { let ccx = CrateContext { shared: self.shared, - index: index, - local_ccxs: self.local_ccxs, + local_ccx: &self.local_ccxs[index], }; if @@ -630,8 +626,7 @@ impl<'tcx> LocalCrateContext<'tcx> { assert!(local_ccxs.len() == 1); CrateContext { shared: shared, - index: 0, - local_ccxs: local_ccxs + local_ccx: &local_ccxs[0] } } } @@ -642,7 +637,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } fn local(&self) -> &'b LocalCrateContext<'tcx> { - &self.local_ccxs[self.index] + self.local_ccx } pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { From 7b429242a51fad9cef64f6051ced26eb05fd0903 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 12:07:45 -0400 Subject: [PATCH 477/905] remove unused `link_meta` --- src/librustc_trans/context.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 99ffd789286b..c54929383f4d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -682,10 +682,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.shared.exported_symbols } - pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { - &self.shared.link_meta - } - pub fn needs_unwind_cleanup_cache(&self) -> &RefCell, bool>> { &self.local().needs_unwind_cleanup_cache } From 33875055f0f3c1c9c8c697b374f111377f35d8e2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 12:07:56 -0400 Subject: [PATCH 478/905] redirect `exported_symbols` through `shared` --- src/librustc_trans/context.rs | 4 ---- src/librustc_trans/debuginfo/utils.rs | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c54929383f4d..657dd56accd9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -678,10 +678,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } - pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { - &self.shared.exported_symbols - } - pub fn needs_unwind_cleanup_cache(&self) -> &RefCell, bool>> { &self.local().needs_unwind_cleanup_cache } diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index ceff96a39b2c..0a873767d935 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -37,7 +37,7 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool // 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.exported_symbols().contains(&node_id) + !cx.shared().exported_symbols().contains(&node_id) } #[allow(non_snake_case)] From fe78b546ed6764cae5d793bf75ff756d94007489 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 12:38:03 -0400 Subject: [PATCH 479/905] merge the "predeclare" and "declare" phases so we run them per-CGU --- src/librustc_trans/base.rs | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index fd8beab92f5e..0a08f49d818d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1142,7 +1142,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert_module_sources::assert_module_sources(tcx, &modules); - // Instantiate translation items without filling out definitions yet... for ccx in crate_context_list.iter_need_trans() { let dep_node = ccx.codegen_unit().work_product_dep_node(); tcx.dep_graph.with_task(dep_node, @@ -1150,35 +1149,22 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, AssertDepGraphSafe(symbol_map.clone()), trans_decl_task); + fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, symbol_map: AssertDepGraphSafe>>) { + // Instantiate translation items without filling out definitions yet... + // FIXME(#40304): Instead of this, the symbol-map should be an // on-demand thing that we compute. let AssertDepGraphSafe(symbol_map) = symbol_map; let cgu = ccx.codegen_unit(); let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); - for (trans_item, linkage) in trans_items { + for &(trans_item, linkage) in &trans_items { trans_item.predefine(&ccx, linkage); } - } - } - // ... and now that we have everything pre-defined, fill out those definitions. - for ccx in crate_context_list.iter_need_trans() { - let dep_node = ccx.codegen_unit().work_product_dep_node(); - tcx.dep_graph.with_task(dep_node, - ccx, - AssertDepGraphSafe(symbol_map.clone()), - trans_def_task); - - fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, - symbol_map: AssertDepGraphSafe>>) { - // FIXME(#40304): Instead of this, the symbol-map should be an - // on-demand thing that we compute. - let AssertDepGraphSafe(symbol_map) = symbol_map; - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); - for (trans_item, _) in trans_items { + // ... and now that we have everything pre-defined, fill out those definitions. + for &(trans_item, _) in &trans_items { trans_item.define(&ccx); } From 6cb516ad7b6e058be547e7ee5dc78762cc9b809b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 12:38:27 -0400 Subject: [PATCH 480/905] move `assert_module_sources` call down below --- src/librustc_trans/base.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 0a08f49d818d..ce136a7883cc 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1140,8 +1140,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) .collect(); - assert_module_sources::assert_module_sources(tcx, &modules); - for ccx in crate_context_list.iter_need_trans() { let dep_node = ccx.codegen_unit().work_product_dep_node(); tcx.dep_graph.with_task(dep_node, @@ -1205,6 +1203,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + assert_module_sources::assert_module_sources(tcx, &modules); + symbol_names_test::report_symbol_names(&shared_ccx); if shared_ccx.sess().trans_stats() { From bc79f01a581c9340cd869ba36579ee80d9606298 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 12:46:37 -0400 Subject: [PATCH 481/905] create `ModuleTranslation` all in one big loop --- src/librustc_trans/base.rs | 59 ++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ce136a7883cc..c822cc5f4b9a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1120,41 +1120,31 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, codegen_units, previous_work_products, symbol_map.clone()); - let modules: Vec<_> = crate_context_list.iter_all() - .map(|ccx| { - let source = match ccx.previous_work_product() { - Some(buf) => ModuleSource::Preexisting(buf.clone()), - None => ModuleSource::Translated(ModuleLlvm { - llcx: ccx.llcx(), - llmod: ccx.llmod(), - }), - }; - ModuleTranslation { - name: String::from(ccx.codegen_unit().name()), - symbol_name_hash: ccx.codegen_unit() - .compute_symbol_name_hash(&shared_ccx, - &symbol_map), - source: source, - } + let modules: Vec = crate_context_list + .iter_all() + .map(|ccx| { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + module_translation) }) .collect(); - for ccx in crate_context_list.iter_need_trans() { - let dep_node = ccx.codegen_unit().work_product_dep_node(); - tcx.dep_graph.with_task(dep_node, - ccx, - AssertDepGraphSafe(symbol_map.clone()), - trans_decl_task); + fn module_translation<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) + -> ModuleTranslation { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; - - fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, - symbol_map: AssertDepGraphSafe>>) { + let source = if let Some(buf) = ccx.previous_work_product() { + // Don't need to translate this module. + ModuleSource::Preexisting(buf.clone()) + } else { // Instantiate translation items without filling out definitions yet... - // FIXME(#40304): Instead of this, the symbol-map should be an - // on-demand thing that we compute. - let AssertDepGraphSafe(symbol_map) = symbol_map; let cgu = ccx.codegen_unit(); let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for &(trans_item, linkage) in &trans_items { @@ -1200,6 +1190,19 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); } + + ModuleSource::Translated(ModuleLlvm { + llcx: ccx.llcx(), + llmod: ccx.llmod(), + }) + }; + + ModuleTranslation { + name: String::from(ccx.codegen_unit().name()), + symbol_name_hash: ccx.codegen_unit() + .compute_symbol_name_hash(ccx.shared(), + &symbol_map), + source: source, } } From 863927c712d703709c0ee9fa709306ec90e5a88d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 13:14:37 -0400 Subject: [PATCH 482/905] rewrite post-processing routines not to require a `CrateContext` These do some low-level munging on the LLVM data structures. Unclear that they need to operate as a "second pass" but leave it for now. --- src/librustc_trans/base.rs | 41 +++++++++++++++++++++++------------ src/librustc_trans/context.rs | 15 ------------- src/librustc_trans/type_.rs | 10 ++++++++- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c822cc5f4b9a..a034974cb13e 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -799,7 +799,8 @@ fn write_metadata(cx: &SharedCrateContext, /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols<'a, 'tcx>(sess: &Session, - ccxs: &CrateContextList<'a, 'tcx>, + scx: &SharedCrateContext<'a, 'tcx>, + llvm_modules: &[ModuleLlvm], symbol_map: &SymbolMap<'tcx>, exported_symbols: &ExportedSymbols) { let export_threshold = @@ -814,7 +815,6 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, .map(|&(ref name, _)| &name[..]) .collect::>(); - let scx = ccxs.shared(); let tcx = scx.tcx(); let incr_comp = sess.opts.debugging_opts.incremental.is_some(); @@ -829,8 +829,8 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, // incremental compilation, we don't need to collect. See below for more // information. if !incr_comp { - for ccx in ccxs.iter_need_trans() { - for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { + for ll in llvm_modules { + for val in iter_globals(ll.llmod).chain(iter_functions(ll.llmod)) { let linkage = llvm::LLVMRustGetLinkage(val); // We only care about external declarations (not definitions) // and available_externally definitions. @@ -866,8 +866,8 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, // Examine each external definition. If the definition is not used in // any other compilation unit, and is not reachable from other crates, // then give it internal linkage. - for ccx in ccxs.iter_need_trans() { - for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { + for ll in llvm_modules { + for val in iter_globals(ll.llmod).chain(iter_functions(ll.llmod)) { let linkage = llvm::LLVMRustGetLinkage(val); let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) || @@ -926,19 +926,20 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, // 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_imps(cx: &CrateContextList) { +fn create_imps(sess: &Session, + llvm_modules: &[ModuleLlvm]) { // 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 cx.shared().sess().target.target.target_pointer_width == "32" { + let prefix = if sess.target.target.target_pointer_width == "32" { "\x01__imp__" } else { "\x01__imp_" }; unsafe { - for ccx in cx.iter_need_trans() { - let exported: Vec<_> = iter_globals(ccx.llmod()) + for ll in llvm_modules { + let exported: Vec<_> = iter_globals(ll.llmod) .filter(|&val| { llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage && @@ -946,13 +947,13 @@ fn create_imps(cx: &CrateContextList) { }) .collect(); - let i8p_ty = Type::i8p(&ccx); + let i8p_ty = Type::i8p_llcx(ll.llcx); for val in exported { 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(); - let imp = llvm::LLVMAddGlobal(ccx.llmod(), + let imp = llvm::LLVMAddGlobal(ll.llmod, i8p_ty.to_ref(), imp_name.as_ptr() as *const _); let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref()); @@ -1244,11 +1245,23 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let exported_symbols = ExportedSymbols::compute_from(&shared_ccx, &symbol_map); + // Get the list of llvm modules we created. We'll do a few wacky + // transforms on them now. + + let llvm_modules: Vec<_> = + modules.iter() + .filter_map(|module| match module.source { + ModuleSource::Translated(llvm) => Some(llvm), + _ => None, + }) + .collect(); + // Now that we have all symbols that are exported from the CGUs of this // crate, we can run the `internalize_symbols` pass. time(shared_ccx.sess().time_passes(), "internalize symbols", || { internalize_symbols(sess, - &crate_context_list, + &shared_ccx, + &llvm_modules, &symbol_map, &exported_symbols); }); @@ -1259,7 +1272,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if sess.target.target.options.is_like_msvc && sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { - create_imps(&crate_context_list); + create_imps(sess, &llvm_modules); } let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 657dd56accd9..e3b1e04c5303 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -244,21 +244,6 @@ impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { filter_to_previous_work_product_unavail: false, } } - - /// Iterator over all CCX that need translation (cannot reuse results from - /// previous incr. comp.). - pub fn iter_need_trans<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { - CrateContextIterator { - shared: self.shared, - index: 0, - local_ccxs: &self.local_ccxs[..], - filter_to_previous_work_product_unavail: true, - } - } - - pub fn shared(&self) -> &'a SharedCrateContext<'a, 'tcx> { - self.shared - } } /// A CrateContext value binds together one LocalCrateContext with the diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index f68acab91131..d70afc0cce5a 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -11,7 +11,7 @@ #![allow(non_upper_case_globals)] use llvm; -use llvm::{TypeRef, Bool, False, True, TypeKind}; +use llvm::{ContextRef, TypeRef, Bool, False, True, TypeKind}; use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; use context::CrateContext; @@ -82,6 +82,10 @@ impl Type { ty!(llvm::LLVMInt8TypeInContext(ccx.llcx())) } + pub fn i8_llcx(llcx: ContextRef) -> Type { + ty!(llvm::LLVMInt8TypeInContext(llcx)) + } + pub fn i16(ccx: &CrateContext) -> Type { ty!(llvm::LLVMInt16TypeInContext(ccx.llcx())) } @@ -123,6 +127,10 @@ impl Type { Type::i8(ccx).ptr_to() } + pub fn i8p_llcx(llcx: ContextRef) -> Type { + Type::i8_llcx(llcx).ptr_to() + } + pub fn int(ccx: &CrateContext) -> Type { match &ccx.tcx().sess.target.target.target_pointer_width[..] { "16" => Type::i16(ccx), From 3f59079f8a36af1d8b5ff5a218f16a8e4806a542 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 13:57:45 -0400 Subject: [PATCH 483/905] kill `CrateContextList` as a thing --- src/librustc_trans/base.rs | 119 ++++++++++++++-------------------- src/librustc_trans/context.rs | 99 ++++------------------------ 2 files changed, 63 insertions(+), 155 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a034974cb13e..309161676218 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -38,7 +38,7 @@ use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; use middle::cstore::EncodedMetadata; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; +use rustc::dep_graph::{AssertDepGraphSafe, DepNode}; use rustc::hir::map as hir_map; use rustc::util::common::time; use session::config::{self, NoDebugInfo}; @@ -56,7 +56,7 @@ use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; use consts; -use context::{self, SharedCrateContext, CrateContextList}; +use context::{self, LocalCrateContext, SharedCrateContext}; use debuginfo; use declare; use machine; @@ -1113,41 +1113,61 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let symbol_map = Rc::new(symbol_map); - let previous_work_products = trans_reuse_previous_work_products(&shared_ccx, - &codegen_units, - &symbol_map); - - let crate_context_list = CrateContextList::new(&shared_ccx, - codegen_units, - previous_work_products, - symbol_map.clone()); - - let modules: Vec = crate_context_list - .iter_all() - .map(|ccx| { - let dep_node = ccx.codegen_unit().work_product_dep_node(); + let modules: Vec = codegen_units + .into_iter() + .map(|cgu| { + let dep_node = cgu.work_product_dep_node(); tcx.dep_graph.with_task(dep_node, - ccx, - AssertDepGraphSafe(symbol_map.clone()), + AssertDepGraphSafe(&shared_ccx), + AssertDepGraphSafe((cgu, symbol_map.clone())), module_translation) }) .collect(); - fn module_translation<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, - symbol_map: AssertDepGraphSafe>>) - -> ModuleTranslation { - // FIXME(#40304): Instead of this, the symbol-map should be an - // on-demand thing that we compute. - let AssertDepGraphSafe(symbol_map) = symbol_map; + fn module_translation<'a, 'tcx>( + scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, + args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc>)>) + -> ModuleTranslation + { + // FIXME(#40304): We ought to be using the id as a key and some queries, I think. + let AssertDepGraphSafe(scx) = scx; + let AssertDepGraphSafe((cgu, symbol_map)) = args; - let source = if let Some(buf) = ccx.previous_work_product() { + let cgu_name = String::from(cgu.name()); + let cgu_id = cgu.work_product_id(); + let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_map); + + // 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. + let previous_work_product = + scx.dep_graph().previous_work_product(&cgu_id).and_then(|work_product| { + if work_product.input_hash == symbol_name_hash { + debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); + Some(work_product) + } else { + if scx.sess().opts.debugging_opts.incremental_info { + println!("incremental: CGU `{}` invalidated because of \ + changed partitioning hash.", + cgu.name()); + } + debug!("trans_reuse_previous_work_products: \ + not reusing {:?} because hash changed to {:?}", + work_product, symbol_name_hash); + None + } + }); + + let source = if let Some(buf) = previous_work_product { // Don't need to translate this module. ModuleSource::Preexisting(buf.clone()) } else { // Instantiate translation items without filling out definitions yet... - - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); + let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone()); + let ccx = CrateContext::new(scx, &lcx); + let trans_items = ccx.codegen_unit() + .items_in_deterministic_order(ccx.tcx(), &symbol_map); for &(trans_item, linkage) in &trans_items { trans_item.predefine(&ccx, linkage); } @@ -1199,11 +1219,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; ModuleTranslation { - name: String::from(ccx.codegen_unit().name()), - symbol_name_hash: ccx.codegen_unit() - .compute_symbol_name_hash(ccx.shared(), - &symbol_map), - source: source, + name: cgu_name, + symbol_name_hash, + source, } } @@ -1487,43 +1505,6 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } } -/// For each CGU, identify if we can reuse an existing object file (or -/// maybe other context). -fn trans_reuse_previous_work_products(scx: &SharedCrateContext, - codegen_units: &[CodegenUnit], - symbol_map: &SymbolMap) - -> Vec> { - debug!("trans_reuse_previous_work_products()"); - codegen_units - .iter() - .map(|cgu| { - let id = cgu.work_product_id(); - - let hash = cgu.compute_symbol_name_hash(scx, symbol_map); - - debug!("trans_reuse_previous_work_products: id={:?} hash={}", id, hash); - - if let Some(work_product) = scx.dep_graph().previous_work_product(&id) { - if work_product.input_hash == hash { - debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); - return Some(work_product); - } else { - if scx.sess().opts.debugging_opts.incremental_info { - println!("incremental: CGU `{}` invalidated because of \ - changed partitioning hash.", - cgu.name()); - } - debug!("trans_reuse_previous_work_products: \ - not reusing {:?} because hash changed to {:?}", - work_product, hash); - } - } - - None - }) - .collect() -} - fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> (Vec>, SymbolMap<'tcx>) { let time_passes = scx.sess().time_passes(); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index e3b1e04c5303..80d6f15518f9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,8 +10,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, - DepTrackingMapConfig, WorkProduct}; +use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig}; use middle::cstore::LinkMeta; use rustc::hir; use rustc::hir::def_id::DefId; @@ -86,7 +85,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, - previous_work_product: Option, codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, /// Cache instances of monomorphic and polymorphic items @@ -211,41 +209,6 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { } } -/// This list owns a number of LocalCrateContexts and binds them to their common -/// SharedCrateContext. This type just exists as a convenience, something to -/// pass around all LocalCrateContexts with and get an iterator over them. -pub struct CrateContextList<'a, 'tcx: 'a> { - shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccxs: Vec>, -} - -impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { - pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>, - codegen_units: Vec>, - previous_work_products: Vec>, - symbol_map: Rc>) - -> CrateContextList<'a, 'tcx> { - CrateContextList { - shared: shared_ccx, - local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, wp)| { - LocalCrateContext::new(shared_ccx, cgu, wp, symbol_map.clone()) - }).collect() - } - } - - /// Iterate over all crate contexts, whether or not they need - /// translation. That is, whether or not a `.o` file is available - /// for re-use from a previous incr. comp.). - pub fn iter_all<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { - CrateContextIterator { - shared: self.shared, - index: 0, - local_ccxs: &self.local_ccxs[..], - filter_to_previous_work_product_unavail: false, - } - } -} - /// A CrateContext value binds together one LocalCrateContext with the /// SharedCrateContext. It exists as a convenience wrapper, so we don't have to /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans. @@ -254,47 +217,17 @@ pub struct CrateContext<'a, 'tcx: 'a> { local_ccx: &'a LocalCrateContext<'tcx>, } -impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { -} - -pub struct CrateContextIterator<'a, 'tcx: 'a> { - shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccxs: &'a [LocalCrateContext<'tcx>], - index: usize, - - /// if true, only return results where `previous_work_product` is none - filter_to_previous_work_product_unavail: bool, -} - -impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { - type Item = CrateContext<'a, 'tcx>; - - fn next(&mut self) -> Option> { - loop { - if self.index >= self.local_ccxs.len() { - return None; - } - - let index = self.index; - self.index += 1; - - let ccx = CrateContext { - shared: self.shared, - local_ccx: &self.local_ccxs[index], - }; - - if - self.filter_to_previous_work_product_unavail && - ccx.previous_work_product().is_some() - { - continue; - } - - return Some(ccx); - } +impl<'a, 'tcx> CrateContext<'a, 'tcx> { + pub fn new(shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccx: &'a LocalCrateContext<'tcx>) + -> Self { + CrateContext { shared, local_ccx } } } +impl<'a, 'tcx> DepGraphSafe for CrateContext<'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[..], @@ -512,11 +445,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { } impl<'tcx> LocalCrateContext<'tcx> { - fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: CodegenUnit<'tcx>, - previous_work_product: Option, - symbol_map: Rc>) - -> LocalCrateContext<'tcx> { + pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, + codegen_unit: CodegenUnit<'tcx>, + symbol_map: Rc>) + -> LocalCrateContext<'tcx> { unsafe { // Append ".rs" to LLVM module identifier. // @@ -542,7 +474,6 @@ impl<'tcx> LocalCrateContext<'tcx> { let local_ccx = LocalCrateContext { llmod: llmod, llcx: llcx, - previous_work_product: previous_work_product, codegen_unit: codegen_unit, needs_unwind_cleanup_cache: RefCell::new(FxHashMap()), instances: RefCell::new(FxHashMap()), @@ -651,10 +582,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().llcx } - pub fn previous_work_product(&self) -> Option<&WorkProduct> { - self.local().previous_work_product.as_ref() - } - pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> { &self.local().codegen_unit } From c22fdf9a3ac1e316069d55effbfa5c91cc5c0a12 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 14:58:20 -0400 Subject: [PATCH 484/905] use `tcx.crate_name(LOCAL_CRATE)` rather than `LinkMeta::crate_name` --- src/librustc/middle/cstore.rs | 1 - src/librustc_driver/driver.rs | 2 +- src/librustc_metadata/encoder.rs | 4 ++-- src/librustc_trans/back/link.rs | 6 +----- src/librustc_trans/base.rs | 6 ++++-- src/librustc_trans/context.rs | 4 ++-- src/librustc_trans/debuginfo/metadata.rs | 4 ++-- src/librustc_trans/lib.rs | 2 ++ 8 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 81cf24e58dda..cbbfeacadb40 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -53,7 +53,6 @@ pub use self::NativeLibraryKind::*; #[derive(Clone, Debug)] pub struct LinkMeta { - pub crate_name: Symbol, pub crate_hash: Svh, } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 20ae561431b5..6b136d0fa0cb 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1140,7 +1140,7 @@ pub fn phase_6_link_output(sess: &Session, outputs: &OutputFilenames) { time(sess.time_passes(), "linking", - || link::link_binary(sess, trans, outputs, &trans.link.crate_name.as_str())); + || link::link_binary(sess, trans, outputs, &trans.crate_name.as_str())); } fn escape_dep_filename(filename: &str) -> String { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ffe68094c6af..3bf22f8a6c82 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -14,7 +14,7 @@ use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, EncodedMetadata, EncodedMetadataHash}; -use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE}; use rustc::hir::map::definitions::DefPathTable; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; @@ -1380,7 +1380,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let link_meta = self.link_meta; let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); let root = self.lazy(&CrateRoot { - name: link_meta.crate_name, + name: tcx.crate_name(LOCAL_CRATE), triple: tcx.sess.opts.target_triple.clone(), hash: link_meta.crate_hash, disambiguator: tcx.sess.local_crate_disambiguator(), diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 0ffa7a79408e..7468f4ace1b1 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -47,7 +47,6 @@ use std::str; use flate; use syntax::ast; use syntax::attr; -use syntax::symbol::Symbol; use syntax_pos::Span; /// The LLVM module name containing crate-metadata. This includes a `.` on @@ -136,11 +135,8 @@ pub fn find_crate_name(sess: Option<&Session>, "rust_out".to_string() } -pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap, - name: &str) - -> LinkMeta { +pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMeta { let r = LinkMeta { - crate_name: Symbol::intern(name), crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate].to_smaller_hash()), }; info!("{:?}", r); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 309161676218..e8ca2bd5e6c1 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1063,12 +1063,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // particular items that will be processed. let krate = tcx.hir.krate(); - let ty::CrateAnalysis { reachable, name, .. } = analysis; + let ty::CrateAnalysis { reachable, .. } = analysis; let exported_symbols = find_exported_symbols(tcx, reachable); let check_overflow = tcx.sess.overflow_checks(); - let link_meta = link::build_link_meta(incremental_hashes_map, &name); + let link_meta = link::build_link_meta(incremental_hashes_map); let shared_ccx = SharedCrateContext::new(tcx, link_meta.clone(), @@ -1096,6 +1096,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let empty_exported_symbols = ExportedSymbols::empty(); let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols); return CrateTranslation { + crate_name: tcx.crate_name(LOCAL_CRATE), modules: vec![], metadata_module: metadata_module, link: link_meta, @@ -1307,6 +1308,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); CrateTranslation { + crate_name: tcx.crate_name(LOCAL_CRATE), modules: modules, metadata_module: metadata_module, link: link_meta, diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 80d6f15518f9..0d7e70f6dd1a 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -13,7 +13,7 @@ use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig}; use middle::cstore::LinkMeta; use rustc::hir; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::traits; use debuginfo; use callee; @@ -439,7 +439,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn metadata_symbol_name(&self) -> String { format!("rust_metadata_{}_{}", - self.link_meta().crate_name, + self.tcx().crate_name(LOCAL_CRATE), self.link_meta().crate_hash) } } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 2d1c95114ebd..1f4756a94ea3 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -26,7 +26,7 @@ use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock, DIFlags}; use rustc::hir::def::CtorKind; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::ty::fold::TypeVisitor; use rustc::ty::subst::Substs; use rustc::ty::util::TypeIdHasher; @@ -810,7 +810,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, }; fn fallback_path(scc: &SharedCrateContext) -> CString { - CString::new(scc.link_meta().crate_name.to_string()).unwrap() + CString::new(scc.tcx().crate_name(LOCAL_CRATE).to_string()).unwrap() } } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 628d46f8e705..abda358bc4f8 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -40,6 +40,7 @@ #![feature(conservative_impl_trait)] use rustc::dep_graph::WorkProduct; +use syntax_pos::symbol::Symbol; extern crate flate; extern crate libc; @@ -165,6 +166,7 @@ unsafe impl Send for ModuleTranslation { } unsafe impl Sync for ModuleTranslation { } pub struct CrateTranslation { + pub crate_name: Symbol, pub modules: Vec, pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, From f227187cb8ddd76ef93e630adc56eefc09ae7e59 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 15:55:48 -0400 Subject: [PATCH 485/905] remove `LinkMeta` from `SharedCrateContext` A number of things were using `crate_hash` that really ought to be using `crate_disambiguator` (e.g., to create the plugin symbol names). They have been updated. It is important to remove `LinkMeta` from `SharedCrateContext` since it contains a hash of the entire crate, and hence it will change whenever **anything** changes (which would then require rebuilding **everything**). --- src/librustc/session/mod.rs | 12 +++++------- src/librustc_metadata/creader.rs | 6 +++--- src/librustc_plugin/load.rs | 4 ++-- src/librustc_trans/back/symbol_export.rs | 4 ++-- src/librustc_trans/back/symbol_names.rs | 8 ++++---- src/librustc_trans/base.rs | 7 ++++--- src/librustc_trans/context.rs | 10 +--------- 7 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 039db3d9ee91..adc9aabb8c77 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -13,7 +13,6 @@ pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo}; use dep_graph::DepGraph; use hir::def_id::{CrateNum, DefIndex}; -use hir::svh::Svh; use lint; use middle::cstore::CrateStore; use middle::dependency_format; @@ -402,15 +401,14 @@ impl Session { /// Returns the symbol name for the registrar function, /// given the crate Svh and the function DefIndex. - pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex) + pub fn generate_plugin_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex) -> String { - format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize()) + format!("__rustc_plugin_registrar__{}_{}", disambiguator, index.as_usize()) } - pub fn generate_derive_registrar_symbol(&self, - svh: &Svh, - index: DefIndex) -> String { - format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize()) + pub fn generate_derive_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex) + -> String { + format!("__rustc_derive_registrar__{}_{}", disambiguator, index.as_usize()) } pub fn sysroot<'a>(&'a self) -> &'a Path { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 04a8b88f8a59..a8ee999505e2 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -600,7 +600,7 @@ impl<'a> CrateLoader<'a> { Err(err) => self.sess.span_fatal(span, &err), }; - let sym = self.sess.generate_derive_registrar_symbol(&root.hash, + let sym = self.sess.generate_derive_registrar_symbol(root.disambiguator, root.macro_derive_registrar.unwrap()); let registrar = unsafe { let sym = match lib.symbol(&sym) { @@ -654,7 +654,7 @@ impl<'a> CrateLoader<'a> { /// Look for a plugin registrar. Returns library path, crate /// SVH and DefIndex of the registrar function. pub fn find_plugin_registrar(&mut self, span: Span, name: &str) - -> Option<(PathBuf, Svh, DefIndex)> { + -> Option<(PathBuf, Symbol, DefIndex)> { let ekrate = self.read_extension_crate(span, &ExternCrateInfo { name: Symbol::intern(name), ident: Symbol::intern(name), @@ -675,7 +675,7 @@ impl<'a> CrateLoader<'a> { let root = ekrate.metadata.get_root(); match (ekrate.dylib.as_ref(), root.plugin_registrar_fn) { (Some(dylib), Some(reg)) => { - Some((dylib.to_path_buf(), root.hash, reg)) + Some((dylib.to_path_buf(), root.disambiguator, reg)) } (None, Some(_)) => { span_err!(self.sess, span, E0457, diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index e884f3bdbb12..ed49e8a14c8c 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -100,8 +100,8 @@ impl<'a> PluginLoader<'a> { fn load_plugin(&mut self, span: Span, name: &str, args: Vec) { let registrar = self.reader.find_plugin_registrar(span, name); - if let Some((lib, svh, index)) = registrar { - let symbol = self.sess.generate_plugin_registrar_symbol(&svh, index); + if let Some((lib, disambiguator, index)) = registrar { + let symbol = self.sess.generate_plugin_registrar_symbol(disambiguator, index); let fun = self.dylink_registrar(span, lib, symbol); self.plugins.push(PluginRegistrar { fun: fun, diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 23a67ef5046e..04617edf4a7a 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -64,10 +64,10 @@ impl ExportedSymbols { } if let Some(id) = scx.sess().derive_registrar_fn.get() { - let svh = &scx.link_meta().crate_hash; let def_id = scx.tcx().hir.local_def_id(id); let idx = def_id.index; - let registrar = scx.sess().generate_derive_registrar_symbol(svh, idx); + let disambiguator = scx.sess().local_crate_disambiguator(); + let registrar = scx.sess().generate_derive_registrar_symbol(disambiguator, idx); local_crate.push((registrar, SymbolExportLevel::C)); } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 3568c1ba8f4c..8facbd6cc278 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -179,14 +179,14 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, if let Some(id) = node_id { if scx.sess().plugin_registrar_fn.get() == Some(id) { - let svh = &scx.link_meta().crate_hash; let idx = def_id.index; - return scx.sess().generate_plugin_registrar_symbol(svh, idx); + let disambiguator = scx.sess().local_crate_disambiguator(); + return scx.sess().generate_plugin_registrar_symbol(disambiguator, idx); } if scx.sess().derive_registrar_fn.get() == Some(id) { - let svh = &scx.link_meta().crate_hash; let idx = def_id.index; - return scx.sess().generate_derive_registrar_symbol(svh, idx); + let disambiguator = scx.sess().local_crate_disambiguator(); + return scx.sess().generate_derive_registrar_symbol(disambiguator, idx); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index e8ca2bd5e6c1..cec599e28484 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -39,6 +39,7 @@ use middle::lang_items::StartFnLangItem; use middle::cstore::EncodedMetadata; use rustc::ty::{self, Ty, TyCtxt}; use rustc::dep_graph::{AssertDepGraphSafe, DepNode}; +use rustc::middle::cstore::LinkMeta; use rustc::hir::map as hir_map; use rustc::util::common::time; use session::config::{self, NoDebugInfo}; @@ -725,6 +726,7 @@ fn contains_null(s: &str) -> bool { } fn write_metadata(cx: &SharedCrateContext, + link_meta: &LinkMeta, exported_symbols: &NodeSet) -> (ContextRef, ModuleRef, EncodedMetadata) { use flate; @@ -762,7 +764,7 @@ fn write_metadata(cx: &SharedCrateContext, let cstore = &cx.tcx().sess.cstore; let metadata = cstore.encode_metadata(cx.tcx(), - cx.link_meta(), + &link_meta, exported_symbols); if kind == MetadataKind::Uncompressed { return (metadata_llcx, metadata_llmod, metadata); @@ -1071,13 +1073,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let link_meta = link::build_link_meta(incremental_hashes_map); let shared_ccx = SharedCrateContext::new(tcx, - link_meta.clone(), exported_symbols, check_overflow); // Translate the metadata. let (metadata_llcx, metadata_llmod, metadata) = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(&shared_ccx, shared_ccx.exported_symbols()) + write_metadata(&shared_ccx, &link_meta, shared_ccx.exported_symbols()) }); let metadata_module = ModuleTranslation { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 0d7e70f6dd1a..9d18b4574bcc 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -11,7 +11,6 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig}; -use middle::cstore::LinkMeta; use rustc::hir; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::traits; @@ -65,7 +64,6 @@ pub struct Stats { /// (aside from metadata-related ones). pub struct SharedCrateContext<'a, 'tcx: 'a> { exported_symbols: NodeSet, - link_meta: LinkMeta, tcx: TyCtxt<'a, 'tcx, 'tcx>, empty_param_env: ty::ParameterEnvironment<'tcx>, stats: Stats, @@ -316,7 +314,6 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, - link_meta: LinkMeta, exported_symbols: NodeSet, check_overflow: bool) -> SharedCrateContext<'b, 'tcx> { @@ -367,7 +364,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { SharedCrateContext { exported_symbols: exported_symbols, - link_meta: link_meta, empty_param_env: tcx.empty_parameter_environment(), tcx: tcx, stats: Stats { @@ -409,10 +405,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.project_cache } - pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { - &self.link_meta - } - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx } @@ -440,7 +432,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn metadata_symbol_name(&self) -> String { format!("rust_metadata_{}_{}", self.tcx().crate_name(LOCAL_CRATE), - self.link_meta().crate_hash) + self.tcx().crate_disambiguator(LOCAL_CRATE)) } } From 8e26983c86c6e6a51c85e1bd5c4621f3b43afe99 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 17:11:54 -0400 Subject: [PATCH 486/905] pull stats out of `SharedCrateContext` shared mutable state is bad --- src/librustc_trans/base.rs | 70 ++++++++++++++++++++--------------- src/librustc_trans/context.rs | 41 +++++++++++--------- 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index cec599e28484..3fd966eb73ee 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -57,7 +57,7 @@ use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; use consts; -use context::{self, LocalCrateContext, SharedCrateContext}; +use context::{self, LocalCrateContext, SharedCrateContext, Stats}; use debuginfo; use declare; use machine; @@ -1115,21 +1115,25 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let symbol_map = Rc::new(symbol_map); + let mut all_stats = Stats::default(); let modules: Vec = codegen_units .into_iter() .map(|cgu| { let dep_node = cgu.work_product_dep_node(); - tcx.dep_graph.with_task(dep_node, - AssertDepGraphSafe(&shared_ccx), - AssertDepGraphSafe((cgu, symbol_map.clone())), - module_translation) + let (stats, module) = + tcx.dep_graph.with_task(dep_node, + AssertDepGraphSafe(&shared_ccx), + AssertDepGraphSafe((cgu, symbol_map.clone())), + module_translation); + all_stats.extend(stats); + module }) .collect(); fn module_translation<'a, 'tcx>( scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc>)>) - -> ModuleTranslation + -> (Stats, ModuleTranslation) { // FIXME(#40304): We ought to be using the id as a key and some queries, I think. let AssertDepGraphSafe(scx) = scx; @@ -1161,12 +1165,19 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }); - let source = if let Some(buf) = previous_work_product { + if let Some(buf) = previous_work_product { // Don't need to translate this module. - ModuleSource::Preexisting(buf.clone()) - } else { - // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone()); + let module = ModuleTranslation { + name: cgu_name, + symbol_name_hash, + source: ModuleSource::Preexisting(buf.clone()) + }; + return (Stats::default(), module); + } + + // Instantiate translation items without filling out definitions yet... + let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone()); + let module = { let ccx = CrateContext::new(scx, &lcx); let trans_items = ccx.codegen_unit() .items_in_deterministic_order(ccx.tcx(), &symbol_map); @@ -1214,17 +1225,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debuginfo::finalize(&ccx); } - ModuleSource::Translated(ModuleLlvm { - llcx: ccx.llcx(), - llmod: ccx.llmod(), - }) + ModuleTranslation { + name: cgu_name, + symbol_name_hash, + source: ModuleSource::Translated(ModuleLlvm { + llcx: ccx.llcx(), + llmod: ccx.llmod(), + }) + } }; - ModuleTranslation { - name: cgu_name, - symbol_name_hash, - source, - } + (lcx.into_stats(), module) } assert_module_sources::assert_module_sources(tcx, &modules); @@ -1232,20 +1243,19 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, symbol_names_test::report_symbol_names(&shared_ccx); if shared_ccx.sess().trans_stats() { - let stats = shared_ccx.stats(); println!("--- trans stats ---"); - println!("n_glues_created: {}", stats.n_glues_created.get()); - println!("n_null_glues: {}", stats.n_null_glues.get()); - println!("n_real_glues: {}", stats.n_real_glues.get()); + println!("n_glues_created: {}", all_stats.n_glues_created.get()); + println!("n_null_glues: {}", all_stats.n_null_glues.get()); + println!("n_real_glues: {}", all_stats.n_real_glues.get()); - println!("n_fns: {}", stats.n_fns.get()); - println!("n_inlines: {}", stats.n_inlines.get()); - println!("n_closures: {}", stats.n_closures.get()); + println!("n_fns: {}", all_stats.n_fns.get()); + println!("n_inlines: {}", all_stats.n_inlines.get()); + println!("n_closures: {}", all_stats.n_closures.get()); println!("fn stats:"); - stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| { + all_stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| { insns_b.cmp(&insns_a) }); - for tuple in stats.fn_stats.borrow().iter() { + for tuple in all_stats.fn_stats.borrow().iter() { match *tuple { (ref name, insns) => { println!("{} insns, {}", insns, *name); @@ -1255,7 +1265,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } if shared_ccx.sess().count_llvm_insns() { - for (k, v) in shared_ccx.stats().llvm_insns.borrow().iter() { + for (k, v) in all_stats.llvm_insns.borrow().iter() { println!("{:7} {}", *v, *k); } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 9d18b4574bcc..7e49dee498d0 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -45,6 +45,7 @@ use syntax::symbol::InternedString; use syntax_pos::DUMMY_SP; use abi::Abi; +#[derive(Clone, Default)] pub struct Stats { pub n_glues_created: Cell, pub n_null_glues: Cell, @@ -58,6 +59,22 @@ pub struct Stats { pub fn_stats: RefCell >, } +impl Stats { + pub fn extend(&mut self, stats: Stats) { + self.n_glues_created.set(self.n_glues_created.get() + stats.n_glues_created.get()); + self.n_null_glues.set(self.n_null_glues.get() + stats.n_null_glues.get()); + self.n_real_glues.set(self.n_real_glues.get() + stats.n_real_glues.get()); + self.n_fns.set(self.n_fns.get() + stats.n_fns.get()); + self.n_inlines.set(self.n_inlines.get() + stats.n_inlines.get()); + self.n_closures.set(self.n_closures.get() + stats.n_closures.get()); + self.n_llvm_insns.set(self.n_llvm_insns.get() + stats.n_llvm_insns.get()); + self.llvm_insns.borrow_mut().extend( + stats.llvm_insns.borrow().iter() + .map(|(key, value)| (key.clone(), value.clone()))); + self.fn_stats.borrow_mut().append(&mut *stats.fn_stats.borrow_mut()); + } +} + /// The shared portion of a `CrateContext`. There is one `SharedCrateContext` /// per crate. The data here is shared between all compilation units of the /// crate, so it must not contain references to any LLVM data structures @@ -66,7 +83,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { exported_symbols: NodeSet, tcx: TyCtxt<'a, 'tcx, 'tcx>, empty_param_env: ty::ParameterEnvironment<'tcx>, - stats: Stats, check_overflow: bool, use_dll_storage_attrs: bool, @@ -83,6 +99,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, + stats: Stats, codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, /// Cache instances of monomorphic and polymorphic items @@ -366,17 +383,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { exported_symbols: exported_symbols, empty_param_env: tcx.empty_parameter_environment(), tcx: tcx, - stats: Stats { - n_glues_created: Cell::new(0), - n_null_glues: Cell::new(0), - n_real_glues: Cell::new(0), - n_fns: Cell::new(0), - n_inlines: Cell::new(0), - n_closures: Cell::new(0), - n_llvm_insns: Cell::new(0), - llvm_insns: RefCell::new(FxHashMap()), - fn_stats: RefCell::new(Vec::new()), - }, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, translation_items: RefCell::new(FxHashSet()), @@ -417,10 +423,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.tcx.dep_graph } - pub fn stats<'a>(&'a self) -> &'a Stats { - &self.stats - } - pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } @@ -466,6 +468,7 @@ impl<'tcx> LocalCrateContext<'tcx> { let local_ccx = LocalCrateContext { llmod: llmod, llcx: llcx, + stats: Stats::default(), codegen_unit: codegen_unit, needs_unwind_cleanup_cache: RefCell::new(FxHashMap()), instances: RefCell::new(FxHashMap()), @@ -537,6 +540,10 @@ impl<'tcx> LocalCrateContext<'tcx> { local_ccx: &local_ccxs[0] } } + + pub fn into_stats(self) -> Stats { + self.stats + } } impl<'b, 'tcx> CrateContext<'b, 'tcx> { @@ -651,7 +658,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn stats<'a>(&'a self) -> &'a Stats { - &self.shared.stats + &self.local().stats } pub fn int_type(&self) -> Type { From f2487b81523a4f39a5ad27a9d28b198e4cc4dfda Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 18:08:36 -0400 Subject: [PATCH 487/905] refactor `metadata_symbol_name` --- src/librustc_trans/back/symbol_export.rs | 9 ++++++++- src/librustc_trans/base.rs | 2 +- src/librustc_trans/context.rs | 8 +------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 04617edf4a7a..5d6717272fdf 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -15,6 +15,7 @@ use back::symbol_names::symbol_name; use util::nodemap::FxHashMap; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::session::config; +use rustc::ty::TyCtxt; use syntax::attr; use trans_item::TransItem; @@ -72,7 +73,7 @@ impl ExportedSymbols { } if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) { - local_crate.push((scx.metadata_symbol_name(), + local_crate.push((metadata_symbol_name(scx.tcx()), SymbolExportLevel::Rust)); } @@ -173,6 +174,12 @@ impl ExportedSymbols { } } +pub fn metadata_symbol_name(tcx: TyCtxt) -> String { + format!("rust_metadata_{}_{}", + tcx.crate_name(LOCAL_CRATE), + tcx.crate_disambiguator(LOCAL_CRATE)) +} + pub fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel { match crate_type { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3fd966eb73ee..b364814d07e8 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -776,7 +776,7 @@ fn write_metadata(cx: &SharedCrateContext, let llmeta = C_bytes_in_context(metadata_llcx, &compressed); let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false); - let name = cx.metadata_symbol_name(); + let name = symbol_export::metadata_symbol_name(cx.tcx()); let buf = CString::new(name).unwrap(); let llglobal = unsafe { llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr()) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 7e49dee498d0..c3770470bfd0 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -12,7 +12,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig}; use rustc::hir; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::DefId; use rustc::traits; use debuginfo; use callee; @@ -430,12 +430,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn translation_items(&self) -> &RefCell>> { &self.translation_items } - - pub fn metadata_symbol_name(&self) -> String { - format!("rust_metadata_{}_{}", - self.tcx().crate_name(LOCAL_CRATE), - self.tcx().crate_disambiguator(LOCAL_CRATE)) - } } impl<'tcx> LocalCrateContext<'tcx> { From 07fb93e65ad2c371a59e8f671650c5b343ef5487 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Apr 2017 18:21:51 -0400 Subject: [PATCH 488/905] make `write_metadata` take `tcx` intead of `SharedCrateContext` --- src/librustc_trans/base.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index b364814d07e8..c770bbdb90f7 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -725,14 +725,14 @@ fn contains_null(s: &str) -> bool { s.bytes().any(|b| b == 0) } -fn write_metadata(cx: &SharedCrateContext, - link_meta: &LinkMeta, - exported_symbols: &NodeSet) - -> (ContextRef, ModuleRef, EncodedMetadata) { +fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, + link_meta: &LinkMeta, + exported_symbols: &NodeSet) + -> (ContextRef, ModuleRef, EncodedMetadata) { use flate; let (metadata_llcx, metadata_llmod) = unsafe { - context::create_context_and_module(cx.sess(), "metadata") + context::create_context_and_module(tcx.sess, "metadata") }; #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -742,7 +742,7 @@ fn write_metadata(cx: &SharedCrateContext, Compressed } - let kind = cx.sess().crate_types.borrow().iter().map(|ty| { + let kind = tcx.sess.crate_types.borrow().iter().map(|ty| { match *ty { config::CrateTypeExecutable | config::CrateTypeStaticlib | @@ -762,8 +762,8 @@ fn write_metadata(cx: &SharedCrateContext, }); } - let cstore = &cx.tcx().sess.cstore; - let metadata = cstore.encode_metadata(cx.tcx(), + let cstore = &tcx.sess.cstore; + let metadata = cstore.encode_metadata(tcx, &link_meta, exported_symbols); if kind == MetadataKind::Uncompressed { @@ -776,7 +776,7 @@ fn write_metadata(cx: &SharedCrateContext, let llmeta = C_bytes_in_context(metadata_llcx, &compressed); let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false); - let name = symbol_export::metadata_symbol_name(cx.tcx()); + let name = symbol_export::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()) @@ -784,7 +784,7 @@ fn write_metadata(cx: &SharedCrateContext, unsafe { llvm::LLVMSetInitializer(llglobal, llconst); let section_name = - cx.tcx().sess.cstore.metadata_section_name(&cx.sess().target.target); + tcx.sess.cstore.metadata_section_name(&tcx.sess.target.target); let name = CString::new(section_name).unwrap(); llvm::LLVMSetSection(llglobal, name.as_ptr()); @@ -1078,7 +1078,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Translate the metadata. let (metadata_llcx, metadata_llmod, metadata) = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(&shared_ccx, &link_meta, shared_ccx.exported_symbols()) + write_metadata(tcx, &link_meta, shared_ccx.exported_symbols()) }); let metadata_module = ModuleTranslation { From baeec7b8eb3ee0fd7a40bff409400903e5679ff5 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 14 Apr 2017 02:58:54 +0200 Subject: [PATCH 489/905] Avoid to use floating point match Its going to be forbidden, see issue 41255. --- src/librand/distributions/gamma.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index e024b62adfb1..9a42b82beff6 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -103,12 +103,14 @@ impl Gamma { assert!(shape > 0.0, "Gamma::new called with shape <= 0"); assert!(scale > 0.0, "Gamma::new called with scale <= 0"); - let repr = match shape { - 1.0 => One(Exp::new(1.0 / scale)), - 0.0...1.0 => Small(GammaSmallShape::new_raw(shape, scale)), - _ => Large(GammaLargeShape::new_raw(shape, scale)), + let repr = if shape == 1.0 { + One(Exp::new(1.0 / scale)) + } else if 0.0 <= shape && shape < 1.0 { + Small(GammaSmallShape::new_raw(shape, scale)) + } else { + Large(GammaLargeShape::new_raw(shape, scale)) }; - Gamma { repr: repr } + Gamma { repr } } } From a35c4e354a65fdbbb61741db3a9dd1c190f2f146 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Thu, 13 Apr 2017 23:41:03 -0500 Subject: [PATCH 490/905] Comply with windows symbol name conventions --- src/test/run-pass/simple_global_asm.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs index ac2cacf3db21..cd8273c6bc2b 100644 --- a/src/test/run-pass/simple_global_asm.rs +++ b/src/test/run-pass/simple_global_asm.rs @@ -14,7 +14,9 @@ #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] global_asm!(r#" .global foo + .global _foo foo: +_foo: ret "#); From 5a09d7c3de6cc5daf1b9925a8e7d19edf44c27a7 Mon Sep 17 00:00:00 2001 From: Evgeny Safronov Date: Mon, 6 Mar 2017 09:03:31 +0300 Subject: [PATCH 491/905] Add `as_bytes()` for `FromUtf8Error`. This change allows to obtain an underlying invalid UTF-8 bytes without `FromUtf8Error` destruction. Such method may be useful for example in a library that attempts to save both valid and invalid UTF-8 strings in some struct and to be able to provide immutable access to it without destruction. --- src/libcollections/string.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 7d9d7276201b..12f582404dc7 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1403,6 +1403,25 @@ impl String { } impl FromUtf8Error { + /// Returns a slice of [`u8`]s bytes that were attempted to convert to a `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // some invalid bytes, in a vector + /// let bytes = vec![0, 159]; + /// + /// let value = String::from_utf8(bytes); + /// + /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes()); + /// ``` + #[unstable(feature = "from_utf8_error_as_bytes", issue = "40895")] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes[..] + } + /// Returns the bytes that were attempted to convert to a `String`. /// /// This method is carefully constructed to avoid allocation. It will From 4cb9de48fbf3e616d80bb6726ce590e06c763a1e Mon Sep 17 00:00:00 2001 From: Evgeny Safronov Date: Sat, 8 Apr 2017 19:37:46 +0300 Subject: [PATCH 492/905] fix: add feature to doc tests --- src/libcollections/string.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 12f582404dc7..6da4cc1c7138 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1410,6 +1410,7 @@ impl FromUtf8Error { /// Basic usage: /// /// ``` + /// #![feature(from_utf8_error_as_bytes)] /// // some invalid bytes, in a vector /// let bytes = vec![0, 159]; /// From 0eecd5150d7d7456f324fe654076d6f9709c5106 Mon Sep 17 00:00:00 2001 From: Evgeny Safronov Date: Sat, 8 Apr 2017 21:25:30 +0300 Subject: [PATCH 493/905] refactor: add reason string --- src/libcollections/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 6da4cc1c7138..8d6cf3051126 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1418,7 +1418,7 @@ impl FromUtf8Error { /// /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes()); /// ``` - #[unstable(feature = "from_utf8_error_as_bytes", issue = "40895")] + #[unstable(feature = "from_utf8_error_as_bytes", reason = "recently added", issue = "40895")] pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] } From 4cea3f74037bf0f7c61968949a764b5de20414b5 Mon Sep 17 00:00:00 2001 From: Evgeny Safronov Date: Mon, 10 Apr 2017 19:12:33 +0300 Subject: [PATCH 494/905] docs: track newly introduced unstable feature --- src/doc/unstable-book/src/from_utf8_error_as_bytes.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/doc/unstable-book/src/from_utf8_error_as_bytes.md diff --git a/src/doc/unstable-book/src/from_utf8_error_as_bytes.md b/src/doc/unstable-book/src/from_utf8_error_as_bytes.md new file mode 100644 index 000000000000..570f779417f0 --- /dev/null +++ b/src/doc/unstable-book/src/from_utf8_error_as_bytes.md @@ -0,0 +1,7 @@ +# `from_utf8_error_as_bytes` + +The tracking issue for this feature is: [#40895] + +[#40895]: https://github.com/rust-lang/rust/issues/40895 + +------------------------ From 3ae20deac7f7a4e9d5bcb640dd4e2eacd9c2cfe3 Mon Sep 17 00:00:00 2001 From: Evgeny Safronov Date: Tue, 11 Apr 2017 09:01:10 +0300 Subject: [PATCH 495/905] fix: add missing link in SUMMARY.md --- src/doc/unstable-book/src/SUMMARY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 14774e2d2293..9acb7b4afe7e 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -78,6 +78,8 @@ - [fmt_internals](fmt-internals.md) - [fn_traits](fn-traits.md) - [fnbox](fnbox.md) +- [field_init_shorthand](field-init-shorthand.md) +- [from_utf8_error_as_bytes](from_utf8_error_as_bytes.md) - [fundamental](fundamental.md) - [fused](fused.md) - [future_atomic_orderings](future-atomic-orderings.md) From bb843582cac721b1a478c6dc12dafee1edbd73e4 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Sat, 8 Apr 2017 08:39:31 +0100 Subject: [PATCH 496/905] Add a comment for disabling errexit --- appveyor.yml | 3 +-- src/ci/init_repo.sh | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 9070c5d9edf1..978ca0d9739b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -148,8 +148,7 @@ test_script: - sh src/ci/run.sh on_failure: - - cat %CD%\sccache.log - - cat C:\Users\appveyor\AppData\Local\Temp\1\build-cache-logs\*.log + - cat %CD%\sccache.log || exit 0 cache: - C:\cache\rustsrc diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 633b88dd2c42..1db2135eb6d8 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -41,6 +41,8 @@ if [ ! -f "$cache_valid_file" ]; then rm -rf "$CACHE_DIR" mkdir "$CACHE_DIR" else + # Ignore errors while gathering information about the possible brokenness + # of the git repo since our gathered info will tell us something is wrong set +o errexit stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1; echo $?) From e9c74bc42db1f811820bd829f99c023d3d007628 Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Fri, 14 Apr 2017 17:14:20 +0200 Subject: [PATCH 497/905] Use associated constants in core::num::dec2flt --- src/libcore/lib.rs | 1 + src/libcore/num/dec2flt/algorithm.rs | 38 +++--- src/libcore/num/dec2flt/mod.rs | 20 +-- src/libcore/num/dec2flt/rawfp.rs | 192 ++++++++++----------------- 4 files changed, 99 insertions(+), 152 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index af6134274931..80c2221ce641 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,6 +70,7 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_type_defaults)] +#![feature(associated_consts)] #![feature(cfg_target_feature)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 60dab943a3ac..42bc46c0c683 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -106,17 +106,17 @@ mod fpu_precision { /// a bignum. pub fn fast_path(integral: &[u8], fractional: &[u8], e: i64) -> Option { let num_digits = integral.len() + fractional.len(); - // log_10(f64::max_sig) ~ 15.95. We compare the exact value to max_sig near the end, + // log_10(f64::MAX_SIG) ~ 15.95. We compare the exact value to MAX_SIG near the end, // this is just a quick, cheap rejection (and also frees the rest of the code from // worrying about underflow). if num_digits > 16 { return None; } - if e.abs() >= T::ceil_log5_of_max_sig() as i64 { + if e.abs() >= T::CEIL_LOG5_OF_MAX_SIG as i64 { return None; } let f = num::from_str_unchecked(integral.iter().chain(fractional.iter())); - if f > T::max_sig() { + if f > T::MAX_SIG { return None; } @@ -154,14 +154,14 @@ pub fn fast_path(integral: &[u8], fractional: &[u8], e: i64) -> Opt /// > the best possible approximation that uses p bits of significand.) pub fn bellerophon(f: &Big, e: i16) -> T { let slop; - if f <= &Big::from_u64(T::max_sig()) { + if f <= &Big::from_u64(T::MAX_SIG) { // The cases abs(e) < log5(2^N) are in fast_path() slop = if e >= 0 { 0 } else { 3 }; } else { slop = if e >= 0 { 1 } else { 4 }; } let z = rawfp::big_to_fp(f).mul(&power_of_ten(e)).normalize(); - let exp_p_n = 1 << (P - T::sig_bits() as u32); + let exp_p_n = 1 << (P - T::SIG_BITS as u32); let lowbits: i64 = (z.f % exp_p_n) as i64; // Is the slop large enough to make a difference when // rounding to n bits? @@ -210,14 +210,14 @@ fn algorithm_r(f: &Big, e: i16, z0: T) -> T { if d2 < y { let mut d2_double = d2; d2_double.mul_pow2(1); - if m == T::min_sig() && d_negative && d2_double > y { + if m == T::MIN_SIG && d_negative && d2_double > y { z = prev_float(z); } else { return z; } } else if d2 == y { if m % 2 == 0 { - if m == T::min_sig() && d_negative { + if m == T::MIN_SIG && d_negative { z = prev_float(z); } else { return z; @@ -303,12 +303,12 @@ pub fn algorithm_m(f: &Big, e: i16) -> T { quick_start::(&mut u, &mut v, &mut k); let mut rem = Big::from_small(0); let mut x = Big::from_small(0); - let min_sig = Big::from_u64(T::min_sig()); - let max_sig = Big::from_u64(T::max_sig()); + let min_sig = Big::from_u64(T::MIN_SIG); + let max_sig = Big::from_u64(T::MAX_SIG); loop { u.div_rem(&v, &mut x, &mut rem); - if k == T::min_exp_int() { - // We have to stop at the minimum exponent, if we wait until `k < T::min_exp_int()`, + if k == T::MIN_EXP_INT { + // We have to stop at the minimum exponent, if we wait until `k < T::MIN_EXP_INT`, // then we'd be off by a factor of two. Unfortunately this means we have to special- // case normal numbers with the minimum exponent. // FIXME find a more elegant formulation, but run the `tiny-pow10` test to make sure @@ -318,8 +318,8 @@ pub fn algorithm_m(f: &Big, e: i16) -> T { } return underflow(x, v, rem); } - if k > T::max_exp_int() { - return T::infinity2(); + if k > T::MAX_EXP_INT { + return T::INFINITY; } if x < min_sig { u.mul_pow2(1); @@ -345,18 +345,18 @@ fn quick_start(u: &mut Big, v: &mut Big, k: &mut i16) { // The target ratio is one where u/v is in an in-range significand. Thus our termination // condition is log2(u / v) being the significand bits, plus/minus one. // FIXME Looking at the second bit could improve the estimate and avoid some more divisions. - let target_ratio = T::sig_bits() as i16; + let target_ratio = T::SIG_BITS as i16; let log2_u = u.bit_length() as i16; let log2_v = v.bit_length() as i16; let mut u_shift: i16 = 0; let mut v_shift: i16 = 0; assert!(*k == 0); loop { - if *k == T::min_exp_int() { + if *k == T::MIN_EXP_INT { // Underflow or subnormal. Leave it to the main function. break; } - if *k == T::max_exp_int() { + if *k == T::MAX_EXP_INT { // Overflow. Leave it to the main function. break; } @@ -376,7 +376,7 @@ fn quick_start(u: &mut Big, v: &mut Big, k: &mut i16) { } fn underflow(x: Big, v: Big, rem: Big) -> T { - if x < Big::from_u64(T::min_sig()) { + if x < Big::from_u64(T::MIN_SIG) { let q = num::to_u64(&x); let z = rawfp::encode_subnormal(q); return round_by_remainder(v, rem, q, z); @@ -395,9 +395,9 @@ fn underflow(x: Big, v: Big, rem: Big) -> T { // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainder // is zero, we have a half-to-even situation. let bits = x.bit_length(); - let lsb = bits - T::sig_bits() as usize; + let lsb = bits - T::SIG_BITS as usize; let q = num::get_bits(&x, lsb, bits); - let k = T::min_exp_int() + lsb as i16; + let k = T::MIN_EXP_INT + lsb as i16; let z = rawfp::encode_normal(Unpacked::new(q, k)); let q_even = q % 2 == 0; match num::compare_with_half_ulp(&x, lsb) { diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs index eee3e9250fe8..f353770a736e 100644 --- a/src/libcore/num/dec2flt/mod.rs +++ b/src/libcore/num/dec2flt/mod.rs @@ -214,11 +214,11 @@ fn dec2flt(s: &str) -> Result { let (sign, s) = extract_sign(s); let flt = match parse_decimal(s) { ParseResult::Valid(decimal) => convert(decimal)?, - ParseResult::ShortcutToInf => T::infinity2(), - ParseResult::ShortcutToZero => T::zero2(), + ParseResult::ShortcutToInf => T::INFINITY, + ParseResult::ShortcutToZero => T::ZERO, ParseResult::Invalid => match s { - "inf" => T::infinity2(), - "NaN" => T::nan2(), + "inf" => T::INFINITY, + "NaN" => T::NAN, _ => { return Err(pfe_invalid()); } } }; @@ -254,7 +254,7 @@ fn convert(mut decimal: Decimal) -> Result { // FIXME These bounds are rather conservative. A more careful analysis of the failure modes // of Bellerophon could allow using it in more cases for a massive speed up. let exponent_in_range = table::MIN_E <= e && e <= table::MAX_E; - let value_in_range = upper_bound <= T::max_normal_digits() as u64; + let value_in_range = upper_bound <= T::MAX_NORMAL_DIGITS as u64; if exponent_in_range && value_in_range { Ok(algorithm::bellerophon(&f, e)) } else { @@ -315,17 +315,17 @@ fn bound_intermediate_digits(decimal: &Decimal, e: i64) -> u64 { fn trivial_cases(decimal: &Decimal) -> Option { // There were zeros but they were stripped by simplify() if decimal.integral.is_empty() && decimal.fractional.is_empty() { - return Some(T::zero2()); + return Some(T::ZERO); } // This is a crude approximation of ceil(log10(the real value)). We don't need to worry too // much about overflow here because the input length is tiny (at least compared to 2^64) and // the parser already handles exponents whose absolute value is greater than 10^18 // (which is still 10^19 short of 2^64). let max_place = decimal.exp + decimal.integral.len() as i64; - if max_place > T::inf_cutoff() { - return Some(T::infinity2()); - } else if max_place < T::zero_cutoff() { - return Some(T::zero2()); + if max_place > T::INF_CUTOFF { + return Some(T::INFINITY); + } else if max_place < T::ZERO_CUTOFF { + return Some(T::ZERO); } None } diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 45fa721a5a33..1485c79ead25 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -56,24 +56,12 @@ 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. -/// The "methods" (pseudo-constants) with default implementation should not be overriden. pub trait RawFloat : Float + Copy + Debug + LowerExp + Mul + Div + Neg { - // suffix of "2" because Float::infinity is deprecated - #[allow(deprecated)] - fn infinity2() -> Self { - Float::infinity() - } - - // suffix of "2" because Float::nan is deprecated - #[allow(deprecated)] - fn nan2() -> Self { - Float::nan() - } - - // suffix of "2" because Float::zero is deprecated - fn zero2() -> Self; + const INFINITY: Self; + const NAN: Self; + const ZERO: Self; // suffix of "2" because Float::integer_decode is deprecated #[allow(deprecated)] @@ -94,94 +82,83 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp /// represented, the other code in this module makes sure to never let that happen. fn from_int(x: u64) -> Self; - /// Get the value 10e from a pre-computed table. Panics for e >= - /// ceil_log5_of_max_sig(). + /// Get the value 10e from a pre-computed table. + /// Panics for `e >= CEIL_LOG5_OF_MAX_SIG`. fn short_fast_pow10(e: usize) -> Self; - // FIXME Everything that follows should be associated constants, but taking the value of an - // associated constant from a type parameter does not work (yet?) - // A possible workaround is having a `FloatInfo` struct for all the constants, but so far - // the methods aren't painful enough to rewrite. - /// What the name says. It's easier to hard code than juggling intrinsics and /// hoping LLVM constant folds it. - fn ceil_log5_of_max_sig() -> i16; + const CEIL_LOG5_OF_MAX_SIG: i16; // A conservative bound on the decimal digits of inputs that can't produce overflow or zero or /// subnormals. Probably the decimal exponent of the maximum normal value, hence the name. - fn max_normal_digits() -> usize; + const MAX_NORMAL_DIGITS: usize; /// When the most significant decimal digit has a place value greater than this, the number /// is certainly rounded to infinity. - fn inf_cutoff() -> i64; + const INF_CUTOFF: i64; /// When the most significant decimal digit has a place value less than this, the number /// is certainly rounded to zero. - fn zero_cutoff() -> i64; + const ZERO_CUTOFF: i64; /// The number of bits in the exponent. - fn exp_bits() -> u8; + const EXP_BITS: u8; /// The number of bits in the singificand, *including* the hidden bit. - fn sig_bits() -> u8; + const SIG_BITS: u8; /// The number of bits in the singificand, *excluding* the hidden bit. - fn explicit_sig_bits() -> u8 { - Self::sig_bits() - 1 - } + const EXPLICIT_SIG_BITS: u8; /// The maximum legal exponent in fractional representation. - fn max_exp() -> i16 { - (1 << (Self::exp_bits() - 1)) - 1 - } + const MAX_EXP: i16; /// The minimum legal exponent in fractional representation, excluding subnormals. - fn min_exp() -> i16 { - -Self::max_exp() + 1 - } + const MIN_EXP: i16; /// `MAX_EXP` for integral representation, i.e., with the shift applied. - fn max_exp_int() -> i16 { - Self::max_exp() - (Self::sig_bits() as i16 - 1) - } + const MAX_EXP_INT: i16; /// `MAX_EXP` encoded (i.e., with offset bias) - fn max_encoded_exp() -> i16 { - (1 << Self::exp_bits()) - 1 - } + const MAX_ENCODED_EXP: i16; /// `MIN_EXP` for integral representation, i.e., with the shift applied. - fn min_exp_int() -> i16 { - Self::min_exp() - (Self::sig_bits() as i16 - 1) - } + const MIN_EXP_INT: i16; /// The maximum normalized singificand in integral representation. - fn max_sig() -> u64 { - (1 << Self::sig_bits()) - 1 - } + const MAX_SIG: u64; /// The minimal normalized significand in integral representation. - fn min_sig() -> u64 { - 1 << (Self::sig_bits() - 1) + const MIN_SIG: u64; +} + +// Mostly a workaround for #34344. +macro_rules! other_constants { + ($type: ident) => { + const EXPLICIT_SIG_BITS: u8 = Self::SIG_BITS - 1; + const MAX_EXP: i16 = (1 << (Self::EXP_BITS - 1)) - 1; + const MIN_EXP: i16 = -Self::MAX_EXP + 1; + const MAX_EXP_INT: i16 = Self::MAX_EXP - (Self::SIG_BITS as i16 - 1); + const MAX_ENCODED_EXP: i16 = (1 << Self::EXP_BITS) - 1; + const MIN_EXP_INT: i16 = Self::MIN_EXP - (Self::SIG_BITS as i16 - 1); + const MAX_SIG: u64 = (1 << Self::SIG_BITS) - 1; + const MIN_SIG: u64 = 1 << (Self::SIG_BITS - 1); + + const INFINITY: Self = $crate::$type::INFINITY; + const NAN: Self = $crate::$type::NAN; + const ZERO: Self = 0.0; } } impl RawFloat for f32 { - fn zero2() -> Self { - 0.0 - } - - fn sig_bits() -> u8 { - 24 - } - - fn exp_bits() -> u8 { - 8 - } - - fn ceil_log5_of_max_sig() -> i16 { - 11 - } + const SIG_BITS: u8 = 24; + const EXP_BITS: u8 = 8; + const CEIL_LOG5_OF_MAX_SIG: i16 = 11; + const MAX_NORMAL_DIGITS: usize = 35; + const INF_CUTOFF: i64 = 40; + const ZERO_CUTOFF: i64 = -48; + other_constants!(f32); fn transmute(self) -> u64 { let bits: u32 = unsafe { transmute(self) }; @@ -207,37 +184,17 @@ impl RawFloat for f32 { fn short_fast_pow10(e: usize) -> Self { table::F32_SHORT_POWERS[e] } - - fn max_normal_digits() -> usize { - 35 - } - - fn inf_cutoff() -> i64 { - 40 - } - - fn zero_cutoff() -> i64 { - -48 - } } impl RawFloat for f64 { - fn zero2() -> Self { - 0.0 - } - - fn sig_bits() -> u8 { - 53 - } - - fn exp_bits() -> u8 { - 11 - } - - fn ceil_log5_of_max_sig() -> i16 { - 23 - } + const SIG_BITS: u8 = 53; + const EXP_BITS: u8 = 11; + const CEIL_LOG5_OF_MAX_SIG: i16 = 23; + const MAX_NORMAL_DIGITS: usize = 305; + const INF_CUTOFF: i64 = 310; + const ZERO_CUTOFF: i64 = -326; + other_constants!(f64); fn transmute(self) -> u64 { let bits: u64 = unsafe { transmute(self) }; @@ -262,38 +219,27 @@ impl RawFloat for f64 { fn short_fast_pow10(e: usize) -> Self { table::F64_SHORT_POWERS[e] } - - fn max_normal_digits() -> usize { - 305 - } - - fn inf_cutoff() -> i64 { - 310 - } - - fn zero_cutoff() -> i64 { - -326 - } - } -/// Convert an Fp to the closest f64. Only handles number that fit into a normalized f64. +/// Convert an Fp to the closest machine float type. +/// Does not handle subnormal results. pub fn fp_to_float(x: Fp) -> T { let x = x.normalize(); // x.f is 64 bit, so x.e has a mantissa shift of 63 let e = x.e + 63; - if e > T::max_exp() { + if e > T::MAX_EXP { panic!("fp_to_float: exponent {} too large", e) - } else if e > T::min_exp() { + } else if e > T::MIN_EXP { encode_normal(round_normal::(x)) } else { panic!("fp_to_float: exponent {} too small", e) } } -/// Round the 64-bit significand to 53 bit with half-to-even. Does not handle exponent overflow. +/// Round the 64-bit significand to T::SIG_BITS bits with half-to-even. +/// Does not handle exponent overflow. pub fn round_normal(x: Fp) -> Unpacked { - let excess = 64 - T::sig_bits() as i16; + let excess = 64 - T::SIG_BITS as i16; let half: u64 = 1 << (excess - 1); let (q, rem) = (x.f >> excess, x.f & ((1 << excess) - 1)); assert_eq!(q << excess | rem, x.f); @@ -303,8 +249,8 @@ pub fn round_normal(x: Fp) -> Unpacked { Unpacked::new(q, k) } else if rem == half && (q % 2) == 0 { Unpacked::new(q, k) - } else if q == T::max_sig() { - Unpacked::new(T::min_sig(), k + 1) + } else if q == T::MAX_SIG { + Unpacked::new(T::MIN_SIG, k + 1) } else { Unpacked::new(q + 1, k) } @@ -313,22 +259,22 @@ pub fn round_normal(x: Fp) -> Unpacked { /// Inverse of `RawFloat::unpack()` for normalized numbers. /// Panics if the significand or exponent are not valid for normalized numbers. pub fn encode_normal(x: Unpacked) -> T { - debug_assert!(T::min_sig() <= x.sig && x.sig <= T::max_sig(), + debug_assert!(T::MIN_SIG <= x.sig && x.sig <= T::MAX_SIG, "encode_normal: significand not normalized"); // Remove the hidden bit - let sig_enc = x.sig & !(1 << T::explicit_sig_bits()); + let sig_enc = x.sig & !(1 << T::EXPLICIT_SIG_BITS); // Adjust the exponent for exponent bias and mantissa shift - let k_enc = x.k + T::max_exp() + T::explicit_sig_bits() as i16; - debug_assert!(k_enc != 0 && k_enc < T::max_encoded_exp(), + let k_enc = x.k + T::MAX_EXP + T::EXPLICIT_SIG_BITS as i16; + debug_assert!(k_enc != 0 && k_enc < T::MAX_ENCODED_EXP, "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; + let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc; T::from_bits(bits) } -/// Construct the subnormal. A mantissa of 0 is allowed and constructs zero. +/// 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"); + 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) } @@ -364,8 +310,8 @@ pub fn prev_float(x: T) -> T { Zero => panic!("prev_float: argument is zero"), Normal => { let Unpacked { sig, k } = x.unpack(); - if sig == T::min_sig() { - encode_normal(Unpacked::new(T::max_sig(), k - 1)) + if sig == T::MIN_SIG { + encode_normal(Unpacked::new(T::MAX_SIG, k - 1)) } else { encode_normal(Unpacked::new(sig - 1, k)) } @@ -380,7 +326,7 @@ pub fn prev_float(x: T) -> T { pub fn next_float(x: T) -> T { match x.classify() { Nan => panic!("next_float: argument is NaN"), - Infinite => T::infinity2(), + Infinite => T::INFINITY, // This seems too good to be true, but it works. // 0.0 is encoded as the all-zero word. Subnormals are 0x000m...m where m is the mantissa. // In particular, the smallest subnormal is 0x0...01 and the largest is 0x000F...F. From ec27aa97b921957711b96e578c7c197ff28553ac Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Fri, 14 Apr 2017 19:17:03 +0200 Subject: [PATCH 498/905] Compile WASM as WASM instead of asm.js Looks like the LinkerFlavor change introduced in #40018 accidentally uses GCC for the WebAssembly target, causing Rust to never actually pass the post link args to emscripten. This then causes the code to be compiled as asm.js instead of WebAssembly, because the Binaryen tools never run due to the missing linker argument. --- src/librustc_back/target/wasm32_unknown_emscripten.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs index a51f59d6ff19..f5fb63038e91 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -14,7 +14,7 @@ use super::emscripten_base::{cmd}; pub fn target() -> Result { let mut post_link_args = LinkArgs::new(); - post_link_args.insert(LinkerFlavor::Gcc, + post_link_args.insert(LinkerFlavor::Em, vec!["-s".to_string(), "BINARYEN=1".to_string(), "-s".to_string(), From 2a23e6e277bc6a6a00c5e5d9d5a159265bef8c24 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Fri, 14 Apr 2017 23:36:27 +0200 Subject: [PATCH 499/905] std::collections docs: Address issues that came up in PR #41286 * Bound: * Added another example using RangeArgument to illustrate how Bound maps to range endpoints. * Added a note to the existing example that says that it's better to use range syntax in most cases * Added missing /// line * binary_heap::PeakMut: s/Object representing/Structure wrapping * added collections/hash_set/struct.HashSet.html to linkchecker whitelist --- src/libcollections/binary_heap.rs | 2 +- src/libcollections/lib.rs | 19 +++++++++++++++++++ src/tools/linkchecker/main.rs | 3 ++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 89d9576cba2a..149c285a72a9 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -219,7 +219,7 @@ pub struct BinaryHeap { data: Vec, } -/// Object representing a mutable reference to the greatest item on a +/// Structure wrapping a mutable reference to the greatest item on a /// `BinaryHeap`. /// /// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 4ff54095bd35..a207087915a3 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -135,8 +135,25 @@ mod std { } /// 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}; @@ -152,6 +169,8 @@ mod std { /// /// 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 { diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 8c4eb728b756..137de561c76c 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -142,7 +142,8 @@ fn check(cache: &mut Cache, if file.ends_with("btree_set/struct.BTreeSet.html") || file.ends_with("collections/struct.BTreeSet.html") || file.ends_with("collections/btree_map/struct.BTreeMap.html") || - file.ends_with("collections/hash_map/struct.HashMap.html") { + file.ends_with("collections/hash_map/struct.HashMap.html") || + file.ends_with("collections/hash_set/struct.HashSet.html") { return None; } From 63ed7843bbf7fff95779eaa192b7d38a9e0978ca Mon Sep 17 00:00:00 2001 From: nate Date: Fri, 14 Apr 2017 13:08:07 -0700 Subject: [PATCH 500/905] add 'mir' as part of the --emit flag list in rustc --help menu and man doc. This is added because 'rustc' can now generate MIR (referencing to "Teach rustc --emit=mir #39891"). --- man/rustc.1 | 2 +- src/librustc/session/config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/rustc.1 b/man/rustc.1 index 165625595619..6c80f11fa720 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -50,7 +50,7 @@ Comma separated list of types of crates for the compiler to emit. \fB\-\-crate\-name\fR \fINAME\fR Specify the name of the crate being built. .TP -\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info][=\fIPATH\fR] +\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info|mir][=\fIPATH\fR] Configure the output that \fBrustc\fR will produce. Each emission may also have an optional explicit output \fIPATH\fR specified for that particular emission kind. This path takes precedence over the \fB-o\fR option. diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index b9a974045bce..fadb1844008c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1246,7 +1246,7 @@ pub fn rustc_short_optgroups() -> Vec { "NAME"), opt::multi_s("", "emit", "Comma separated list of types of output for \ the compiler to emit", - "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info]"), + "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]"), opt::multi_s("", "print", "Comma separated list of compiler information to \ print on stdout", &format!("[{}]", &print_opts.join("|"))), From c5979945daf502a690514b117dbbb4d20f1528cd Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 03:33:12 +0300 Subject: [PATCH 501/905] [rustbuild] Side-step HashMap iteration to preserve command-line step order. --- src/bootstrap/step.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6008fa81c665..34705040e8a5 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -1217,8 +1217,8 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? let mut visited = HashSet::new(); visited.insert(0); let idx_to_node = nodes.iter().map(|p| (*p.1, p.0)).collect::>(); - for idx in nodes.values() { - self.topo_sort(*idx, &idx_to_node, &edges, &mut visited, &mut order); + for idx in 0..nodes.len() { + self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order); } return order } From 1d05a0237c93e29bee6688e15502f15388a739b2 Mon Sep 17 00:00:00 2001 From: Theodore DeRego Date: Fri, 14 Apr 2017 18:37:57 -0700 Subject: [PATCH 502/905] Update magenta error codes --- src/libstd/sys/unix/process/magenta.rs | 87 ++++++++++++++------------ 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs index 07f29784df60..5b5e29c0374f 100644 --- a/src/libstd/sys/unix/process/magenta.rs +++ b/src/libstd/sys/unix/process/magenta.rs @@ -202,7 +202,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // ERR_NO_RESOURCES: The system was not able to allocate some resource // needed for the operation. -#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -5; +#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -3; // ERR_NO_MEMORY: The system was not able to allocate memory needed // for the operation. @@ -210,30 +210,34 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // ERR_CALL_FAILED: The second phase of mx_channel_call(; did not complete // successfully. -#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -53; +#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -5; + +// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be +// retried. This should not be seen outside of the VDSO. +#[allow(unused)] pub const ERR_INTERRUPTED_RETRY: mx_status_t = -6; // ======= Parameter errors ======= // ERR_INVALID_ARGS: an argument is invalid, ex. null pointer #[allow(unused)] pub const ERR_INVALID_ARGS: mx_status_t = -10; +// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. +#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -11; + // ERR_WRONG_TYPE: The subject of the operation is the wrong type to // perform the operation. // Example: Attempting a message_read on a thread handle. -#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -54; +#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -12; // ERR_BAD_SYSCALL: The specified syscall number is invalid. -#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -11; - -// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. -#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -12; +#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -13; // ERR_OUT_OF_RANGE: An argument is outside the valid range for this // operation. -#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -13; +#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -14; // ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for // this operation. -#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -14; +#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -15; // ======= Precondition or state errors ======= // ERR_BAD_STATE: operation failed because the current state of the @@ -241,37 +245,9 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // not satisfied #[allow(unused)] pub const ERR_BAD_STATE: mx_status_t = -20; -// ERR_NOT_FOUND: The requested entity is not found. -#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -3; - -// ERR_ALREADY_EXISTS: An object with the specified identifier -// already exists. -// Example: Attempting to create a file when a file already exists -// with that name. -#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -15; - -// ERR_ALREADY_BOUND: The operation failed because the named entity -// is already owned or controlled by another entity. The operation -// could succeed later if the current owner releases the entity. -#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -16; - // ERR_TIMED_OUT: The time limit for the operation elapsed before // the operation completed. -#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -23; - -// ERR_HANDLE_CLOSED: a handle being waited on was closed -#[allow(unused)] pub const ERR_HANDLE_CLOSED: mx_status_t = -24; - -// ERR_REMOTE_CLOSED: The operation failed because the remote end -// of the subject of the operation was closed. -#[allow(unused)] pub const ERR_REMOTE_CLOSED: mx_status_t = -25; - -// ERR_UNAVAILABLE: The subject of the operation is currently unable -// to perform the operation. -// Note: This is used when there's no direct way for the caller to -// observe when the subject will be able to perform the operation -// and should thus retry. -#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -26; +#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -21; // ERR_SHOULD_WAIT: The operation cannot be performed currently but // potentially could succeed if the caller waits for a prerequisite @@ -281,7 +257,36 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // messages waiting but has an open remote will return ERR_SHOULD_WAIT. // Attempting to read from a message pipe that has no messages waiting // and has a closed remote end will return ERR_REMOTE_CLOSED. -#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -27; +#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -22; + +// ERR_CANCELED: The in-progress operation (e.g. a wait) has been +// // canceled. +#[allow(unused)] pub const ERR_CANCELED: mx_status_t = -23; + +// ERR_PEER_CLOSED: The operation failed because the remote end +// of the subject of the operation was closed. +#[allow(unused)] pub const ERR_PEER_CLOSED: mx_status_t = -24; + +// ERR_NOT_FOUND: The requested entity is not found. +#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -25; + +// ERR_ALREADY_EXISTS: An object with the specified identifier +// already exists. +// Example: Attempting to create a file when a file already exists +// with that name. +#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -26; + +// ERR_ALREADY_BOUND: The operation failed because the named entity +// is already owned or controlled by another entity. The operation +// could succeed later if the current owner releases the entity. +#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -27; + +// ERR_UNAVAILABLE: The subject of the operation is currently unable +// to perform the operation. +// Note: This is used when there's no direct way for the caller to +// observe when the subject will be able to perform the operation +// and should thus retry. +#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -28; // ======= Permission check errors ======= // ERR_ACCESS_DENIED: The caller did not have permission to perform @@ -312,3 +317,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; #[allow(unused)] pub const ERR_BAD_PATH: mx_status_t = -50; #[allow(unused)] pub const ERR_NOT_DIR: mx_status_t = -51; #[allow(unused)] pub const ERR_NOT_FILE: mx_status_t = -52; +// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit. +#[allow(unused)] pub const ERR_FILE_BIG: mx_status_t = -53; +// ERR_NO_SPACE: Filesystem or device space is exhausted. +#[allow(unused)] pub const ERR_NO_SPACE: mx_status_t = -54; From 4aca54001865435c799757c6fcb8595c23ff6c77 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sat, 25 Feb 2017 16:16:27 -0500 Subject: [PATCH 503/905] Implement RFC 1268 This patch allows overlap to occur between any two impls of a trait for traits which have no associated items. Several compile-fail tests around coherence had to be changed to add at least one item to the trait they test against. Ref #29864 --- src/librustc/traits/specialize/mod.rs | 5 ++++ .../traits/specialize/specialization_graph.rs | 5 ++++ src/librustc/ty/mod.rs | 10 ++++++++ src/test/compile-fail/E0120.rs | 2 +- ...herence-conflicting-negative-trait-impl.rs | 2 +- .../coherence-default-trait-impl.rs | 2 +- src/test/compile-fail/coherence-impls-send.rs | 1 - .../coherence-no-direct-lifetime-dispatch.rs | 2 +- .../coherence-overlap-all-t-and-tuple.rs | 1 + .../coherence-overlap-messages.rs | 8 +++---- .../coherence-projection-conflict-orphan.rs | 2 +- .../coherence-projection-conflict-ty-param.rs | 2 +- .../coherence-projection-conflict.rs | 2 +- ...erence_copy_like_err_fundamental_struct.rs | 2 +- ...ce_copy_like_err_fundamental_struct_ref.rs | 2 +- ..._copy_like_err_fundamental_struct_tuple.rs | 2 +- .../coherence_copy_like_err_struct.rs | 2 +- .../coherence_copy_like_err_tuple.rs | 2 +- .../specialization/specialization-overlap.rs | 8 +++---- .../overlap-permitted-for-marker-traits.rs | 23 +++++++++++++++++++ 20 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/overlap-permitted-for-marker-traits.rs diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 50a4d982832a..6455de48a299 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -155,6 +155,11 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return r; } + if tcx.impl_always_allowed_to_overlap(impl1_def_id) + && tcx.impl_always_allowed_to_overlap(impl2_def_id) { + return true; + } + // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. if !tcx.sess.features.borrow().specialization && diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 40eb69395678..87abe681d393 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -113,6 +113,11 @@ impl<'a, 'gcx, 'tcx> Children { possible_sibling, impl_def_id); if let Some(impl_header) = overlap { + if tcx.impl_always_allowed_to_overlap(impl_def_id) + && tcx.impl_always_allowed_to_overlap(possible_sibling) { + return Ok((true, true)); + } + let le = specializes(tcx, impl_def_id, possible_sibling); let ge = specializes(tcx, possible_sibling, impl_def_id); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8ff91583d082..9fdabd38d4ab 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,6 +2227,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::impl_trait_ref::get(self, DUMMY_SP, id) } + /// Returns true if the impl is positive and is for a triat which contains + /// no items + pub fn impl_always_allowed_to_overlap(self, def_id: DefId) -> bool { + self.trait_impl_polarity(def_id) == hir::ImplPolarity::Positive + && self.impl_trait_ref(def_id) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }) + } + // Returns `ty::VariantDef` if `def` refers to a struct, // or variant or their constructors, panics otherwise. pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef { diff --git a/src/test/compile-fail/E0120.rs b/src/test/compile-fail/E0120.rs index 3fdeb7531754..80cc0d2680f7 100644 --- a/src/test/compile-fail/E0120.rs +++ b/src/test/compile-fail/E0120.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait MyTrait {} +trait MyTrait { fn foo() {} } impl Drop for MyTrait { //~^ ERROR E0120 diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs index 7fd1b17f2966..d841e8c41d98 100644 --- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs @@ -20,8 +20,8 @@ impl !Send for TestType {} //~^ ERROR conflicting implementations of trait `std::marker::Send` unsafe impl Send for TestType {} -//~^ ERROR conflicting implementations of trait `std::marker::Send` impl !Send for TestType {} +//~^ ERROR conflicting implementations of trait `std::marker::Send` fn main() {} diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs index 15a80c64f8b0..e6bf068156c2 100644 --- a/src/test/compile-fail/coherence-default-trait-impl.rs +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -10,7 +10,7 @@ #![feature(optin_builtin_traits)] -trait MyTrait {} +trait MyTrait { fn foo() {} } impl MyTrait for .. {} //~^ ERROR redundant default implementations of trait `MyTrait` diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index f130a9353516..d0e6bc6a1c69 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -34,7 +34,6 @@ unsafe impl Send for [MyType] {} unsafe impl Send for &'static [NotSync] {} //~^ ERROR E0117 -//~| ERROR E0119 fn main() { } diff --git a/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs b/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs index 6de338f1db0f..47026cd32d41 100644 --- a/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs +++ b/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs @@ -10,7 +10,7 @@ // Test that you cannot *directly* dispatch on lifetime requirements -trait MyTrait {} +trait MyTrait { fn foo() {} } impl MyTrait for T {} impl MyTrait for T {} //~ ERROR E0119 diff --git a/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs index 928ba7a36db2..1fad608db6c3 100644 --- a/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs +++ b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs @@ -17,6 +17,7 @@ // Seems pretty basic, but then there was issue #24241. :) trait From { + fn foo() {} } impl From for T { diff --git a/src/test/compile-fail/coherence-overlap-messages.rs b/src/test/compile-fail/coherence-overlap-messages.rs index 0ae8135221c2..a10deeafbe67 100644 --- a/src/test/compile-fail/coherence-overlap-messages.rs +++ b/src/test/compile-fail/coherence-overlap-messages.rs @@ -8,22 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo {} +trait Foo { fn foo() {} } impl Foo for T {} impl Foo for U {} //~ ERROR conflicting implementations of trait `Foo`: -trait Bar {} +trait Bar { fn bar() {} } impl Bar for (T, u8) {} impl Bar for (u8, T) {} //~ ERROR conflicting implementations of trait `Bar` for type `(u8, u8)`: -trait Baz {} +trait Baz { fn baz() {} } impl Baz for T {} impl Baz for u8 {} //~ ERROR conflicting implementations of trait `Baz` for type `u8`: -trait Quux {} +trait Quux { fn quux() {} } impl Quux for T {} impl Quux for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`: diff --git a/src/test/compile-fail/coherence-projection-conflict-orphan.rs b/src/test/compile-fail/coherence-projection-conflict-orphan.rs index 3ed3549de89a..784ff0cd5e0a 100644 --- a/src/test/compile-fail/coherence-projection-conflict-orphan.rs +++ b/src/test/compile-fail/coherence-projection-conflict-orphan.rs @@ -15,7 +15,7 @@ // due to the orphan rules. Therefore, `A::Item` may yet turn out to // be `i32`. -pub trait Foo

    {} +pub trait Foo

    { fn foo() {} } pub trait Bar { type Output: 'static; diff --git a/src/test/compile-fail/coherence-projection-conflict-ty-param.rs b/src/test/compile-fail/coherence-projection-conflict-ty-param.rs index f04902a70f68..120d9046389a 100644 --- a/src/test/compile-fail/coherence-projection-conflict-ty-param.rs +++ b/src/test/compile-fail/coherence-projection-conflict-ty-param.rs @@ -13,7 +13,7 @@ use std::marker::PhantomData; -pub trait Foo

    {} +pub trait Foo

    { fn foo() {} } impl > Foo

    for Option {} diff --git a/src/test/compile-fail/coherence-projection-conflict.rs b/src/test/compile-fail/coherence-projection-conflict.rs index 6d3ab32f06f4..3c32ab38b93d 100644 --- a/src/test/compile-fail/coherence-projection-conflict.rs +++ b/src/test/compile-fail/coherence-projection-conflict.rs @@ -10,7 +10,7 @@ use std::marker::PhantomData; -pub trait Foo

    {} +pub trait Foo

    { fn foo() {} } pub trait Bar { type Output: 'static; diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs index fcd6e5c49520..9fbb7aa4cb1a 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs @@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs index b5c0a7fb5f56..2f6dca4f3c27 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs @@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs index 8e3e3f31cb5f..f424e8872010 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs @@ -19,7 +19,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } diff --git a/src/test/compile-fail/coherence_copy_like_err_struct.rs b/src/test/compile-fail/coherence_copy_like_err_struct.rs index 35bc17b8e887..04262e65c5a2 100644 --- a/src/test/compile-fail/coherence_copy_like_err_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_struct.rs @@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyStruct` is not declared fundamental, therefore this would diff --git a/src/test/compile-fail/coherence_copy_like_err_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_tuple.rs index a70cc92955fb..378a70864f0e 100644 --- a/src/test/compile-fail/coherence_copy_like_err_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_tuple.rs @@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // Tuples are not fundamental, therefore this would require that diff --git a/src/test/compile-fail/specialization/specialization-overlap.rs b/src/test/compile-fail/specialization/specialization-overlap.rs index f57981710010..ff12a82db5b7 100644 --- a/src/test/compile-fail/specialization/specialization-overlap.rs +++ b/src/test/compile-fail/specialization/specialization-overlap.rs @@ -10,19 +10,19 @@ #![feature(specialization)] -trait Foo {} +trait Foo { fn foo() {} } impl Foo for T {} impl Foo for Vec {} //~ ERROR E0119 -trait Bar {} +trait Bar { fn bar() {} } impl Bar for (T, u8) {} impl Bar for (u8, T) {} //~ ERROR E0119 -trait Baz {} +trait Baz { fn baz() {} } impl Baz for u8 {} impl Baz for T {} //~ ERROR E0119 -trait Qux {} +trait Qux { fn qux() {} } impl Qux for T {} impl Qux for T {} //~ ERROR E0119 diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs new file mode 100644 index 000000000000..66c45e671833 --- /dev/null +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -0,0 +1,23 @@ +// 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. + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for T {} + +fn foo(t: T) -> T { + t +} + +fn main() { + assert_eq!(1, foo(1)); + assert_eq!(vec![1], foo(vec![1])); +} From ddcca79d25fffd6604fba593b1ca642a9dfa5727 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 3 Mar 2017 09:09:09 -0500 Subject: [PATCH 504/905] Update with response to feedback --- src/librustc/ty/mod.rs | 2 +- src/test/run-pass/overlap-permitted-for-marker-traits.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9fdabd38d4ab..e9bcb80cff25 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,7 +2227,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::impl_trait_ref::get(self, DUMMY_SP, id) } - /// Returns true if the impl is positive and is for a triat which contains + /// Returns true if the impl is positive and is for a trait which contains /// no items pub fn impl_always_allowed_to_overlap(self, def_id: DefId) -> bool { self.trait_impl_polarity(def_id) == hir::ImplPolarity::Positive diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs index 66c45e671833..b0b1930d274d 100644 --- a/src/test/run-pass/overlap-permitted-for-marker-traits.rs +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -19,5 +19,6 @@ fn foo(t: T) -> T { fn main() { assert_eq!(1, foo(1)); + assert_eq!(2.0, foo(2.0)); assert_eq!(vec![1], foo(vec![1])); } From c81c958e984b92222909e2ba5c74a2260a44bdae Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 17 Mar 2017 12:43:15 -0400 Subject: [PATCH 505/905] Further update with response to feedback --- src/librustc/traits/select.rs | 3 ++- src/librustc/traits/specialize/mod.rs | 5 ----- .../traits/specialize/specialization_graph.rs | 5 ++--- src/librustc/ty/mod.rs | 22 ++++++++++++------- .../auxiliary/trait_impl_conflict.rs | 1 + 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 67d50210ba39..410eb2b84849 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1736,7 +1736,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if other.evaluation == EvaluatedToOk { if let ImplCandidate(victim_def) = victim.candidate { let tcx = self.tcx().global_tcx(); - return traits::specializes(tcx, other_def, victim_def); + return traits::specializes(tcx, other_def, victim_def) || + tcx.impls_are_allowed_to_overlap(other_def, victim_def); } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 6455de48a299..50a4d982832a 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -155,11 +155,6 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return r; } - if tcx.impl_always_allowed_to_overlap(impl1_def_id) - && tcx.impl_always_allowed_to_overlap(impl2_def_id) { - return true; - } - // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. if !tcx.sess.features.borrow().specialization && diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 87abe681d393..6e2c16c82aeb 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -113,9 +113,8 @@ impl<'a, 'gcx, 'tcx> Children { possible_sibling, impl_def_id); if let Some(impl_header) = overlap { - if tcx.impl_always_allowed_to_overlap(impl_def_id) - && tcx.impl_always_allowed_to_overlap(possible_sibling) { - return Ok((true, true)); + if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { + return Ok((false, false)); } let le = specializes(tcx, impl_def_id, possible_sibling); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e9bcb80cff25..2ae77046a90e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,14 +2227,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::impl_trait_ref::get(self, DUMMY_SP, id) } - /// Returns true if the impl is positive and is for a trait which contains - /// no items - pub fn impl_always_allowed_to_overlap(self, def_id: DefId) -> bool { - self.trait_impl_polarity(def_id) == hir::ImplPolarity::Positive - && self.impl_trait_ref(def_id) - .map_or(false, |trait_ref| { - self.associated_item_def_ids(trait_ref.def_id).is_empty() - }) + /// Returns true if the impls are the same polarity and are implementing + /// a trait which contains no items + pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { + let trait1_is_empty = self.impl_trait_ref(def_id1) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }); + let trait2_is_empty = self.impl_trait_ref(def_id2) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }); + self.trait_impl_polarity(def_id1) == self.trait_impl_polarity(def_id2) + && trait1_is_empty + && trait2_is_empty } // Returns `ty::VariantDef` if `def` refers to a struct, diff --git a/src/test/compile-fail/auxiliary/trait_impl_conflict.rs b/src/test/compile-fail/auxiliary/trait_impl_conflict.rs index c3ecbb014dc6..3190ce430ad6 100644 --- a/src/test/compile-fail/auxiliary/trait_impl_conflict.rs +++ b/src/test/compile-fail/auxiliary/trait_impl_conflict.rs @@ -9,6 +9,7 @@ // except according to those terms. pub trait Foo { + fn foo() {} } impl Foo for isize { From adcdd605be9cbdb338d4ecc2410cde87272f2191 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 17 Mar 2017 14:16:29 -0400 Subject: [PATCH 506/905] Put overlapping impls behind feature gate, add tests I've added some explicit tests that negative impls are allowed to overlap, and also to make sure that the feature doesn't interfere with specialization. I've not added an explicit test for positive overlapping with negative, as that's already tested elsewhere. --- src/librustc/ty/mod.rs | 3 +++ src/libsyntax/feature_gate.rs | 3 +++ ...herence-conflicting-negative-trait-impl.rs | 1 + src/test/compile-fail/coherence-impls-send.rs | 1 + ...overlapping-impls-requires-feature-gate.rs | 17 ++++++++++++ ...lap-doesnt-conflict-with-specialization.rs | 27 +++++++++++++++++++ .../overlap-permitted-for-marker-traits.rs | 7 +++++ 7 files changed, 59 insertions(+) create mode 100644 src/test/compile-fail/overlapping-impls-requires-feature-gate.rs create mode 100644 src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2ae77046a90e..3da9383762bc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2230,6 +2230,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { + if !self.sess.features.borrow().overlapping_marker_traits { + return false; + } let trait1_is_empty = self.impl_trait_ref(def_id1) .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8b62416dcbdb..6e455234196d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -349,6 +349,9 @@ declare_features! ( // Allows module-level inline assembly by way of global_asm!() (active, global_asm, "1.18.0", Some(35119)), + + // Allows overlapping impls of marker traits + (active, overlapping_marker_traits, "1.18.0", Some(29864)), ); declare_features! ( diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs index d841e8c41d98..8e9d1eff3458 100644 --- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(optin_builtin_traits)] +#![feature(overlapping_marker_traits)] trait MyTrait {} diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index d0e6bc6a1c69..9caaee41aeb1 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(optin_builtin_traits)] +#![feature(overlapping_marker_traits)] use std::marker::Copy; diff --git a/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs b/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs new file mode 100644 index 000000000000..bf2b06dd8ba0 --- /dev/null +++ b/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs @@ -0,0 +1,17 @@ +// 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. + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for Vec {} +//~^ ERROR E0119 + +fn main() {} diff --git a/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs b/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs new file mode 100644 index 000000000000..ed45d81c0d6a --- /dev/null +++ b/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs @@ -0,0 +1,27 @@ +// 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(overlapping_marker_traits)] +#![feature(specialization)] + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for Vec {} + +fn foo(t: T) -> T { + t +} + +fn main() { + assert_eq!(1, foo(1)); + assert_eq!(2.0, foo(2.0)); + assert_eq!(vec![1], foo(vec![1])); +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs index b0b1930d274d..45085c093fc9 100644 --- a/src/test/run-pass/overlap-permitted-for-marker-traits.rs +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -8,11 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + trait MyMarker {} impl MyMarker for T {} impl MyMarker for T {} +struct MyStruct; +impl !Send for MyStruct {} +impl !Send for MyStruct {} + fn foo(t: T) -> T { t } From 5a9c25b91e3ccefbeb52b1bd0a79ed48d9efae85 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 17 Mar 2017 19:20:18 -0400 Subject: [PATCH 507/905] Name files what tidy wants them to be namd --- ...-feature-gate.rs => feature-gate-overlapping_marker_traits.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/compile-fail/{overlapping-impls-requires-feature-gate.rs => feature-gate-overlapping_marker_traits.rs} (100%) diff --git a/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs similarity index 100% rename from src/test/compile-fail/overlapping-impls-requires-feature-gate.rs rename to src/test/compile-fail/feature-gate-overlapping_marker_traits.rs From 805704c3469853b923c61744eed64a79c7879170 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 30 Mar 2017 08:54:28 -0400 Subject: [PATCH 508/905] update tests slightly --- .../feature-gate-overlapping_marker_traits.rs | 6 ++- src/test/compile-fail/overlap-marker-trait.rs | 41 +++++++++++++++++++ ...overlap-permitted-for-marker-traits-neg.rs | 20 +++++++++ .../overlap-permitted-for-marker-traits.rs | 17 +++++--- 4 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/overlap-marker-trait.rs create mode 100644 src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs diff --git a/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs index bf2b06dd8ba0..d2aa4e59b5ba 100644 --- a/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs +++ b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt::{Debug, Display}; + trait MyMarker {} -impl MyMarker for T {} -impl MyMarker for Vec {} +impl MyMarker for T {} +impl MyMarker for T {} //~^ ERROR E0119 fn main() {} diff --git a/src/test/compile-fail/overlap-marker-trait.rs b/src/test/compile-fail/overlap-marker-trait.rs new file mode 100644 index 000000000000..a649ae25f34e --- /dev/null +++ b/src/test/compile-fail/overlap-marker-trait.rs @@ -0,0 +1,41 @@ +// 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. + +// Test for RFC 1268: we allow overlapping impls of marker traits, +// that is, traits without items. In this case, a type `T` is +// `MyMarker` if it is either `Debug` or `Display`. This test just +// checks that we don't consider **all** types to be `MyMarker`. See +// also the companion test in +// `run-pass/overlap-permitted-for-marker-traits.rs`. + +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + +use std::fmt::{Debug, Display}; + +trait Marker {} + +impl Marker for T {} +impl Marker for T {} + +fn is_marker() { } + +struct NotDebugOrDisplay; + +fn main() { + // Debug && Display: + is_marker::(); + + // Debug && !Display: + is_marker::>(); + + // !Debug && !Display + is_marker::(); //~ ERROR +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs b/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs new file mode 100644 index 000000000000..740d5d22ab50 --- /dev/null +++ b/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs @@ -0,0 +1,20 @@ +// 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(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + +// Overlapping negative impls for `MyStruct` are permitted: +struct MyStruct; +impl !Send for MyStruct {} +impl !Send for MyStruct {} + +fn main() { +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs index 45085c093fc9..11a46299d8c8 100644 --- a/src/test/run-pass/overlap-permitted-for-marker-traits.rs +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -8,24 +8,29 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests for RFC 1268: we allow overlapping impls of marker traits, +// that is, traits without items. In this case, a type `T` is +// `MyMarker` if it is either `Debug` or `Display`. + #![feature(overlapping_marker_traits)] #![feature(optin_builtin_traits)] +use std::fmt::{Debug, Display}; + trait MyMarker {} -impl MyMarker for T {} -impl MyMarker for T {} - -struct MyStruct; -impl !Send for MyStruct {} -impl !Send for MyStruct {} +impl MyMarker for T {} +impl MyMarker for T {} fn foo(t: T) -> T { t } fn main() { + // Debug && Display: assert_eq!(1, foo(1)); assert_eq!(2.0, foo(2.0)); + + // Debug && !Display: assert_eq!(vec![1], foo(vec![1])); } From ae9f571cd11d0b822827547ca6fe192cabb55d0d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 14 Apr 2017 20:38:10 -0400 Subject: [PATCH 509/905] Add Unstable Book entry for 'overlapping-marker-traits'. --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/overlapping-marker-traits.md | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/doc/unstable-book/src/overlapping-marker-traits.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index a5599395f796..a9796fdf01e0 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -136,6 +136,7 @@ - [optin_builtin_traits](optin-builtin-traits.md) - [option_entry](option-entry.md) - [osstring_shrink_to_fit](osstring-shrink-to-fit.md) +- [overlapping_marker_traits](overlapping-marker-traits.md) - [panic_abort](panic-abort.md) - [panic_runtime](panic-runtime.md) - [panic_unwind](panic-unwind.md) diff --git a/src/doc/unstable-book/src/overlapping-marker-traits.md b/src/doc/unstable-book/src/overlapping-marker-traits.md new file mode 100644 index 000000000000..a4920839c6ca --- /dev/null +++ b/src/doc/unstable-book/src/overlapping-marker-traits.md @@ -0,0 +1,7 @@ +# `overlapping_marker_traits` + +The tracking issue for this feature is: [#29864] + +[#29864]: https://github.com/rust-lang/rust/issues/29864 + +------------------------ From 7c8ca80c8120cbc6a1d703f2af2f0397dd86f997 Mon Sep 17 00:00:00 2001 From: king6cong Date: Sat, 15 Apr 2017 11:43:35 +0800 Subject: [PATCH 510/905] code format --- src/libcore/iter/iterator.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 8bf641e37fe4..3ad91ef15ea7 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -2164,16 +2164,16 @@ pub trait Iterator { } } -/// Select an element from an iterator based on the given projection +/// Select an element from an iterator based on the given "projection" /// and "comparison" function. /// /// This is an idiosyncratic helper to try to factor out the /// commonalities of {max,min}{,_by}. In particular, this avoids /// having to implement optimizations several times. #[inline] -fn select_fold1(mut it: I, - mut f_proj: FProj, - mut f_cmp: FCmp) -> Option<(B, I::Item)> +fn select_fold1(mut it: I, + mut f_proj: FProj, + mut f_cmp: FCmp) -> Option<(B, I::Item)> where I: Iterator, FProj: FnMut(&I::Item) -> B, FCmp: FnMut(&B, &I::Item, &B, &I::Item) -> bool @@ -2186,7 +2186,7 @@ fn select_fold1(mut it: I, for x in it { let x_p = f_proj(&x); - if f_cmp(&sel_p, &sel, &x_p, &x) { + if f_cmp(&sel_p, &sel, &x_p, &x) { sel = x; sel_p = x_p; } From 65fafd9414915fe33bc69fb4bfefa8629b5e42ea Mon Sep 17 00:00:00 2001 From: Suchith J N Date: Sat, 15 Apr 2017 10:14:09 +0530 Subject: [PATCH 511/905] [41272] - code for desugaring iflet changed --- src/librustc/hir/lowering.rs | 97 ++++---------------------------- src/test/run-pass/issue-41272.rs | 13 +++++ 2 files changed, 23 insertions(+), 87 deletions(-) create mode 100644 src/test/run-pass/issue-41272.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 30fec50d4eb6..adefd2a8d7ba 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2033,7 +2033,6 @@ impl<'a> LoweringContext<'a> { // // match { // => , - // [_ if => ,] // _ => [ | ()] // } @@ -2047,93 +2046,17 @@ impl<'a> LoweringContext<'a> { arms.push(self.arm(hir_vec![pat], body_expr)); } - // `[_ if => ,]` - // `_ => [ | ()]` + // _ => [|()] { - let mut current: Option<&Expr> = else_opt.as_ref().map(|p| &**p); - let mut else_exprs: Vec> = vec![current]; - - // First, we traverse the AST and recursively collect all - // `else` branches into else_exprs, e.g.: - // - // if let Some(_) = x { - // ... - // } else if ... { // Expr1 - // ... - // } else if ... { // Expr2 - // ... - // } else { // Expr3 - // ... - // } - // - // ... results in else_exprs = [Some(&Expr1), - // Some(&Expr2), - // Some(&Expr3)] - // - // Because there also the case there is no `else`, these - // entries can also be `None`, as in: - // - // if let Some(_) = x { - // ... - // } else if ... { // Expr1 - // ... - // } else if ... { // Expr2 - // ... - // } - // - // ... results in else_exprs = [Some(&Expr1), - // Some(&Expr2), - // None] - // - // The last entry in this list is always translated into - // the final "unguard" wildcard arm of the `match`. In the - // case of a `None`, it becomes `_ => ()`. - loop { - if let Some(e) = current { - // There is an else branch at this level - if let ExprKind::If(_, _, ref else_opt) = e.node { - // The else branch is again an if-expr - current = else_opt.as_ref().map(|p| &**p); - else_exprs.push(current); - } else { - // The last item in the list is not an if-expr, - // stop here - break - } - } else { - // We have no more else branch - break - } - } - - // Now translate the list of nested else-branches into the - // arms of the match statement. - for else_expr in else_exprs { - if let Some(else_expr) = else_expr { - let (guard, body) = if let ExprKind::If(ref cond, - ref then, - _) = else_expr.node { - let then = self.lower_block(then, false); - (Some(cond), - self.expr_block(then, ThinVec::new())) - } else { - (None, - self.lower_expr(else_expr)) - }; - - arms.push(hir::Arm { - attrs: hir_vec![], - pats: hir_vec![self.pat_wild(e.span)], - guard: guard.map(|e| P(self.lower_expr(e))), - body: P(body), - }); - } else { - // There was no else-branch, push a noop - let pat_under = self.pat_wild(e.span); - let unit = self.expr_tuple(e.span, hir_vec![]); - arms.push(self.arm(hir_vec![pat_under], unit)); - } - } + let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); + let wildcard_pattern = self.pat_wild(e.span); + let body = + if let Some(else_expr) = wildcard_arm { + P(self.lower_expr(else_expr)) + } else { + self.expr_tuple(e.span, hir_vec![]) + }; + arms.push(self.arm(hir_vec![wildcard_pattern], body)); } let contains_else_clause = else_opt.is_some(); diff --git a/src/test/run-pass/issue-41272.rs b/src/test/run-pass/issue-41272.rs new file mode 100644 index 000000000000..154aa5b8cbe6 --- /dev/null +++ b/src/test/run-pass/issue-41272.rs @@ -0,0 +1,13 @@ +struct Foo; + +impl Foo { + fn bar(&mut self) -> bool { true } +} + +/* This causes E0301. By fixing issue #41272 this problem should vanish */ +fn iflet_issue(foo: &mut Foo) { + if let Some(_) = Some(true) { + } else if foo.bar() {} +} + +fn main() {} From 4ac11becc2cb716d65cb3ebe5f13d3846ef78b93 Mon Sep 17 00:00:00 2001 From: Suchith J N Date: Sat, 15 Apr 2017 12:17:25 +0530 Subject: [PATCH 512/905] [41272] - Fixed to conform to rust project style --- src/librustc/hir/lowering.rs | 17 ++++++++--------- src/test/run-pass/issue-41272.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index adefd2a8d7ba..994364ba181e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2048,15 +2048,14 @@ impl<'a> LoweringContext<'a> { // _ => [|()] { - let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); - let wildcard_pattern = self.pat_wild(e.span); - let body = - if let Some(else_expr) = wildcard_arm { - P(self.lower_expr(else_expr)) - } else { - self.expr_tuple(e.span, hir_vec![]) - }; - arms.push(self.arm(hir_vec![wildcard_pattern], body)); + let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); + let wildcard_pattern = self.pat_wild(e.span); + let body = if let Some(else_expr) = wildcard_arm { + P(self.lower_expr(else_expr)) + } else { + self.expr_tuple(e.span, hir_vec![]) + }; + arms.push(self.arm(hir_vec![wildcard_pattern], body)); } let contains_else_clause = else_opt.is_some(); diff --git a/src/test/run-pass/issue-41272.rs b/src/test/run-pass/issue-41272.rs index 154aa5b8cbe6..d0834a26ae77 100644 --- a/src/test/run-pass/issue-41272.rs +++ b/src/test/run-pass/issue-41272.rs @@ -1,3 +1,13 @@ +// 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. + struct Foo; impl Foo { From 65b04fa06869cecfbb8d76a8c8a2456aa1f3686e Mon Sep 17 00:00:00 2001 From: Suchith J N Date: Sat, 15 Apr 2017 17:21:53 +0530 Subject: [PATCH 513/905] Fixed aesthetics and test --- src/librustc/hir/lowering.rs | 8 ++++---- src/test/run-pass/issue-41272.rs | 10 ++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 994364ba181e..a6d10c5ab904 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2051,10 +2051,10 @@ impl<'a> LoweringContext<'a> { let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); let wildcard_pattern = self.pat_wild(e.span); let body = if let Some(else_expr) = wildcard_arm { - P(self.lower_expr(else_expr)) - } else { - self.expr_tuple(e.span, hir_vec![]) - }; + P(self.lower_expr(else_expr)) + } else { + self.expr_tuple(e.span, hir_vec![]) + }; arms.push(self.arm(hir_vec![wildcard_pattern], body)); } diff --git a/src/test/run-pass/issue-41272.rs b/src/test/run-pass/issue-41272.rs index d0834a26ae77..d6a0034690af 100644 --- a/src/test/run-pass/issue-41272.rs +++ b/src/test/run-pass/issue-41272.rs @@ -14,10 +14,16 @@ impl Foo { fn bar(&mut self) -> bool { true } } -/* This causes E0301. By fixing issue #41272 this problem should vanish */ -fn iflet_issue(foo: &mut Foo) { +fn error(foo: &mut Foo) { if let Some(_) = Some(true) { } else if foo.bar() {} } +fn ok(foo: &mut Foo) { + if let Some(_) = Some(true) { + } else { + if foo.bar() {} + } +} + fn main() {} From 6fc7d45d64dd9489a94b2acfd4d1044482e95e2d Mon Sep 17 00:00:00 2001 From: Suchith J N Date: Sat, 15 Apr 2017 17:35:30 +0530 Subject: [PATCH 514/905] Fixed aesthetics of if let block --- src/librustc/hir/lowering.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a6d10c5ab904..d65603007533 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2051,10 +2051,10 @@ impl<'a> LoweringContext<'a> { let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); let wildcard_pattern = self.pat_wild(e.span); let body = if let Some(else_expr) = wildcard_arm { - P(self.lower_expr(else_expr)) - } else { - self.expr_tuple(e.span, hir_vec![]) - }; + P(self.lower_expr(else_expr)) + } else { + self.expr_tuple(e.span, hir_vec![]) + }; arms.push(self.arm(hir_vec![wildcard_pattern], body)); } From 5649b3796fa3f8b32116f13e81b44361169ec686 Mon Sep 17 00:00:00 2001 From: Suchith J N Date: Sat, 15 Apr 2017 17:40:54 +0530 Subject: [PATCH 515/905] Aesthetic issue. Corrected indentation --- src/librustc/hir/lowering.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d65603007533..0fd906ae5e4a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2051,9 +2051,9 @@ impl<'a> LoweringContext<'a> { let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); let wildcard_pattern = self.pat_wild(e.span); let body = if let Some(else_expr) = wildcard_arm { - P(self.lower_expr(else_expr)) + P(self.lower_expr(else_expr)) } else { - self.expr_tuple(e.span, hir_vec![]) + self.expr_tuple(e.span, hir_vec![]) }; arms.push(self.arm(hir_vec![wildcard_pattern], body)); } From 2a17b84cbc9cbd36ad79bb1708d1714f1cf3787b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 15:40:38 +0300 Subject: [PATCH 516/905] rustc: provide adt_sized_constraint as an on-demand query. --- src/librustc/ty/mod.rs | 137 +++++++++++++++------------------- src/librustc_driver/driver.rs | 1 + 2 files changed, 61 insertions(+), 77 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3da9383762bc..09eacb40aef7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1695,85 +1695,21 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - self.calculate_sized_constraint_inner(tcx.global_tcx(), &mut Vec::new()) - } - - /// Calculates the Sized-constraint. - /// - /// As the Sized-constraint of enums can be a *set* of types, - /// the Sized-constraint may need to be a set also. Because introducing - /// a new type of IVar is currently a complex affair, the Sized-constraint - /// may be a tuple. - /// - /// In fact, there are only a few options for the constraint: - /// - `bool`, if the type is always Sized - /// - an obviously-unsized type - /// - a type parameter or projection whose Sizedness can't be known - /// - a tuple of type parameters or projections, if there are multiple - /// such. - /// - a TyError, if a type contained itself. The representability - /// check should catch this case. - fn calculate_sized_constraint_inner(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - stack: &mut Vec) - -> Ty<'tcx> - { - if let Some(ty) = tcx.maps.adt_sized_constraint.borrow().get(&self.did) { - return ty; - } - - // Follow the memoization pattern: push the computation of - // DepNode::SizedConstraint as our current task. - let _task = tcx.dep_graph.in_task(DepNode::SizedConstraint(self.did)); - - if stack.contains(&self.did) { - debug!("calculate_sized_constraint: {:?} is recursive", self); - // This should be reported as an error by `check_representable`. - // - // Consider the type as Sized in the meanwhile to avoid - // further errors. - tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err); - return tcx.types.err; - } - - stack.push(self.did); - - let tys : Vec<_> = - self.variants.iter().flat_map(|v| { - v.fields.last() - }).flat_map(|f| { - let ty = tcx.item_type(f.did); - self.sized_constraint_for_ty(tcx, stack, ty) - }).collect(); - - let self_ = stack.pop().unwrap(); - assert_eq!(self_, self.did); - - let ty = match tys.len() { - _ if tys.references_error() => tcx.types.err, - 0 => tcx.types.bool, - 1 => tys[0], - _ => tcx.intern_tup(&tys[..], false) - }; - - let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned(); - match old { - Some(old_ty) => { - debug!("calculate_sized_constraint: {:?} recurred", self); - assert_eq!(old_ty, tcx.types.err); - old_ty - } - None => { - debug!("calculate_sized_constraint: {:?} => {:?}", self, ty); - tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty); - ty + match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) { + Ok(ty) => ty, + Err(_) => { + debug!("adt_sized_constraint: {:?} is recursive", self); + // This should be reported as an error by `check_representable`. + // + // Consider the type as Sized in the meanwhile to avoid + // further errors. + tcx.types.err } } } fn sized_constraint_for_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - stack: &mut Vec, ty: Ty<'tcx>) -> Vec> { let result = match ty.sty { @@ -1791,23 +1727,23 @@ impl<'a, 'gcx, 'tcx> AdtDef { TyTuple(ref tys, _) => { match tys.last() { None => vec![], - Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty) + Some(ty) => self.sized_constraint_for_ty(tcx, ty) } } TyAdt(adt, substs) => { // recursive case let adt_ty = - adt.calculate_sized_constraint_inner(tcx, stack) + adt.sized_constraint(tcx) .subst(tcx, substs); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_ty); if let ty::TyTuple(ref tys, _) = adt_ty.sty { tys.iter().flat_map(|ty| { - self.sized_constraint_for_ty(tcx, stack, ty) + self.sized_constraint_for_ty(tcx, ty) }).collect() } else { - self.sized_constraint_for_ty(tcx, stack, adt_ty) + self.sized_constraint_for_ty(tcx, adt_ty) } } @@ -2703,9 +2639,56 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) panic!("associated item not found for def_id: {:?}", def_id); } +/// Calculates the Sized-constraint. +/// +/// As the Sized-constraint of enums can be a *set* of types, +/// the Sized-constraint may need to be a set also. Because introducing +/// a new type of IVar is currently a complex affair, the Sized-constraint +/// may be a tuple. +/// +/// In fact, there are only a few options for the constraint: +/// - `bool`, if the type is always Sized +/// - an obviously-unsized type +/// - a type parameter or projection whose Sizedness can't be known +/// - a tuple of type parameters or projections, if there are multiple +/// such. +/// - a TyError, if a type contained itself. The representability +/// check should catch this case. +fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Ty<'tcx> { + let def = tcx.lookup_adt_def(def_id); + + let tys: Vec<_> = def.variants.iter().flat_map(|v| { + v.fields.last() + }).flat_map(|f| { + let ty = tcx.item_type(f.did); + def.sized_constraint_for_ty(tcx, ty) + }).collect(); + + let ty = match tys.len() { + _ if tys.references_error() => tcx.types.err, + 0 => tcx.types.bool, + 1 => tys[0], + _ => tcx.intern_tup(&tys[..], false) + }; + + debug!("adt_sized_constraint: {:?} => {:?}", def, ty); + + ty +} + pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { associated_item, + adt_sized_constraint, + ..*providers + }; +} + +pub fn provide_extern(providers: &mut ty::maps::Providers) { + *providers = ty::maps::Providers { + adt_sized_constraint, ..*providers }; } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6b136d0fa0cb..48d9719e76c4 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -898,6 +898,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); + ty::provide_extern(&mut extern_providers); TyCtxt::create_and_enter(sess, local_providers, From f8f5282e5c45db26ae4b4bed11b342dcb399b037 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 15 Apr 2017 07:23:56 -0600 Subject: [PATCH 517/905] Remove MethodMatchResult and MethodMatchedData. These two enums were unused. --- src/librustc/traits/mod.rs | 2 -- src/librustc/traits/select.rs | 29 ----------------------------- 2 files changed, 31 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index ea243d65881e..0ff379b30ffd 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -38,8 +38,6 @@ pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal}; pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; -pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; -pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs}; pub use self::specialize::{SpecializesCache, find_associated_item}; pub use self::util::elaborate_predicates; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 410eb2b84849..70ddcff5181b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -10,8 +10,6 @@ //! See `README.md` for high-level documentation -pub use self::MethodMatchResult::*; -pub use self::MethodMatchedData::*; use self::SelectionCandidate::*; use self::EvaluationResult::*; @@ -110,23 +108,6 @@ pub struct SelectionCache<'tcx> { SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, } -pub enum MethodMatchResult { - MethodMatched(MethodMatchedData), - MethodAmbiguous(/* list of impls that could apply */ Vec), - MethodDidNotMatch, -} - -#[derive(Copy, Clone, Debug)] -pub enum MethodMatchedData { - // In the case of a precise match, we don't really need to store - // how the match was found. So don't. - PreciseMethodMatch, - - // In the case of a coercion, we need to know the precise impl so - // that we can determine the type to which things were coerced. - CoerciveMethodMatch(/* impl we matched */ DefId) -} - /// The selection process begins by considering all impls, where /// clauses, and so forth that might resolve an obligation. Sometimes /// we'll be able to say definitively that (e.g.) an impl does not @@ -2982,13 +2963,3 @@ impl EvaluationResult { } } } - -impl MethodMatchResult { - pub fn may_apply(&self) -> bool { - match *self { - MethodMatched(_) => true, - MethodAmbiguous(_) => true, - MethodDidNotMatch => false, - } - } -} From 675475c4d3e3b1ebff5b761570f4a3f9a0ca23df Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 9 Mar 2017 17:53:01 -0800 Subject: [PATCH 518/905] Specialize Vec::from_elem to use calloc or memset Fixes #38723. --- src/doc/unstable-book/src/allocator.md | 5 +++ src/liballoc/heap.rs | 34 ++++++++++++++++++ src/liballoc/raw_vec.rs | 17 ++++++++- src/liballoc_jemalloc/lib.rs | 21 +++++++++++ src/liballoc_system/lib.rs | 34 ++++++++++++++++-- src/libcollections/vec.rs | 35 +++++++++++++++++-- .../run-pass/auxiliary/allocator-dummy.rs | 5 +++ 7 files changed, 144 insertions(+), 7 deletions(-) diff --git a/src/doc/unstable-book/src/allocator.md b/src/doc/unstable-book/src/allocator.md index 7261641698f4..cfcf8e22d708 100644 --- a/src/doc/unstable-book/src/allocator.md +++ b/src/doc/unstable-book/src/allocator.md @@ -51,6 +51,11 @@ pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 { unsafe { libc::malloc(size as libc::size_t) as *mut u8 } } +#[no_mangle] +pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 { + unsafe { libc::calloc(size as libc::size_t, 1) as *mut u8 } +} + #[no_mangle] pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { unsafe { libc::free(ptr as *mut libc::c_void) } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 51e6f2f8bd7a..08a0b2a6d008 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -23,6 +23,7 @@ use core::intrinsics::{min_align_of_val, size_of_val}; extern "C" { #[allocator] fn __rust_allocate(size: usize, align: usize) -> *mut u8; + fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8; fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize); fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8; fn __rust_reallocate_inplace(ptr: *mut u8, @@ -59,6 +60,20 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { __rust_allocate(size, align) } +/// Return a pointer to `size` bytes of memory aligned to `align` and +/// initialized to zeroes. +/// +/// On failure, return a null pointer. +/// +/// Behavior is undefined if the requested size is 0 or the alignment is not a +/// power of 2. The alignment must be no larger than the largest supported page +/// size on the platform. +#[inline] +pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); + __rust_allocate_zeroed(size, align) +} + /// Resize the allocation referenced by `ptr` to `size` bytes. /// /// On failure, return a null pointer and leave the original allocation intact. @@ -162,6 +177,25 @@ mod tests { use boxed::Box; use heap; + #[test] + fn allocate_zeroed() { + unsafe { + let size = 1024; + let ptr = heap::allocate_zeroed(size, 1); + if ptr.is_null() { + ::oom() + } + + let end = ptr.offset(size as isize); + let mut i = ptr; + while i < end { + assert_eq!(*i, 0); + i = i.offset(1); + } + heap::deallocate(ptr, size, 1); + } + } + #[test] fn basic_reallocate_inplace_noop() { unsafe { diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 357a2724e002..6a53d3a9ca57 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -81,7 +81,18 @@ impl RawVec { /// # Aborts /// /// Aborts on OOM + #[inline] pub fn with_capacity(cap: usize) -> Self { + RawVec::allocate(cap, false) + } + + /// Like `with_capacity` but guarantees the buffer is zeroed. + #[inline] + pub fn with_capacity_zeroed(cap: usize) -> Self { + RawVec::allocate(cap, true) + } + + fn allocate(cap: usize, zeroed: bool) -> Self { unsafe { let elem_size = mem::size_of::(); @@ -93,7 +104,11 @@ impl RawVec { heap::EMPTY as *mut u8 } else { let align = mem::align_of::(); - let ptr = heap::allocate(alloc_size, align); + let ptr = if zeroed { + heap::allocate_zeroed(alloc_size, align) + } else { + heap::allocate(alloc_size, align) + }; if ptr.is_null() { oom() } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 83cc1ef09c29..288531cb5b21 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -38,6 +38,10 @@ mod imp { target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_mallocx")] fn mallocx(size: size_t, flags: c_int) -> *mut c_void; + #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", + target_os = "dragonfly", target_os = "windows", target_env = "musl"), + link_name = "je_calloc")] + fn calloc(size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_rallocx")] @@ -56,6 +60,8 @@ mod imp { fn nallocx(size: size_t, flags: c_int) -> size_t; } + const MALLOCX_ZERO: c_int = 0x40; + // The minimum alignment guaranteed by the architecture. This value is used to // add fast paths for low alignment values. In practice, the alignment is a // constant at the call site and the branch will be optimized out. @@ -91,6 +97,16 @@ mod imp { unsafe { mallocx(size as size_t, flags) as *mut u8 } } + #[no_mangle] + pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + unsafe { calloc(size as size_t, 1) as *mut u8 } + } else { + let flags = align_to_flags(align) | MALLOCX_ZERO; + unsafe { mallocx(size as size_t, flags) as *mut u8 } + } + } + #[no_mangle] pub extern "C" fn __rust_reallocate(ptr: *mut u8, _old_size: usize, @@ -135,6 +151,11 @@ mod imp { bogus() } + #[no_mangle] + pub extern "C" fn __rust_allocate_zeroed(_size: usize, _align: usize) -> *mut u8 { + bogus() + } + #[no_mangle] pub extern "C" fn __rust_reallocate(_ptr: *mut u8, _old_size: usize, diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index de2b75f62b68..6d47c2ff28fb 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -44,6 +44,11 @@ pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { unsafe { imp::allocate(size, align) } } +#[no_mangle] +pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 { + unsafe { imp::allocate_zeroed(size, align) } +} + #[no_mangle] pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { unsafe { imp::deallocate(ptr, old_size, align) } @@ -121,6 +126,18 @@ mod imp { } } + pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + libc::calloc(size as libc::size_t, 1) as *mut u8 + } else { + let ptr = aligned_malloc(size, align); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, size); + } + ptr + } + } + pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { if align <= MIN_ALIGN { libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 @@ -173,6 +190,8 @@ mod imp { #[repr(C)] struct Header(*mut u8); + + const HEAP_ZERO_MEMORY: DWORD = 0x00000008; const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010; unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { @@ -185,11 +204,12 @@ mod imp { aligned } - pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + #[inline] + unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 { if align <= MIN_ALIGN { - HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8 + HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8 } else { - let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8; + let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8; if ptr.is_null() { return ptr; } @@ -197,6 +217,14 @@ mod imp { } } + pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + allocate_with_flags(size, align, 0) + } + + pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + allocate_with_flags(size, align, HEAP_ZERO_MEMORY) + } + pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 { if align <= MIN_ALIGN { HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8 diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 8824185d2809..f488e36c077c 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1370,9 +1370,38 @@ impl Vec { #[doc(hidden)] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_elem(elem: T, n: usize) -> Vec { - let mut v = Vec::with_capacity(n); - v.extend_with_element(n, elem); - v + ::from_elem(elem, n) +} + +// Specialization trait used for Vec::from_elem +trait SpecFromElem: Sized { + fn from_elem(elem: Self, n: usize) -> Vec; +} + +impl SpecFromElem for T { + default fn from_elem(elem: Self, n: usize) -> Vec { + let mut v = Vec::with_capacity(n); + v.extend_with_element(n, elem); + v + } +} + +impl SpecFromElem for u8 { + #[inline] + fn from_elem(elem: u8, n: usize) -> Vec { + if elem == 0 { + return Vec { + buf: RawVec::with_capacity_zeroed(n), + len: n, + } + } + unsafe { + let mut v = Vec::with_capacity(n); + ptr::write_bytes(v.as_mut_ptr(), elem, n); + v.set_len(n); + v + } + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/test/run-pass/auxiliary/allocator-dummy.rs b/src/test/run-pass/auxiliary/allocator-dummy.rs index a1d21db8f4d5..1133ace275b8 100644 --- a/src/test/run-pass/auxiliary/allocator-dummy.rs +++ b/src/test/run-pass/auxiliary/allocator-dummy.rs @@ -27,6 +27,11 @@ pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 { } } +#[no_mangle] +pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 { + unsafe { libc::calloc(size as libc::size_t, 1) as *mut u8 } +} + #[no_mangle] pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { unsafe { From aad2062073f46f28c6d1269463cc6c19df1e0199 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 10 Mar 2017 08:19:42 -0800 Subject: [PATCH 519/905] Specialize Vec::from_elem for other numeric types --- src/libcollections/lib.rs | 2 ++ src/libcollections/vec.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 99afd08e8118..31af6c2f2843 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -35,6 +35,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![cfg_attr(not(test), feature(char_escape_debug))] +#![cfg_attr(not(test), feature(core_float))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] @@ -42,6 +43,7 @@ #![feature(fused)] #![feature(generic_param_attrs)] #![feature(heap_api)] +#![feature(i128_type)] #![feature(inclusive_range)] #![feature(lang_items)] #![feature(manually_drop)] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f488e36c077c..a3c529f35859 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -77,6 +77,8 @@ use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::mem; +#[cfg(not(test))] +use core::num::Float; use core::ops::{InPlace, Index, IndexMut, Place, Placer}; use core::ops; use core::ptr; @@ -1404,6 +1406,41 @@ impl SpecFromElem for u8 { } } +macro_rules! impl_spec_from_elem { + ($t: ty, $is_zero: expr) => { + impl SpecFromElem for $t { + #[inline] + fn from_elem(elem: $t, n: usize) -> Vec<$t> { + if $is_zero(elem) { + return Vec { + buf: RawVec::with_capacity_zeroed(n), + len: n, + } + } + let mut v = Vec::with_capacity(n); + v.extend_with_element(n, elem); + v + } + } + }; +} + +impl_spec_from_elem!(i8, |x| x == 0); +impl_spec_from_elem!(i16, |x| x == 0); +impl_spec_from_elem!(i32, |x| x == 0); +impl_spec_from_elem!(i64, |x| x == 0); +impl_spec_from_elem!(i128, |x| x == 0); +impl_spec_from_elem!(isize, |x| x == 0); + +impl_spec_from_elem!(u16, |x| x == 0); +impl_spec_from_elem!(u32, |x| x == 0); +impl_spec_from_elem!(u64, |x| x == 0); +impl_spec_from_elem!(u128, |x| x == 0); +impl_spec_from_elem!(usize, |x| x == 0); + +impl_spec_from_elem!(f32, |x: f32| x == 0. && x.is_sign_positive()); +impl_spec_from_elem!(f64, |x: f64| x == 0. && x.is_sign_positive()); + //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// From a2489495d909c43cfbefaeb79db6a77b13908257 Mon Sep 17 00:00:00 2001 From: Daniel Keep Date: Mon, 25 Apr 2016 02:04:01 +1000 Subject: [PATCH 520/905] Implementation of the `vis` macro matcher. --- src/libsyntax/ext/tt/macro_parser.rs | 1 + src/libsyntax/ext/tt/macro_rules.rs | 15 +++- src/libsyntax/fold.rs | 1 + src/libsyntax/parse/token.rs | 2 + src/libsyntax/print/pprust.rs | 5 ++ src/test/run-pass/macro-pub-matcher.rs | 119 +++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/macro-pub-matcher.rs diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 6cd1fea2e75e..eb0b7c29f8d9 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -529,6 +529,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { token::NtPath(panictry!(p.parse_path(PathStyle::Type))) }, "meta" => token::NtMeta(panictry!(p.parse_meta_item())), + "vis" => token::NtVis(panictry!(p.parse_visibility(true))), // this is not supposed to happen, since it has been checked // when compiling the macro. _ => p.span_bug(sp, "invalid fragment specifier") diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 93348c8f0837..4e197a85ebd9 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -790,6 +790,19 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result { + // Explicitly disallow `priv`, on the off chance it comes back. + match *tok { + Comma => Ok(true), + ModSep => Ok(true), + MatchNt(_, ref frag, _, _) => { + let name = frag.name.as_str(); + Ok(name == "ident" || name == "ty") + }, + Ident(i, _) if i.name.as_str() != "priv" => Ok(true), + _ => Ok(false) + } + }, "" => Ok(true), // keywords::Invalid _ => Err((format!("invalid fragment specifier `{}`", frag), "valid fragment specifiers are `ident`, `block`, \ @@ -813,7 +826,7 @@ fn has_legal_fragment_specifier(tok: "ed::TokenTree) -> Result<(), String> { fn is_legal_fragment_specifier(frag: &str) -> bool { match frag { "item" | "block" | "stmt" | "expr" | "pat" | - "path" | "ty" | "ident" | "meta" | "tt" | "" => true, + "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "" => true, _ => false, } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index a6ab8e10d9f9..f39399a62e85 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -636,6 +636,7 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtWhereClause(where_clause) => token::NtWhereClause(fld.fold_where_clause(where_clause)), token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)), + token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)), } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 74aa3984a9a4..513aa866043a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -371,6 +371,7 @@ pub enum Nonterminal { NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), NtArg(ast::Arg), + NtVis(ast::Visibility), } impl fmt::Debug for Nonterminal { @@ -392,6 +393,7 @@ impl fmt::Debug for Nonterminal { NtGenerics(..) => f.pad("NtGenerics(..)"), NtWhereClause(..) => f.pad("NtWhereClause(..)"), NtArg(..) => f.pad("NtArg(..)"), + NtVis(..) => f.pad("NtVis(..)"), } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 433ba3d3693f..2494af2c1618 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -293,6 +293,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtGenerics(ref e) => generics_to_string(&e), token::NtWhereClause(ref e) => where_clause_to_string(&e), token::NtArg(ref e) => arg_to_string(&e), + token::NtVis(ref e) => vis_to_string(&e), } } } @@ -373,6 +374,10 @@ pub fn ident_to_string(id: ast::Ident) -> String { to_string(|s| s.print_ident(id)) } +pub fn vis_to_string(v: &ast::Visibility) -> String { + to_string(|s| s.print_visibility(v)) +} + pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, constness: ast::Constness, diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs new file mode 100644 index 000000000000..64fa0bef464c --- /dev/null +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -0,0 +1,119 @@ +#![allow(dead_code, unused_imports)] +#![feature(pub_restricted)] + +/** +Ensure that `:vis` matches can be captured in existing positions, and passed +through without the need for reparse tricks. +*/ +macro_rules! vis_passthru { + ($vis:vis const $name:ident: $ty:ty = $e:expr;) => { $vis const $name: $ty = $e; }; + ($vis:vis enum $name:ident {}) => { $vis struct $name {} }; + ($vis:vis extern "C" fn $name:ident() {}) => { $vis extern "C" fn $name() {} }; + ($vis:vis fn $name:ident() {}) => { $vis fn $name() {} }; + ($vis:vis mod $name:ident {}) => { $vis mod $name {} }; + ($vis:vis static $name:ident: $ty:ty = $e:expr;) => { $vis static $name: $ty = $e; }; + ($vis:vis struct $name:ident;) => { $vis struct $name; }; + ($vis:vis trait $name:ident {}) => { $vis trait $name {} }; + ($vis:vis type $name:ident = $ty:ty;) => { $vis type $name = $ty; }; + ($vis:vis use $path:ident as $name:ident;) => { $vis use self::$path as $name; }; +} + +mod with_pub { + vis_passthru! { pub const A: i32 = 0; } + vis_passthru! { pub enum B {} } + vis_passthru! { pub extern "C" fn c() {} } + vis_passthru! { pub mod d {} } + vis_passthru! { pub static E: i32 = 0; } + vis_passthru! { pub struct F; } + vis_passthru! { pub trait G {} } + vis_passthru! { pub type H = i32; } + vis_passthru! { pub use A as I; } +} + +mod without_pub { + vis_passthru! { const A: i32 = 0; } + vis_passthru! { enum B {} } + vis_passthru! { extern "C" fn c() {} } + vis_passthru! { mod d {} } + vis_passthru! { static E: i32 = 0; } + vis_passthru! { struct F; } + vis_passthru! { trait G {} } + vis_passthru! { type H = i32; } + vis_passthru! { use A as I; } +} + +mod with_pub_restricted { + vis_passthru! { pub(crate) const A: i32 = 0; } + vis_passthru! { pub(crate) enum B {} } + vis_passthru! { pub(crate) extern "C" fn c() {} } + vis_passthru! { pub(crate) mod d {} } + vis_passthru! { pub(crate) static E: i32 = 0; } + vis_passthru! { pub(crate) struct F; } + vis_passthru! { pub(crate) trait G {} } + vis_passthru! { pub(crate) type H = i32; } + vis_passthru! { pub(crate) use A as I; } +} + +mod garden { + mod with_pub_restricted_path { + vis_passthru! { pub(::garden) const A: i32 = 0; } + vis_passthru! { pub(::garden) enum B {} } + vis_passthru! { pub(::garden) extern "C" fn c() {} } + vis_passthru! { pub(::garden) mod d {} } + vis_passthru! { pub(::garden) static E: i32 = 0; } + vis_passthru! { pub(::garden) struct F; } + vis_passthru! { pub(::garden) trait G {} } + vis_passthru! { pub(::garden) type H = i32; } + vis_passthru! { pub(::garden) use A as I; } + } +} + +/* +Ensure that the `:vis` matcher works in a more complex situation: parsing a +struct definition. +*/ +macro_rules! vis_parse_struct { + /* + The rule duplication is currently unavoidable due to the leading attribute + matching. + */ + ($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* pub struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub, $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, , $name, $($body)* } + }; + + ($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* pub struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub, $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, , $name, $($body)* } + }; + + (@parse_fields $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => { + $(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* } + }; + + (@parse_tuple $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => { + $(#[$attrs])* $vis struct $name ( $($fvis $fty,)* ); + }; +} + +mod test_struct { + vis_parse_struct! { pub(crate) struct A { pub a: i32, b: i32, pub(crate) c: i32 } } + vis_parse_struct! { pub struct B { a: i32, pub(crate) b: i32, pub c: i32 } } + vis_parse_struct! { struct C { pub(crate) a: i32, pub b: i32, c: i32 } } + + vis_parse_struct! { pub(crate) struct D (pub i32, i32, pub(crate) i32); } + vis_parse_struct! { pub struct E (i32, pub(crate) i32, pub i32); } + vis_parse_struct! { struct F (pub(crate) i32, pub i32, i32); } +} + +fn main() {} From d53e413e04e438fd0dc1a8b1a8dcb07a0774092a Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 04:21:12 +0000 Subject: [PATCH 521/905] update :vis implementation to current rust --- src/libsyntax/ext/tt/macro_rules.rs | 12 ++++++------ src/libsyntax/parse/parser.rs | 2 +- src/test/run-pass/macro-pub-matcher.rs | 19 +++++++++---------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 4e197a85ebd9..f888e29bdabb 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -793,13 +793,13 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result { // Explicitly disallow `priv`, on the off chance it comes back. match *tok { - Comma => Ok(true), - ModSep => Ok(true), - MatchNt(_, ref frag, _, _) => { - let name = frag.name.as_str(); - Ok(name == "ident" || name == "ty") + TokenTree::Token(_, ref tok) => match *tok { + Comma => Ok(true), + ModSep => Ok(true), + Ident(i) if i.name != "priv" => Ok(true), + _ => Ok(false) }, - Ident(i, _) if i.name.as_str() != "priv" => Ok(true), + TokenTree::MetaVarDecl(_, _, frag) if frag.name =="ident" || frag.name == "ty" => Ok(true), _ => Ok(false) } }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3b928ea93c78..11becd58293b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5056,7 +5056,7 @@ impl<'a> Parser<'a> { /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's /// a function definition, it's not a tuple struct field) and the contents within the parens /// isn't valid, emit a proper diagnostic. - fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { + pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs index 64fa0bef464c..7de9cc6bf21d 100644 --- a/src/test/run-pass/macro-pub-matcher.rs +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -1,5 +1,4 @@ #![allow(dead_code, unused_imports)] -#![feature(pub_restricted)] /** Ensure that `:vis` matches can be captured in existing positions, and passed @@ -56,15 +55,15 @@ mod with_pub_restricted { mod garden { mod with_pub_restricted_path { - vis_passthru! { pub(::garden) const A: i32 = 0; } - vis_passthru! { pub(::garden) enum B {} } - vis_passthru! { pub(::garden) extern "C" fn c() {} } - vis_passthru! { pub(::garden) mod d {} } - vis_passthru! { pub(::garden) static E: i32 = 0; } - vis_passthru! { pub(::garden) struct F; } - vis_passthru! { pub(::garden) trait G {} } - vis_passthru! { pub(::garden) type H = i32; } - vis_passthru! { pub(::garden) use A as I; } + vis_passthru! { pub(in garden) const A: i32 = 0; } + vis_passthru! { pub(in garden) enum B {} } + vis_passthru! { pub(in garden) extern "C" fn c() {} } + vis_passthru! { pub(in garden) mod d {} } + vis_passthru! { pub(in garden) static E: i32 = 0; } + vis_passthru! { pub(in garden) struct F; } + vis_passthru! { pub(in garden) trait G {} } + vis_passthru! { pub(in garden) type H = i32; } + vis_passthru! { pub(in garden) use A as I; } } } From 06411c47694916aaf22ef30b6b8877d7659b2002 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 04:46:33 +0000 Subject: [PATCH 522/905] update print_visibility for new pub(restricted) syntax --- src/libsyntax/print/pprust.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2494af2c1618..be1d26f8fe48 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -432,13 +432,7 @@ pub fn mac_to_string(arg: &ast::Mac) -> String { } pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { - match *vis { - ast::Visibility::Public => format!("pub {}", s), - ast::Visibility::Crate(_) => format!("pub(crate) {}", s), - ast::Visibility::Restricted { ref path, .. } => - format!("pub({}) {}", to_string(|s| s.print_path(path, false, 0, true)), s), - ast::Visibility::Inherited => s.to_string() - } + format!("{}{}", to_string(|s| s.print_visibility(vis)), s) } fn needs_parentheses(expr: &ast::Expr) -> bool { @@ -1473,7 +1467,11 @@ impl<'a> State<'a> { ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"), ast::Visibility::Restricted { ref path, .. } => { let path = to_string(|s| s.print_path(path, false, 0, true)); - self.word_nbsp(&format!("pub({})", path)) + if path == "self" || path == "super" { + self.word_nbsp(&format!("pub({})", path)) + } else { + self.word_nbsp(&format!("pub(in {})", path)) + } } ast::Visibility::Inherited => Ok(()) } From 16010c2f50dd92cc57ccced270a9fb727d6d4883 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 04:46:51 +0000 Subject: [PATCH 523/905] parse interpolated visibility tokens --- src/libsyntax/ext/tt/macro_rules.rs | 3 ++- src/libsyntax/parse/parser.rs | 2 ++ src/test/run-pass/macro-pub-matcher.rs | 16 ++++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index f888e29bdabb..84c909284a8f 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -799,7 +799,8 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result Ok(true), _ => Ok(false) }, - TokenTree::MetaVarDecl(_, _, frag) if frag.name =="ident" || frag.name == "ty" => Ok(true), + TokenTree::MetaVarDecl(_, _, frag) + if frag.name =="ident" || frag.name == "ty" => Ok(true), _ => Ok(false) } }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 11becd58293b..31669e1bbe3a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5057,6 +5057,8 @@ impl<'a> Parser<'a> { /// a function definition, it's not a tuple struct field) and the contents within the parens /// isn't valid, emit a proper diagnostic. pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { + maybe_whole!(self, NtVis, |x| x); + if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs index 7de9cc6bf21d..d5b25e6cdf2d 100644 --- a/src/test/run-pass/macro-pub-matcher.rs +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -1,3 +1,13 @@ +// 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. + #![allow(dead_code, unused_imports)] /** @@ -96,11 +106,13 @@ macro_rules! vis_parse_struct { vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, , $name, $($body)* } }; - (@parse_fields $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => { + (@parse_fields + $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => { $(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* } }; - (@parse_tuple $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => { + (@parse_tuple + $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => { $(#[$attrs])* $vis struct $name ( $($fvis $fty,)* ); }; } From 06d32335e893a1b5af5dd3f6a8a53dcae266a016 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 18:34:38 +0000 Subject: [PATCH 524/905] move NtVis enum variant to stave off comment rot --- src/libsyntax/parse/token.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 513aa866043a..25cabef70c15 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -363,6 +363,7 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(ast::MetaItem), NtPath(ast::Path), + NtVis(ast::Visibility), NtTT(TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), @@ -371,7 +372,6 @@ pub enum Nonterminal { NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), NtArg(ast::Arg), - NtVis(ast::Visibility), } impl fmt::Debug for Nonterminal { From 37459e13fc6118eaf0a01a6dae96908414f02a23 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 19:06:40 +0000 Subject: [PATCH 525/905] widen :vis follow set --- src/libsyntax/ext/tt/macro_rules.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 84c909284a8f..00623dabec47 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -795,12 +795,12 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result match *tok { Comma => Ok(true), - ModSep => Ok(true), Ident(i) if i.name != "priv" => Ok(true), - _ => Ok(false) + ref tok => Ok(tok.can_begin_type()) }, - TokenTree::MetaVarDecl(_, _, frag) - if frag.name =="ident" || frag.name == "ty" => Ok(true), + TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident" + || frag.name == "ty" + || frag.name == "path" => Ok(true), _ => Ok(false) } }, From 1d468050574cc28a06ef684727e1106fa660a20c Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 20:04:27 +0000 Subject: [PATCH 526/905] document :vis in unstable book --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/macro-vis-matcher.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/doc/unstable-book/src/macro-vis-matcher.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index a9796fdf01e0..42af79b8bb07 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -114,6 +114,7 @@ - [lookup_host](lookup-host.md) - [loop_break_value](loop-break-value.md) - [macro_reexport](macro-reexport.md) +- [macro_vis_matcher](macro-vis-matcher.md) - [main](main.md) - [manually_drop](manually-drop.md) - [map_entry_recover_keys](map-entry-recover-keys.md) diff --git a/src/doc/unstable-book/src/macro-vis-matcher.md b/src/doc/unstable-book/src/macro-vis-matcher.md new file mode 100644 index 000000000000..7918a3568432 --- /dev/null +++ b/src/doc/unstable-book/src/macro-vis-matcher.md @@ -0,0 +1,14 @@ +# `macro_vis_matcher` + +The tracking issue for this feature is: [#41022] + +With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry: + +* `vis`: a visibility qualifier. Examples: nothing (default visibility); `pub`; `pub(crate)`. + +A `vis` variable may be followed by a comma, ident, type, or path. + +[#41022]: https://github.com/rust-lang/rust/issues/41022 +[frags]: ../book/first-edition/macros.html#syntactic-requirements + +------------------------ From e0cd76674d3f5cf68d83789bad27dec9dcf53501 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 3 Apr 2017 00:09:07 +0000 Subject: [PATCH 527/905] feature gate :vis matcher --- src/librustc_resolve/build_reduced_graph.rs | 4 +- src/librustc_resolve/macros.rs | 4 +- src/libsyntax/ext/tt/macro_rules.rs | 67 +++++++++++++------ src/libsyntax/feature_gate.rs | 6 ++ .../feature-gate-macro-vis-matcher.rs | 19 ++++++ src/test/run-pass/macro-pub-matcher.rs | 1 + 6 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-macro-vis-matcher.rs diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 80f853778c74..c797c151de67 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -521,7 +521,9 @@ impl<'a> Resolver<'a> { LoadedMacro::ProcMacro(ext) => return ext, }; - let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def)); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, + &self.session.features, + ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 966cb7ee8d8d..030e3936de99 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -671,7 +671,9 @@ impl<'a> Resolver<'a> { } let def_id = self.definitions.local_def_id(item.id); - let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, item)); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, + &self.session.features, + item)); self.macro_map.insert(def_id, ext); *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span, diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 00623dabec47..be979960725a 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -18,6 +18,7 @@ use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; use ext::tt::quoted; use ext::tt::transcribe::transcribe; +use feature_gate::{self, emit_feature_err, Features, GateIssue}; use parse::{Directory, ParseSess}; use parse::parser::Parser; use parse::token::{self, NtTT}; @@ -25,6 +26,7 @@ use parse::token::Token::*; use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; +use std::cell::RefCell; use std::collections::{HashMap}; use std::collections::hash_map::{Entry}; use std::rc::Rc; @@ -154,7 +156,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -208,7 +210,7 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { if let MatchedNonterminal(ref nt) = **m { if let NtTT(ref tt) = **nt { let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap(); - valid &= check_lhs_nt_follows(sess, &tt); + valid &= check_lhs_nt_follows(sess, features, &tt); return tt; } } @@ -251,11 +253,13 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable")) } -fn check_lhs_nt_follows(sess: &ParseSess, lhs: "ed::TokenTree) -> bool { +fn check_lhs_nt_follows(sess: &ParseSess, + features: &RefCell, + lhs: "ed::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. match lhs { - "ed::TokenTree::Delimited(_, ref tts) => check_matcher(sess, &tts.tts), + "ed::TokenTree::Delimited(_, ref tts) => check_matcher(sess, features, &tts.tts), _ => { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; sess.span_diagnostic.span_err(lhs.span(), msg); @@ -307,11 +311,13 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { false } -fn check_matcher(sess: &ParseSess, matcher: &[quoted::TokenTree]) -> bool { +fn check_matcher(sess: &ParseSess, + features: &RefCell, + matcher: &[quoted::TokenTree]) -> bool { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); let err = sess.span_diagnostic.err_count(); - check_matcher_core(sess, &first_sets, matcher, &empty_suffix); + check_matcher_core(sess, features, &first_sets, matcher, &empty_suffix); err == sess.span_diagnostic.err_count() } @@ -553,6 +559,7 @@ impl TokenSet { // Requires that `first_sets` is pre-computed for `matcher`; // see `FirstSets::new`. fn check_matcher_core(sess: &ParseSess, + features: &RefCell, first_sets: &FirstSets, matcher: &[quoted::TokenTree], follow: &TokenSet) -> TokenSet { @@ -583,12 +590,11 @@ fn check_matcher_core(sess: &ParseSess, match *token { TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => { let can_be_followed_by_any; - if let Err(bad_frag) = has_legal_fragment_specifier(token) { + if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, token) { let msg = format!("invalid fragment specifier `{}`", bad_frag); sess.span_diagnostic.struct_span_err(token.span(), &msg) - .help("valid fragment specifiers are `ident`, `block`, \ - `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ - and `item`") + .help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \ + `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`") .emit(); // (This eliminates false positives and duplicates // from error messages.) @@ -610,7 +616,7 @@ fn check_matcher_core(sess: &ParseSess, } TokenTree::Delimited(span, ref d) => { let my_suffix = TokenSet::singleton(d.close_tt(span)); - check_matcher_core(sess, first_sets, &d.tts, &my_suffix); + check_matcher_core(sess, features, first_sets, &d.tts, &my_suffix); // don't track non NT tokens last.replace_with_irrelevant(); @@ -642,7 +648,7 @@ fn check_matcher_core(sess: &ParseSess, // At this point, `suffix_first` is built, and // `my_suffix` is some TokenSet that we can use // for checking the interior of `seq_rep`. - let next = check_matcher_core(sess, first_sets, &seq_rep.tts, my_suffix); + let next = check_matcher_core(sess, features, first_sets, &seq_rep.tts, my_suffix); if next.maybe_empty { last.add_all(&next); } else { @@ -807,27 +813,44 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result Ok(true), // keywords::Invalid _ => Err((format!("invalid fragment specifier `{}`", frag), "valid fragment specifiers are `ident`, `block`, \ - `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ - and `item`")) + `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \ + `item` and `vis`")) } } } -fn has_legal_fragment_specifier(tok: "ed::TokenTree) -> Result<(), String> { +fn has_legal_fragment_specifier(sess: &ParseSess, + features: &RefCell, + tok: "ed::TokenTree) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); - if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok { - let s = &frag_spec.name.as_str(); - if !is_legal_fragment_specifier(s) { - return Err(s.to_string()); + if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok { + let frag_name = frag_spec.name.as_str(); + let frag_span = tok.span(); + if !is_legal_fragment_specifier(sess, features, &frag_name, frag_span) { + return Err(frag_name.to_string()); } } Ok(()) } -fn is_legal_fragment_specifier(frag: &str) -> bool { - match frag { +fn is_legal_fragment_specifier(sess: &ParseSess, + features: &RefCell, + frag_name: &str, + frag_span: Span) -> bool { + match frag_name { "item" | "block" | "stmt" | "expr" | "pat" | - "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "" => true, + "path" | "ty" | "ident" | "meta" | "tt" | "" => true, + "vis" => { + if !features.borrow().macro_vis_matcher { + let explain = feature_gate::EXPLAIN_VIS_MATCHER; + emit_feature_err(sess, + "macro_vis_matcher", + frag_span, + GateIssue::Language, + explain); + } + true + }, _ => false, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6e455234196d..aee6da93e506 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -352,6 +352,9 @@ declare_features! ( // Allows overlapping impls of marker traits (active, overlapping_marker_traits, "1.18.0", Some(29864)), + + // Allows use of the :vis macro fragment specifier + (active, macro_vis_matcher, "1.18.0", Some(41022)), ); declare_features! ( @@ -1012,6 +1015,9 @@ pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str = pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = "attributes of the form `#[derive_*]` are reserved for the compiler"; +pub const EXPLAIN_VIS_MATCHER: &'static str = + ":vis 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."; diff --git a/src/test/compile-fail/feature-gate-macro-vis-matcher.rs b/src/test/compile-fail/feature-gate-macro-vis-matcher.rs new file mode 100644 index 000000000000..5d6f2acea83c --- /dev/null +++ b/src/test/compile-fail/feature-gate-macro-vis-matcher.rs @@ -0,0 +1,19 @@ +// 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. + +// Test that the MSP430 interrupt ABI cannot be used when msp430_interrupt +// feature gate is not used. + +macro_rules! m { ($v:vis) => {} } +//~^ ERROR :vis fragment specifier is experimental and subject to change + +fn main() { + m!(pub); +} diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs index d5b25e6cdf2d..1a7529fe2b41 100644 --- a/src/test/run-pass/macro-pub-matcher.rs +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code, unused_imports)] +#![feature(macro_vis_matcher)] /** Ensure that `:vis` matches can be captured in existing positions, and passed From 51c8af5093c5ffedd248873e5d5c92de98d00021 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 3 Apr 2017 00:26:14 +0000 Subject: [PATCH 528/905] reduce macro rule duplication in test --- src/test/run-pass/macro-pub-matcher.rs | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs index 1a7529fe2b41..d79f4b65b69e 100644 --- a/src/test/run-pass/macro-pub-matcher.rs +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -83,28 +83,12 @@ Ensure that the `:vis` matcher works in a more complex situation: parsing a struct definition. */ macro_rules! vis_parse_struct { - /* - The rule duplication is currently unavoidable due to the leading attribute - matching. - */ - ($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident {$($body:tt)*}) => { - vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* } - }; - ($(#[$($attrs:tt)*])* pub struct $name:ident {$($body:tt)*}) => { - vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub, $name, $($body)* } - }; - ($(#[$($attrs:tt)*])* struct $name:ident {$($body:tt)*}) => { - vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, , $name, $($body)* } + ($(#[$($attrs:tt)*])* $vis:vis struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, $vis, $name, $($body)* } }; - ($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident ($($body:tt)*);) => { - vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* } - }; - ($(#[$($attrs:tt)*])* pub struct $name:ident ($($body:tt)*);) => { - vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub, $name, $($body)* } - }; - ($(#[$($attrs:tt)*])* struct $name:ident ($($body:tt)*);) => { - vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, , $name, $($body)* } + ($(#[$($attrs:tt)*])* $vis:vis struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, $vis, $name, $($body)* } }; (@parse_fields From 99f5c8593b1778947830d1da580c55b70680b919 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 23:51:58 +0300 Subject: [PATCH 529/905] rustc: ban registering obligations during InferCtxt snapshots. --- src/librustc/infer/mod.rs | 56 +++++++++++++-------------- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/specialize/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e98792b120de..a1bafe113e41 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -199,10 +199,8 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // `tained_by_errors`) to avoid reporting certain kinds of errors. err_count_on_creation: usize, - // This flag is used for debugging, and is set to true if there are - // any obligations set during the current snapshot. In that case, the - // snapshot can't be rolled back. - pub obligations_in_snapshot: Cell, + // This flag is true while there is an active snapshot. + in_snapshot: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -507,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { projection_mode: Reveal::UserFacing, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), } } } @@ -545,7 +543,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), })) } } @@ -573,7 +571,7 @@ pub struct CombinedSnapshot { int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_vars_snapshot: RegionSnapshot, - obligations_in_snapshot: bool, + was_in_snapshot: bool, } /// Helper trait for shortening the lifetimes inside a @@ -734,6 +732,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.projection_mode } + pub fn is_in_snapshot(&self) -> bool { + self.in_snapshot.get() + } + pub fn freshen>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -861,38 +863,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } - // Clear the "obligations in snapshot" flag, invoke the closure, + // Clear the "currently in a snapshot" flag, invoke the closure, // then restore the flag to its original value. This flag is a // debugging measure designed to detect cases where we start a - // snapshot, create type variables, register obligations involving - // those type variables in the fulfillment cx, and then have to - // unroll the snapshot, leaving "dangling type variables" behind. - // In such cases, the flag will be set by the fulfillment cx, and - // an assertion will fail when rolling the snapshot back. Very - // useful, much better than grovelling through megabytes of - // RUST_LOG output. + // snapshot, create type variables, and register obligations + // which may involve those type variables in the fulfillment cx, + // potentially leaving "dangling type variables" behind. + // In such cases, an assertion will fail when attempting to + // register obligations, within a snapshot. Very useful, much + // better than grovelling through megabytes of RUST_LOG output. // - // HOWEVER, in some cases the flag is wrong. In particular, we + // HOWEVER, in some cases the flag is unhelpful. In particular, we // sometimes create a "mini-fulfilment-cx" in which we enroll // obligations. As long as this fulfillment cx is fully drained // before we return, this is not a problem, as there won't be any // escaping obligations in the main cx. In those cases, you can // use this function. - pub fn save_and_restore_obligations_in_snapshot_flag(&self, func: F) -> R + pub fn save_and_restore_in_snapshot_flag(&self, func: F) -> R where F: FnOnce(&Self) -> R { - let flag = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let flag = self.in_snapshot.get(); + self.in_snapshot.set(false); let result = func(self); - self.obligations_in_snapshot.set(flag); + self.in_snapshot.set(flag); result } fn start_snapshot(&self) -> CombinedSnapshot { debug!("start_snapshot()"); - let obligations_in_snapshot = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let in_snapshot = self.in_snapshot.get(); + self.in_snapshot.set(true); CombinedSnapshot { projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(), @@ -900,7 +901,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot: self.int_unification_table.borrow_mut().snapshot(), float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_vars_snapshot: self.region_vars.start_snapshot(), - obligations_in_snapshot: obligations_in_snapshot, + was_in_snapshot: in_snapshot, } } @@ -911,10 +912,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - assert!(!self.obligations_in_snapshot.get()); - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() @@ -939,9 +939,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 64453f2983b9..d771be077ae3 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { debug!("register_predicate_obligation(obligation={:?})", obligation); - infcx.obligations_in_snapshot.set(true); + assert!(!infcx.is_in_snapshot()); if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { debug!("register_predicate_obligation: duplicate"); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 50a4d982832a..92b7c736d42f 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -242,7 +242,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) - infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| { + infcx.save_and_restore_in_snapshot_flag(|infcx| { let mut fulfill_cx = FulfillmentContext::new(); for oblig in obligations.into_iter() { fulfill_cx.register_predicate_obligation(&infcx, oblig); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e7325275b81..61e4b74ae8d5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2588,7 +2588,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // we can. We don't care if some things turn // out unconstrained or ambiguous, as we're // just trying to get hints here. - let result = self.save_and_restore_obligations_in_snapshot_flag(|_| { + let result = self.save_and_restore_in_snapshot_flag(|_| { let mut fulfill = FulfillmentContext::new(); let ok = ok; // FIXME(#30046) for obligation in ok.obligations { From e56b119bac1ded9396e97f8326f6b0567935ca31 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 23:55:10 +0300 Subject: [PATCH 530/905] rustc_typeck: keep register_infer_ok_obligations calls out of snapshots. --- src/librustc_typeck/check/coercion.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 2e9057800a54..c6a1f6cfc0d7 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -711,16 +711,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - self.commit_if_ok(|_| { - let ok = coerce.coerce(&[expr], source, target)?; - let adjustment = self.register_infer_ok_obligations(ok); - self.apply_adjustment(expr.id, adjustment); + let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?; - // We should now have added sufficient adjustments etc to - // ensure that the type of expression, post-adjustment, is - // a subtype of target. - Ok(target) - }) + let adjustment = self.register_infer_ok_obligations(ok); + self.apply_adjustment(expr.id, adjustment); + + // We should now have added sufficient adjustments etc to + // ensure that the type of expression, post-adjustment, is + // a subtype of target. + Ok(target) } /// Given some expressions, their known unified type and another expression, From 2ad196444b41830b59a724d644052e692ebcad47 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 23:56:40 +0300 Subject: [PATCH 531/905] rustc_typeck: Autoderef::finalize is always called with one &hir::Expr. --- src/librustc_typeck/check/autoderef.rs | 6 ++---- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 8 ++++---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 647adbbb82f2..bfb69d620ace 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -149,11 +149,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.fcx.resolve_type_vars_if_possible(&self.cur_ty) } - pub fn finalize(self, pref: LvaluePreference, exprs: &[E]) - where E: AsCoercionSite - { + pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) { let fcx = self.fcx; - fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); + fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr])); } pub fn finalize_as_infer_ok(self, pref: LvaluePreference, exprs: &[E]) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 9c5870c12aad..70e585bd14f3 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) .next(); let callee_ty = autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, &[callee_expr]); + autoderef.finalize(LvaluePreference::NoPreference, callee_expr); let output = match result { None => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 28ac335cf195..e64ad775d521 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { assert_eq!(n, pick.autoderefs); autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, &[self.self_expr]); + autoderef.finalize(LvaluePreference::NoPreference, self.self_expr); let target = pick.unsize.unwrap_or(autoderefd_ty); let target = target.adjust_for_autoref(self.tcx, autoref); @@ -445,7 +445,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { "expr was deref-able {} times but now isn't?", autoderefs); }); - autoderef.finalize(PreferMutLvalue, &[expr]); + autoderef.finalize(PreferMutLvalue, expr); } } Some(_) | None => {} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 61e4b74ae8d5..7f887870afd9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2074,12 +2074,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, base_expr, adj_ty, autoderefs, false, lvalue_pref, idx_ty) { - autoderef.finalize(lvalue_pref, &[base_expr]); + autoderef.finalize(lvalue_pref, base_expr); return Some(final_mt); } if let ty::TyArray(element_ty, _) = adj_ty.sty { - autoderef.finalize(lvalue_pref, &[base_expr]); + autoderef.finalize(lvalue_pref, base_expr); let adjusted_ty = self.tcx.mk_slice(element_ty); return self.try_index_step( MethodCall::expr(expr.id), expr, base_expr, @@ -2757,7 +2757,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); if self.tcx.vis_is_accessible_from(field.vis, self.body_id) { - autoderef.finalize(lvalue_pref, &[base]); + autoderef.finalize(lvalue_pref, base); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -2881,7 +2881,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, &[base]); + autoderef.finalize(lvalue_pref, base); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } From 516570f2d6b2246cf2ae0269a201bd6a62c91881 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 23:58:50 +0300 Subject: [PATCH 532/905] rustc_typeck: move some obligation methods to Inherited. --- src/librustc_typeck/check/assoc.rs | 39 ----------- src/librustc_typeck/check/compare_method.rs | 64 +++++++---------- src/librustc_typeck/check/mod.rs | 78 ++++++++++++--------- 3 files changed, 68 insertions(+), 113 deletions(-) delete mode 100644 src/librustc_typeck/check/assoc.rs diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs deleted file mode 100644 index 9610477d8fd9..000000000000 --- a/src/librustc_typeck/check/assoc.rs +++ /dev/null @@ -1,39 +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. - -use rustc::infer::InferCtxt; -use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext, - ObligationCause}; -use rustc::ty::fold::TypeFoldable; -use syntax::ast; -use syntax_pos::Span; - -// FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument. -pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - fulfillment_cx: &mut FulfillmentContext<'tcx>, - span: Span, - body_id: ast::NodeId, - value: &T) -> T - - where T : TypeFoldable<'tcx> -{ - debug!("normalize_associated_types_in(value={:?})", value); - let mut selcx = SelectionContext::new(infcx); - let cause = ObligationCause::new(span, body_id, MiscObligation); - let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value); - debug!("normalize_associated_types_in: result={:?} predicates={:?}", - result, - obligations); - for obligation in obligations { - fulfillment_cx.register_predicate_obligation(infcx, obligation); - } - result -} diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 905d8688ea19..8a6853461a5e 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -20,7 +20,6 @@ use rustc::util::common::ErrorReported; use syntax::ast; use syntax_pos::Span; -use super::assoc; use super::{Inherited, FnCtxt}; use astconv::ExplicitSelf; @@ -227,7 +226,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| { let inh = Inherited::new(infcx); let infcx = &inh.infcx; - let fulfillment_cx = &inh.fulfillment_cx; debug!("compare_impl_method: caller_bounds={:?}", infcx.parameter_environment.caller_bounds); @@ -239,12 +237,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, infer::HigherRankedType, &ty::Binder(impl_m_own_bounds.predicates)); for predicate in impl_m_own_bounds { - let traits::Normalized { value: predicate, .. } = + let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); - fulfillment_cx.borrow_mut().register_predicate_obligation( - &infcx, - traits::Obligation::new(cause.clone(), predicate)); + inh.register_predicates(obligations); + inh.register_predicate(traits::Obligation::new(cause.clone(), predicate)); } // We now need to check that the signature of the impl method is @@ -277,11 +274,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx.borrow_mut(), - impl_m_span, - impl_m_body_id, - &impl_sig); + inh.normalize_associated_types_in(impl_m_span, + impl_m_body_id, + &impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -291,11 +286,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx.borrow_mut(), - impl_m_span, - impl_m_body_id, - &trait_sig); + inh.normalize_associated_types_in(impl_m_span, + impl_m_body_id, + &trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -344,7 +337,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { + if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { infcx.report_fulfillment_errors(errors); return Err(ErrorReported); } @@ -731,7 +724,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { - let mut fulfillment_cx = traits::FulfillmentContext::new(); + let inh = Inherited::new(infcx); + let infcx = &inh.infcx; // The below is for the most part highly similar to the procedure // for methods above. It is simpler in many respects, especially @@ -761,31 +755,21 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); - let err = infcx.commit_if_ok(|_| { - // There is no "body" here, so just pass dummy id. - let impl_ty = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &impl_ty); + // There is no "body" here, so just pass dummy id. + let impl_ty = inh.normalize_associated_types_in(impl_c_span, + impl_c_node_id, + &impl_ty); - debug!("compare_const_impl: impl_ty={:?}", impl_ty); + debug!("compare_const_impl: impl_ty={:?}", impl_ty); - let trait_ty = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &trait_ty); + let trait_ty = inh.normalize_associated_types_in(impl_c_span, + impl_c_node_id, + &trait_ty); - debug!("compare_const_impl: trait_ty={:?}", trait_ty); + debug!("compare_const_impl: trait_ty={:?}", trait_ty); - infcx.sub_types(false, &cause, impl_ty, trait_ty) - .map(|InferOk { obligations, value: () }| { - for obligation in obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - }) - }); + let err = infcx.sub_types(false, &cause, impl_ty, trait_ty) + .map(|ok| inh.register_infer_ok_obligations(ok)); if let Err(terr) = err { debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", @@ -822,5 +806,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &terr); diag.emit(); } + + // FIXME(#41323) Check the obligations in the fulfillment context. }); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7f887870afd9..2e69ad4cc618 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -129,7 +129,6 @@ use rustc_back::slice; use rustc_const_eval::eval_length; use rustc_const_math::ConstInt; -mod assoc; mod autoderef; pub mod dropck; pub mod _match; @@ -537,7 +536,7 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { - pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { + fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { Inherited { infcx: infcx, fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), @@ -548,20 +547,55 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { } } + fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { + debug!("register_predicate({:?})", obligation); + if obligation.has_escaping_regions() { + span_bug!(obligation.cause.span, "escaping regions in predicate {:?}", + obligation); + } + self.fulfillment_cx + .borrow_mut() + .register_predicate_obligation(self, obligation); + } + + fn register_predicates(&self, obligations: Vec>) { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, - value: &T) - -> T + value: &T) -> T where T : TypeFoldable<'tcx> { - assoc::normalize_associated_types_in(self, - &mut self.fulfillment_cx.borrow_mut(), - span, - body_id, - value) + let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, value); + self.register_infer_ok_obligations(ok) } + fn normalize_associated_types_in_as_infer_ok(&self, + span: Span, + body_id: ast::NodeId, + value: &T) + -> InferOk<'tcx, T> + where T : TypeFoldable<'tcx> + { + debug!("normalize_associated_types_in(value={:?})", value); + let mut selcx = traits::SelectionContext::new(self); + let cause = ObligationCause::misc(span, body_id); + let traits::Normalized { value, obligations } = + traits::normalize(&mut selcx, cause, value); + debug!("normalize_associated_types_in: result={:?} predicates={:?}", + value, + obligations); + InferOk { value, obligations } + } } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } @@ -1806,32 +1840,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .register_bound(self, ty, def_id, cause); } - pub fn register_predicate(&self, - obligation: traits::PredicateObligation<'tcx>) - { - debug!("register_predicate({:?})", obligation); - if obligation.has_escaping_regions() { - span_bug!(obligation.cause.span, "escaping regions in predicate {:?}", - obligation); - } - self.fulfillment_cx - .borrow_mut() - .register_predicate_obligation(self, obligation); - } - - pub fn register_predicates(&self, - obligations: Vec>) - { - for obligation in obligations { - self.register_predicate(obligation); - } - } - - pub fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { - self.register_predicates(infer_ok.obligations); - infer_ok.value - } - pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { let t = AstConv::ast_ty_to_ty(self, ast_t); self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); From 3725cab5ac1cb6a32b59b7731ce1d6e114c0ae00 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 23:59:25 +0300 Subject: [PATCH 533/905] rustc_typeck: return InferOk from lookup_method_in_trait_adjusted. --- src/librustc_typeck/check/autoderef.rs | 17 +++++--- src/librustc_typeck/check/callee.rs | 3 +- src/librustc_typeck/check/method/confirm.rs | 3 +- src/librustc_typeck/check/method/mod.rs | 46 +++++++++++++-------- src/librustc_typeck/check/mod.rs | 22 ++++++---- src/librustc_typeck/check/op.rs | 17 ++++---- 6 files changed, 67 insertions(+), 41 deletions(-) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index bfb69d620ace..92fb02c6379d 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -158,11 +158,16 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { -> InferOk<'tcx, ()> where E: AsCoercionSite { - let methods: Vec<_> = self.steps + let Autoderef { fcx, span, mut obligations, steps, .. } = self; + let methods: Vec<_> = steps .iter() .map(|&(ty, kind)| { if let AutoderefKind::Overloaded = kind { - self.fcx.try_overloaded_deref(self.span, None, ty, pref) + fcx.try_overloaded_deref(span, None, ty, pref) + .map(|InferOk { value, obligations: o }| { + obligations.extend(o); + value + }) } else { None } @@ -172,7 +177,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { debug!("finalize({:?}) - {:?},{:?}", pref, methods, - self.obligations); + obligations); for expr in exprs { let expr = expr.as_coercion_site(); @@ -180,14 +185,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { for (n, method) in methods.iter().enumerate() { if let &Some(method) = method { let method_call = MethodCall::autoderef(expr.id, n as u32); - self.fcx.tables.borrow_mut().method_map.insert(method_call, method); + fcx.tables.borrow_mut().method_map.insert(method_call, method); } } } InferOk { value: (), - obligations: self.obligations + obligations } } } @@ -209,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, lvalue_pref: LvaluePreference) - -> Option> { + -> Option>> { debug!("try_overloaded_deref({:?},{:?},{:?},{:?})", span, base_expr, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 70e585bd14f3..32f130aca1cb 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -173,7 +173,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { adjusted_ty, None) { None => continue, - Some(method_callee) => { + Some(ok) => { + let method_callee = self.register_infer_ok_obligations(ok); return Some(method_callee); } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e64ad775d521..26ba965fe5cc 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -543,7 +543,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { Some(&base_expr), self.node_ty(base_expr.id), PreferMutLvalue); - let method = method.expect("re-trying deref failed"); + let ok = method.expect("re-trying deref failed"); + let method = self.register_infer_ok_obligations(ok); self.tables.borrow_mut().method_map.insert(method_call, method); } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 9ecf0ffa71eb..7dd2699a6eaf 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -17,7 +17,8 @@ use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; -use rustc::infer; +use rustc::ty::subst::Subst; +use rustc::infer::{self, InferOk}; use syntax::ast; use syntax_pos::Span; @@ -159,7 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> { + -> Option>> { self.lookup_method_in_trait_adjusted(span, self_expr, m_name, @@ -190,7 +191,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unsize: bool, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> { + -> Option>> { debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \ m_name={}, trait_def_id={:?})", self_ty, @@ -236,6 +237,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert_eq!(generics.regions.len(), 0); debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); + let mut obligations = vec![]; // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -248,10 +250,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; - let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); + let fn_sig = fn_sig.subst(self.tcx, substs); + let fn_sig = match self.normalize_associated_types_in_as_infer_ok(span, &fn_sig) { + InferOk { value, obligations: o } => { + obligations.extend(o); + value + } + }; let transformed_self_ty = fn_sig.inputs()[0]; - let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs, - ty::Binder(fn_sig)); + let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig)); debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, @@ -265,18 +272,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs); - assert!(!method_bounds.has_escaping_regions()); - self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id), - &method_bounds); + let bounds = self.tcx.item_predicates(def_id).instantiate(self.tcx, substs); + let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) { + InferOk { value, obligations: o } => { + obligations.extend(o); + value + } + }; + assert!(!bounds.has_escaping_regions()); - // Also register an obligation for the method type being well-formed. - self.register_wf_obligation(method_ty, span, traits::MiscObligation); + let cause = traits::ObligationCause::misc(span, self.body_id); + obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds)); - // FIXME(#18653) -- Try to resolve obligations, giving us more - // typing information, which can sometimes be needed to avoid - // pathological region inference failures. - self.select_obligations_where_possible(); + // Also add an obligation for the method type being well-formed. + obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); // Insert any adjustments needed (always an autoref of some mutability). if let Some(self_expr) = self_expr { @@ -317,7 +326,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("callee = {:?}", callee); - Some(callee) + Some(InferOk { + obligations, + value: callee + }) } pub fn resolve_ufcs(&self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2e69ad4cc618..8b40cb140ae9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1749,14 +1749,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> ty::InstantiatedPredicates<'tcx> { let bounds = self.tcx.item_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result.predicates); + let result = self.normalize_associated_types_in(span, &result); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result); - ty::InstantiatedPredicates { - predicates: result - } + result } /// Replace all anonymized types with fresh inference variables @@ -1799,7 +1797,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn normalize_associated_types_in(&self, span: Span, value: &T) -> T where T : TypeFoldable<'tcx> { - self.inh.normalize_associated_types_in(span, self.body_id, value) + let ok = self.normalize_associated_types_in_as_infer_ok(span, value); + self.register_infer_ok_obligations(ok) + } + + fn normalize_associated_types_in_as_infer_ok(&self, span: Span, value: &T) + -> InferOk<'tcx, T> + where T : TypeFoldable<'tcx> + { + self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, value) } pub fn write_nil(&self, node_id: ast::NodeId) { @@ -2171,8 +2177,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - method.map(|method| { + method.map(|ok| { debug!("try_index_step: success, using overloaded indexing"); + let method = self.register_infer_ok_obligations(ok); self.tables.borrow_mut().method_map.insert(method_call, method); (input_ty, self.make_overloaded_lvalue_return_type(method).ty) }) @@ -3302,8 +3309,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; - } else if let Some(method) = self.try_overloaded_deref( + } else if let Some(ok) = self.try_overloaded_deref( expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { + let method = self.register_infer_ok_obligations(ok); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), method); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cc33bd8754d9..5b174aaf8953 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -398,20 +398,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match trait_did { Some(trait_did) => { - self.lookup_method_in_trait_adjusted(expr.span, - Some(lhs_expr), - opname, - trait_did, - 0, - false, - lhs_ty, - Some(other_tys)) + self.lookup_method_in_trait(expr.span, + Some(lhs_expr), + opname, + trait_did, + lhs_ty, + Some(other_tys)) } None => None }; match method { - Some(method) => { + Some(ok) => { + let method = self.register_infer_ok_obligations(ok); let method_ty = method.ty; // HACK(eddyb) Fully qualified path to work around a resolve bug. From cfa51f226f8190f74bcd3f8275ae05b9d76d59c4 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 15 Apr 2017 21:39:19 +0000 Subject: [PATCH 534/905] satisfy completely useless tidy check --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index aee6da93e506..129674b74769 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -352,7 +352,7 @@ declare_features! ( // Allows overlapping impls of marker traits (active, overlapping_marker_traits, "1.18.0", Some(29864)), - + // Allows use of the :vis macro fragment specifier (active, macro_vis_matcher, "1.18.0", Some(41022)), ); From 1afe77fb5f14294b7d29d0d57263e2399981c130 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Sat, 15 Apr 2017 23:55:59 +0200 Subject: [PATCH 535/905] Cleaned up throughout std::path's docs Part of #29368. * added missing links * updated method summaries to use 3rd person style * added missing periods in `Component`'s variant summaries * use standard iterator boilerplate in `Components`' and `Iter`'s docs * added example to `Iter::as_path`, adapted from `Components::as_path`'s example * consolidated examples for `Path::file_name` * some other small fixes --- src/libstd/path.rs | 125 ++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 47 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index db446d88900c..b751122e970d 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -370,13 +370,15 @@ pub struct PrefixComponent<'a> { } impl<'a> PrefixComponent<'a> { - /// The parsed prefix data. + /// Returns the parsed prefix data. #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> Prefix<'a> { self.parsed } - /// The raw `OsStr` slice for this prefix. + /// Returns the raw [`OsStr`] slice for this prefix. + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &'a OsStr { self.raw @@ -446,25 +448,25 @@ pub enum Component<'a> { #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> ), - /// The root directory component, appears after any prefix and before anything else + /// The root directory component, appears after any prefix and before anything else. #[stable(feature = "rust1", since = "1.0.0")] RootDir, - /// A reference to the current directory, i.e. `.` + /// A reference to the current directory, i.e. `.`. #[stable(feature = "rust1", since = "1.0.0")] CurDir, - /// A reference to the parent directory, i.e. `..` + /// A reference to the parent directory, i.e. `..`. #[stable(feature = "rust1", since = "1.0.0")] ParentDir, - /// A normal component, i.e. `a` and `b` in `a/b` + /// A normal component, e.g. `a` and `b` in `a/b`. #[stable(feature = "rust1", since = "1.0.0")] Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), } impl<'a> Component<'a> { - /// Extracts the underlying `OsStr` slice. + /// Extracts the underlying [`OsStr`] slice. /// /// # Examples /// @@ -475,6 +477,8 @@ impl<'a> Component<'a> { /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); /// ``` + /// + /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -494,12 +498,10 @@ impl<'a> AsRef for Component<'a> { } } -/// The core iterator giving the components of a path. +/// An interator over the [`Component`]s of a [`Path`]. /// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. -/// -/// This `struct` is created by the [`path::Path::components`] method. +/// This `struct` is created by the [`components`] method on [`Path`]. +/// See its documentation for more. /// /// # Examples /// @@ -513,7 +515,9 @@ impl<'a> AsRef for Component<'a> { /// } /// ``` /// -/// [`path::Path::components`]: struct.Path.html#method.components +/// [`Component`]: enum.Component.html +/// [`components`]: struct.Path.html#method.components +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -534,9 +538,15 @@ pub struct Components<'a> { back: State, } -/// An iterator over the components of a path, as [`OsStr`] slices. +/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices. /// +/// This `struct` is created by the [`iter`] method on [`Path`]. +/// See its documentation for more. +/// +/// [`Component`]: enum.Component.html +/// [`iter`]: struct.Path.html#method.iter /// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Path`]: struct.Path.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a> { @@ -762,6 +772,18 @@ impl<'a> fmt::Debug for Iter<'a> { impl<'a> Iter<'a> { /// Extracts a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let mut iter = Path::new("/tmp/foo/bar.txt").iter(); + /// iter.next(); + /// iter.next(); + /// + /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -1067,9 +1089,10 @@ impl PathBuf { /// Truncate `self` to [`self.parent`]. /// - /// Returns false and does nothing if [`self.file_name`] is `None`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`]. /// Otherwise, returns `true`. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`self.parent`]: struct.PathBuf.html#method.parent /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// @@ -1132,10 +1155,11 @@ impl PathBuf { /// Updates [`self.extension`] to `extension`. /// - /// If [`self.file_name`] is `None`, does nothing and returns `false`. + /// Returns `false` and does nothing if [`self.file_name`] is [`None`], + /// returns `true` and updates the extension otherwise. /// - /// Otherwise, returns `true`; if [`self.extension`] is [`None`], the - /// extension is added; otherwise it is replaced. + /// If [`self.extension`] is [`None`], the extension is added; otherwise + /// it is replaced. /// /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// [`self.extension`]: struct.PathBuf.html#method.extension @@ -1195,7 +1219,10 @@ impl PathBuf { self.inner } - /// Converts this `PathBuf` into a boxed `Path`. + /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`]. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`Path`]: struct.Path.html #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_boxed_path(self) -> Box { unsafe { mem::transmute(self.inner.into_boxed_os_str()) } @@ -1402,10 +1429,14 @@ pub struct Path { inner: OsStr, } -/// An error returned from the [`Path::strip_prefix`] method indicating that the -/// prefix was not found in `self`. +/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix +/// was not found. /// -/// [`Path::strip_prefix`]: struct.Path.html#method.strip_prefix +/// This `struct` is created by the [`strip_prefix`] method on [`Path`]. +/// See its documentation for more. +/// +/// [`strip_prefix`]: struct.Path.html#method.strip_prefix +/// [`Path`]: struct.Path.html #[derive(Debug, Clone, PartialEq, Eq)] #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); @@ -1421,7 +1452,7 @@ impl Path { os_str_as_u8_slice(&self.inner) } - /// Directly wrap a string slice as a `Path` slice. + /// Directly wraps a string slice as a `Path` slice. /// /// This is a cost-free conversion. /// @@ -1525,10 +1556,11 @@ impl Path { PathBuf::from(self.inner.to_os_string()) } - /// A path is *absolute* if it is independent of the current directory. + /// Returns `true` if the `Path` is absolute, i.e. if it is independent of + /// the current directory. /// /// * On Unix, a path is absolute if it starts with the root, so - /// `is_absolute` and `has_root` are equivalent. + /// `is_absolute` and [`has_root`] are equivalent. /// /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. @@ -1540,6 +1572,8 @@ impl Path { /// /// assert!(!Path::new("foo.txt").is_absolute()); /// ``` + /// + /// [`has_root`]: #method.has_root #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { @@ -1547,7 +1581,9 @@ impl Path { self.has_root() && (cfg!(unix) || cfg!(target_os = "redox") || self.prefix().is_some()) } - /// A path is *relative* if it is not absolute. + /// Return `false` if the `Path` is relative, i.e. not absolute. + /// + /// See [`is_absolute`]'s documentation for more details. /// /// # Examples /// @@ -1556,6 +1592,8 @@ impl Path { /// /// assert!(Path::new("foo.txt").is_relative()); /// ``` + /// + /// [`is_absolute`]: #method.is_absolute #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1565,7 +1603,7 @@ impl Path { self.components().prefix } - /// A path has a root if the body of the path begins with the directory separator. + /// Returns `true` if the `Path` has a root. /// /// * On Unix, a path has a root if it begins with `/`. /// @@ -1586,7 +1624,7 @@ impl Path { self.components().has_root() } - /// The path without its final component, if any. + /// Returns the `Path` without its final component, if there is one. /// /// Returns [`None`] if the path terminates in a root or prefix. /// @@ -1619,9 +1657,9 @@ impl Path { }) } - /// The final component of the path, if it is a normal file. + /// Returns the final component of the `Path`, if it is a normal file. /// - /// If the path terminates in `..`, `file_name` will return [`None`]. + /// Returns [`None`] If the path terminates in `..`. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// @@ -1631,18 +1669,7 @@ impl Path { /// use std::path::Path; /// use std::ffi::OsStr; /// - /// let path = Path::new("foo.txt"); - /// let os_str = OsStr::new("foo.txt"); - /// - /// assert_eq!(Some(os_str), path.file_name()); - /// ``` - /// - /// # Other examples - /// - /// ``` - /// use std::path::Path; - /// use std::ffi::OsStr; - /// + /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").file_name()); @@ -1869,7 +1896,7 @@ impl Path { buf } - /// Produce an iterator over the components of the path. + /// Produces an iterator over the components of the path. /// /// # Examples /// @@ -1896,7 +1923,7 @@ impl Path { } } - /// Produce an iterator over the path's components viewed as [`OsStr`] slices. + /// Produces an iterator over the path's components viewed as [`OsStr`] slices. /// /// [`OsStr`]: ../ffi/struct.OsStr.html /// @@ -1936,7 +1963,7 @@ impl Path { Display { path: self } } - /// Query the file system to get information about a file, directory, etc. + /// Queries the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the /// destination file. @@ -1959,7 +1986,7 @@ impl Path { fs::metadata(self) } - /// Query the metadata about a file without following symlinks. + /// Queries the metadata about a file without following symlinks. /// /// This is an alias to [`fs::symlink_metadata`]. /// @@ -2096,7 +2123,11 @@ impl Path { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) } - /// Converts a `Box` into a `PathBuf` without copying or allocating. + /// Converts a [`Box`][`Box`] into a [`PathBuf`] without copying or + /// allocating. + /// + /// [`Box`]: ../../std/boxed/struct.Box.html + /// [`PathBuf`]: struct.PathBuf.html #[unstable(feature = "into_boxed_path", issue = "40380")] pub fn into_path_buf(self: Box) -> PathBuf { let inner: Box = unsafe { mem::transmute(self) }; From 8854164d0cda3c90f6c3c774d8acf891599e4da3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 13 Apr 2017 16:40:03 +0300 Subject: [PATCH 536/905] rustc_const_eval: move ConstEvalErr to the rustc crate. --- src/Cargo.lock | 2 - src/librustc/diagnostics.rs | 19 +++ src/librustc/middle/const_val.rs | 168 ++++++++++++++++++++++- src/librustc/ty/maps.rs | 4 +- src/librustc_const_eval/Cargo.toml | 1 - src/librustc_const_eval/check_match.rs | 34 ++--- src/librustc_const_eval/diagnostics.rs | 19 --- src/librustc_const_eval/eval.rs | 176 +------------------------ src/librustc_const_eval/lib.rs | 1 - src/librustc_const_eval/pattern.rs | 4 +- src/librustc_metadata/decoder.rs | 3 +- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_mir/hair/cx/mod.rs | 17 ++- src/librustc_passes/consts.rs | 9 +- src/librustc_trans/Cargo.toml | 1 - src/librustc_trans/consts.rs | 2 +- src/librustc_trans/lib.rs | 1 - src/librustc_trans/mir/block.rs | 5 +- src/librustc_trans/mir/constant.rs | 7 +- src/librustc_trans/trans_item.rs | 5 +- src/librustc_typeck/collect.rs | 21 ++- 21 files changed, 245 insertions(+), 258 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 1fa256197ce5..c4b5366d4a32 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -503,7 +503,6 @@ name = "rustc_const_eval" version = "0.0.0" dependencies = [ "arena 0.0.0", - "graphviz 0.0.0", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", @@ -731,7 +730,6 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 5a0fbf8efb70..8a391f9cde3a 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -327,6 +327,25 @@ struct ListNode { This works because `Box` is a pointer, so its size is well-known. "##, +E0080: r##" +This error indicates that the compiler was unable to sensibly evaluate an +constant expression that had to be evaluated. Attempting to divide by 0 +or causing integer overflow are two ways to induce this error. For example: + +```compile_fail,E0080 +enum Enum { + X = (1 << 500), + Y = (1 / 0) +} +``` + +Ensure that the expressions given can be evaluated as the desired integer type. +See the FFI section of the Reference for more information about using a custom +integer type: + +https://doc.rust-lang.org/reference.html#ffi-attributes +"##, + E0106: r##" This error indicates that a lifetime is missing from a type. If it is an error inside a function signature, the problem may be with failing to adhere to the diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index d81f89827d93..9315f7f58081 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -8,17 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::symbol::InternedString; -use syntax::ast; -use std::rc::Rc; -use hir::def_id::DefId; -use ty::subst::Substs; -use rustc_const_math::*; - use self::ConstVal::*; pub use rustc_const_math::ConstInt; +use hir::def_id::DefId; +use ty::TyCtxt; +use ty::subst::Substs; +use rustc_const_math::*; + +use graphviz::IntoCow; +use errors::DiagnosticBuilder; +use syntax::symbol::InternedString; +use syntax::ast; +use syntax_pos::Span; + +use std::borrow::Cow; use std::collections::BTreeMap; +use std::rc::Rc; + +pub type EvalResult<'tcx> = Result, ConstEvalErr<'tcx>>; #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal<'tcx> { @@ -61,3 +69,149 @@ impl<'tcx> ConstVal<'tcx> { } } } + +#[derive(Clone, Debug)] +pub struct ConstEvalErr<'tcx> { + pub span: Span, + pub kind: ErrKind<'tcx>, +} + +#[derive(Clone, Debug)] +pub enum ErrKind<'tcx> { + CannotCast, + MissingStructField, + NegateOn(ConstVal<'tcx>), + NotOn(ConstVal<'tcx>), + CallOn(ConstVal<'tcx>), + + NonConstPath, + UnimplementedConstVal(&'static str), + ExpectedConstTuple, + ExpectedConstStruct, + IndexedNonVec, + IndexNotUsize, + IndexOutOfBounds { len: u64, index: u64 }, + + MiscBinaryOp, + MiscCatchAll, + + IndexOpFeatureGated, + Math(ConstMathErr), + + ErroneousReferencedConstant(Box>), + + TypeckError +} + +impl<'tcx> From for ErrKind<'tcx> { + fn from(err: ConstMathErr) -> ErrKind<'tcx> { + match err { + ConstMathErr::UnsignedNegation => ErrKind::TypeckError, + _ => ErrKind::Math(err) + } + } +} + +#[derive(Clone, Debug)] +pub enum ConstEvalErrDescription<'a> { + Simple(Cow<'a, str>), +} + +impl<'a> ConstEvalErrDescription<'a> { + /// Return a one-line description of the error, for lints and such + pub fn into_oneline(self) -> Cow<'a, str> { + match self { + ConstEvalErrDescription::Simple(simple) => simple, + } + } +} + +impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { + pub fn description(&self) -> ConstEvalErrDescription { + use self::ErrKind::*; + use self::ConstEvalErrDescription::*; + + macro_rules! simple { + ($msg:expr) => ({ Simple($msg.into_cow()) }); + ($fmt:expr, $($arg:tt)+) => ({ + Simple(format!($fmt, $($arg)+).into_cow()) + }) + } + + match self.kind { + CannotCast => simple!("can't cast this type"), + NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), + NotOn(ref const_val) => simple!("not on {}", const_val.description()), + CallOn(ref const_val) => simple!("call on {}", const_val.description()), + + MissingStructField => simple!("nonexistent struct field"), + NonConstPath => simple!("non-constant path in constant expression"), + UnimplementedConstVal(what) => + simple!("unimplemented constant expression: {}", what), + ExpectedConstTuple => simple!("expected constant tuple"), + ExpectedConstStruct => simple!("expected constant struct"), + IndexedNonVec => simple!("indexing is only supported for arrays"), + IndexNotUsize => simple!("indices must be of type `usize`"), + IndexOutOfBounds { len, index } => { + simple!("index out of bounds: the len is {} but the index is {}", + len, index) + } + + MiscBinaryOp => simple!("bad operands for binary"), + MiscCatchAll => simple!("unsupported constant expr"), + IndexOpFeatureGated => simple!("the index operation on const values is unstable"), + Math(ref err) => Simple(err.description().into_cow()), + + ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), + + TypeckError => simple!("type-checking failed"), + } + } + + pub fn struct_error(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str) + -> DiagnosticBuilder<'gcx> + { + let mut err = self; + while let &ConstEvalErr { + kind: ErrKind::ErroneousReferencedConstant(box ref i_err), .. + } = err { + err = i_err; + } + + let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); + err.note(tcx, primary_span, primary_kind, &mut diag); + diag + } + + pub fn note(&self, + _tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str, + diag: &mut DiagnosticBuilder) + { + match self.description() { + ConstEvalErrDescription::Simple(message) => { + diag.span_label(self.span, &message); + } + } + + if !primary_span.contains(self.span) { + diag.span_note(primary_span, + &format!("for {} here", primary_kind)); + } + } + + pub fn report(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str) + { + if let ErrKind::TypeckError = self.kind { + return; + } + self.struct_error(tcx, primary_span, primary_kind).emit(); + } +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 868ccad8a3a9..e9eb5e97582b 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,7 +10,7 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use middle::const_val::ConstVal; +use middle::const_val; use middle::privacy::AccessLevels; use mir; use session::CompileResult; @@ -443,7 +443,7 @@ define_maps! { <'tcx> /// Results of evaluating monomorphic constants embedded in /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result, ()>, + pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>, /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 907410f74dca..bbc614808249 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -17,5 +17,4 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } -graphviz = { path = "../libgraphviz" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 9d55281d019d..f1ab6a00aa2e 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -14,8 +14,6 @@ use _match::WitnessPreference::*; use pattern::{Pattern, PatternContext, PatternError, PatternKind}; -use eval::report_const_eval_err; - use rustc::dep_graph::DepNode; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; @@ -108,6 +106,22 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { } } +impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { + fn report_inlining_errors(&self, pat_span: Span) { + for error in &self.errors { + match *error { + PatternError::StaticInPattern(span) => { + span_err!(self.tcx.sess, span, E0158, + "statics cannot be referenced in patterns"); + } + PatternError::ConstEval(ref err) => { + err.report(self.tcx, pat_span, "pattern"); + } + } + } + } +} + impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_patterns(&self, has_guard: bool, pats: &[P]) { check_legality_of_move_bindings(self, has_guard, pats); @@ -116,20 +130,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } } - fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) { - for error in patcx.errors { - match error { - PatternError::StaticInPattern(span) => { - span_err!(self.tcx.sess, span, E0158, - "statics cannot be referenced in patterns"); - } - PatternError::ConstEval(err) => { - report_const_eval_err(self.tcx, &err, pat_span, "pattern"); - } - } - } - } - fn check_match( &self, scrut: &hir::Expr, @@ -161,7 +161,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let mut patcx = PatternContext::new(self.tcx, self.tables); let pattern = expand_pattern(cx, patcx.lower_pattern(&pat)); if !patcx.errors.is_empty() { - self.report_inlining_errors(patcx, pat.span); + patcx.report_inlining_errors(pat.span); have_errors = true; } (pattern, &**pat) diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 60eef8dd3bc5..04fc3e68c8cc 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -557,25 +557,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, -E0080: r##" -This error indicates that the compiler was unable to sensibly evaluate an -constant expression that had to be evaluated. Attempting to divide by 0 -or causing integer overflow are two ways to induce this error. For example: - -```compile_fail,E0080 -enum Enum { - X = (1 << 500), - Y = (1 / 0) -} -``` - -Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: - -https://doc.rust-lang.org/reference.html#ffi-attributes -"##, - } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 54f5cff16ed6..b928bae620b6 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -9,8 +9,8 @@ // except according to those terms. use rustc::middle::const_val::ConstVal::*; -use rustc::middle::const_val::ConstVal; -use self::ErrKind::*; +use rustc::middle::const_val::ErrKind::*; +use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind}; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; @@ -24,16 +24,13 @@ use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::DefIdMap; -use graphviz::IntoCow; use syntax::ast; use rustc::hir::{self, Expr}; use syntax_pos::{Span, DUMMY_SP}; -use std::borrow::Cow; use std::cmp::Ordering; use rustc_const_math::*; -use rustc_errors::DiagnosticBuilder; macro_rules! signal { ($e:expr, $exn:expr) => { @@ -158,66 +155,6 @@ fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) } } -fn build_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) - -> DiagnosticBuilder<'tcx> -{ - let mut err = err; - while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err { - err = i_err; - } - - let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); - note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag); - diag -} - -pub fn report_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) -{ - if let TypeckError = err.kind { - return; - } - build_const_eval_err(tcx, err, primary_span, primary_kind).emit(); -} - -pub fn fatal_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) - -> ! -{ - report_const_eval_err(tcx, err, primary_span, primary_kind); - tcx.sess.abort_if_errors(); - unreachable!() -} - -pub fn note_const_eval_err<'a, 'tcx>( - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str, - diag: &mut DiagnosticBuilder) -{ - match err.description() { - ConstEvalErrDescription::Simple(message) => { - diag.span_label(err.span, &message); - } - } - - if !primary_span.contains(err.span) { - diag.span_note(primary_span, - &format!("for {} here", primary_kind)); - } -} - pub struct ConstContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, @@ -251,107 +188,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { } } -#[derive(Clone, Debug)] -pub struct ConstEvalErr<'tcx> { - pub span: Span, - pub kind: ErrKind<'tcx>, -} - -#[derive(Clone, Debug)] -pub enum ErrKind<'tcx> { - CannotCast, - MissingStructField, - NegateOn(ConstVal<'tcx>), - NotOn(ConstVal<'tcx>), - CallOn(ConstVal<'tcx>), - - NonConstPath, - UnimplementedConstVal(&'static str), - ExpectedConstTuple, - ExpectedConstStruct, - IndexedNonVec, - IndexNotUsize, - IndexOutOfBounds { len: u64, index: u64 }, - - MiscBinaryOp, - MiscCatchAll, - - IndexOpFeatureGated, - Math(ConstMathErr), - - ErroneousReferencedConstant(Box>), - - TypeckError -} - -impl<'tcx> From for ErrKind<'tcx> { - fn from(err: ConstMathErr) -> ErrKind<'tcx> { - match err { - ConstMathErr::UnsignedNegation => TypeckError, - _ => Math(err) - } - } -} - -#[derive(Clone, Debug)] -pub enum ConstEvalErrDescription<'a> { - Simple(Cow<'a, str>), -} - -impl<'a> ConstEvalErrDescription<'a> { - /// Return a one-line description of the error, for lints and such - pub fn into_oneline(self) -> Cow<'a, str> { - match self { - ConstEvalErrDescription::Simple(simple) => simple, - } - } -} - -impl<'tcx> ConstEvalErr<'tcx> { - pub fn description(&self) -> ConstEvalErrDescription { - use self::ErrKind::*; - use self::ConstEvalErrDescription::*; - - macro_rules! simple { - ($msg:expr) => ({ Simple($msg.into_cow()) }); - ($fmt:expr, $($arg:tt)+) => ({ - Simple(format!($fmt, $($arg)+).into_cow()) - }) - } - - match self.kind { - CannotCast => simple!("can't cast this type"), - NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), - NotOn(ref const_val) => simple!("not on {}", const_val.description()), - CallOn(ref const_val) => simple!("call on {}", const_val.description()), - - MissingStructField => simple!("nonexistent struct field"), - NonConstPath => simple!("non-constant path in constant expression"), - UnimplementedConstVal(what) => - simple!("unimplemented constant expression: {}", what), - ExpectedConstTuple => simple!("expected constant tuple"), - ExpectedConstStruct => simple!("expected constant struct"), - IndexedNonVec => simple!("indexing is only supported for arrays"), - IndexNotUsize => simple!("indices must be of type `usize`"), - IndexOutOfBounds { len, index } => { - simple!("index out of bounds: the len is {} but the index is {}", - len, index) - } - - MiscBinaryOp => simple!("bad operands for binary"), - MiscCatchAll => simple!("unsupported constant expr"), - IndexOpFeatureGated => simple!("the index operation on const values is unstable"), - Math(ref err) => Simple(err.description().into_cow()), - - ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), - - TypeckError => simple!("type-checking failed"), - } - } -} - -pub type EvalResult<'tcx> = Result, ConstEvalErr<'tcx>>; -pub type CastResult<'tcx> = Result, ErrKind<'tcx>>; +type CastResult<'tcx> = Result, ErrKind<'tcx>>; fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, e: &Expr) -> EvalResult<'tcx> { @@ -947,14 +784,14 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { let a = match self.eval(a) { Ok(a) => a, Err(e) => { - report_const_eval_err(tcx, &e, a.span, "expression"); + e.report(tcx, a.span, "expression"); return Err(ErrorReported); } }; let b = match self.eval(b) { Ok(b) => b, Err(e) => { - report_const_eval_err(tcx, &e, b.span, "expression"); + e.report(tcx, b.span, "expression"); return Err(ErrorReported); } }; @@ -979,8 +816,7 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(_) | Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported), Err(err) => { - let mut diag = build_const_eval_err( - tcx, &err, count_expr.span, reason); + let mut diag = err.struct_error(tcx, count_expr.span, reason); if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { if let Def::Local(..) = path.def { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 4434a901f941..fa3161a86049 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -40,7 +40,6 @@ extern crate rustc_back; extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_errors; -extern crate graphviz; extern crate syntax_pos; // NB: This module needs to be declared first so diagnostics are diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index bd67dd2e6b25..f20fa27dc225 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -11,7 +11,7 @@ use eval; use rustc::lint; -use rustc::middle::const_val::ConstVal; +use rustc::middle::const_val::{ConstEvalErr, ConstVal}; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region}; use rustc::ty::subst::{Substs, Kind}; @@ -29,7 +29,7 @@ use syntax_pos::Span; #[derive(Clone, Debug)] pub enum PatternError<'tcx> { StaticInPattern(Span), - ConstEval(eval::ConstEvalErr<'tcx>), + ConstEval(ConstEvalErr<'tcx>), } #[derive(Copy, Clone, Debug)] diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3498be9dfdf3..d2512ff602a8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -524,7 +524,8 @@ impl<'a, 'tcx> CrateMetadata { }; if let ty::VariantDiscr::Explicit(def_id) = data.discr { - let result = data.evaluated_discr.map_or(Err(()), Ok); + // The original crate wouldn't have compiled if this is missing. + let result = Ok(data.evaluated_discr.unwrap()); tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result); } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index d9b8d04ad386..595748c8c6fd 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -17,7 +17,7 @@ use hair::cx::to_ref::ToRef; use rustc::hir::map; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ConstContext, fatal_const_eval_err}; +use rustc_const_eval::ConstContext; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -597,7 +597,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let count = match ConstContext::new(tcx, count).eval(c) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), - Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression") + Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; ExprKind::Repeat { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 3eef5d83b8ba..5f9fb8e1b120 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -17,8 +17,8 @@ use hair::*; use rustc::mir::transform::MirSource; -use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ConstContext, fatal_const_eval_err}; +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; use rustc::hir::map::blocks::FnLikeNode; @@ -115,10 +115,21 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let tcx = self.tcx.global_tcx(); match ConstContext::with_tables(tcx, self.tables()).eval(e) { Ok(value) => Literal::Value { value: value }, - Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression") + Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") } } + pub fn fatal_const_eval_err(&self, + err: &ConstEvalErr<'tcx>, + primary_span: Span, + primary_kind: &str) + -> ! + { + err.report(self.tcx, primary_span, primary_kind); + self.tcx.sess.abort_if_errors(); + unreachable!() + } + pub fn trait_method(&mut self, trait_def_id: DefId, method_name: &str, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 930a13e36bdc..44d3026d80c3 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -26,10 +26,11 @@ use rustc::dep_graph::DepNode; use rustc::ty::cast::CastKind; -use rustc_const_eval::{ConstEvalErr, ConstContext}; -use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math}; -use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; -use rustc_const_eval::ErrKind::{TypeckError}; +use rustc_const_eval::ConstContext; +use rustc::middle::const_val::ConstEvalErr; +use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll}; +use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; +use rustc::middle::const_val::ErrKind::{TypeckError, Math}; use rustc_const_math::{ConstMathErr, Op}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 07dcb2fc29dc..af477f5a1521 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -15,7 +15,6 @@ log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 6b6fa538dc03..7a53a03344fc 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -13,9 +13,9 @@ use back::symbol_names; use llvm; use llvm::{SetUnnamedAddr}; use llvm::{ValueRef, True}; -use rustc_const_eval::ConstEvalErr; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; +use rustc::middle::const_val::ConstEvalErr; use {debuginfo, machine}; use base; use trans_item::TransItem; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index abda358bc4f8..c5383fceb878 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -51,7 +51,6 @@ extern crate rustc_incremental; pub extern crate rustc_llvm as llvm; extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_const_math; -extern crate rustc_const_eval; #[macro_use] #[no_link] extern crate rustc_bitflags; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index caec4789eddc..0976859e27f4 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -9,9 +9,8 @@ // except according to those terms. use llvm::{self, ValueRef, BasicBlockRef}; -use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err}; use rustc::middle::lang_items; -use rustc::middle::const_val::ConstInt; +use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; @@ -363,7 +362,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let err = ConstEvalErr{ span: span, kind: err }; let mut diag = bcx.tcx().sess.struct_span_warn( span, "this expression will panic at run-time"); - note_const_eval_err(bcx.tcx(), &err, span, "expression", &mut diag); + err.note(bcx.tcx(), span, "expression", &mut diag); diag.emit(); } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 4d5b691c86eb..37d2b1952f49 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -9,8 +9,7 @@ // except according to those terms. use llvm::{self, ValueRef}; -use rustc::middle::const_val::ConstVal; -use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; use rustc_const_math::ConstInt::*; use rustc_const_math::ConstFloat::*; use rustc_const_math::{ConstInt, ConstMathErr}; @@ -327,8 +326,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } }; - let err = ConstEvalErr{ span: span, kind: err }; - report_const_eval_err(tcx, &err, span, "expression"); + let err = ConstEvalErr { span: span, kind: err }; + err.report(tcx, span, "expression"); failure = Err(err); } target diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index f5556bb8382f..4d908f3c94fa 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -28,7 +28,6 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::Substs; -use rustc_const_eval::fatal_const_eval_err; use syntax::ast::{self, NodeId}; use syntax::attr; use type_of; @@ -82,9 +81,7 @@ impl<'a, 'tcx> TransItem<'tcx> { match consts::trans_static(&ccx, m, item.id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, Err(err) => { - // FIXME: shouldn't this be a `span_err`? - fatal_const_eval_err( - ccx.tcx(), &err, item.span, "static"); + err.report(ccx.tcx(), item.span, "static"); } }; } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 649353d52f6a..4c7979ea3765 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -59,7 +59,7 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; -use rustc_const_eval::{ConstContext, report_const_eval_err}; +use rustc_const_eval::ConstContext; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; @@ -587,17 +587,6 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_predicates(def_id); } -fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: hir::BodyId) - -> Result, ()> { - let e = &tcx.hir.body(body).value; - ConstContext::new(tcx, body).eval(e).map_err(|err| { - // enum variant evaluation happens before the global constant check - // so we need to report the real error - report_const_eval_err(tcx, &err, e.span, "enum discriminant"); - }) -} - fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, variants: &[hir::Variant]) { @@ -612,9 +601,15 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || { - evaluate_disr_expr(tcx, e) + ConstContext::new(tcx, e).eval(&tcx.hir.body(e).value) }); + // enum variant evaluation happens before the global constant check + // so we need to report the real error + if let Err(ref err) = result { + err.report(tcx, variant.span, "enum discriminant"); + } + match result { Ok(ConstVal::Integral(x)) => Some(x), _ => None From 63064ec190fef7947c3eabfcdfeaeb293c9a91dd Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 14 Apr 2017 19:00:08 +0300 Subject: [PATCH 537/905] rustc: expose monomorphic const_eval through on-demand. --- src/Cargo.lock | 2 -- src/librustc/middle/const_val.rs | 37 +++++++++++++++++++++- src/librustc_const_eval/eval.rs | 53 ++++++++++---------------------- src/librustc_driver/driver.rs | 3 +- src/librustc_mir/hair/cx/expr.rs | 5 ++- src/librustc_typeck/Cargo.toml | 1 - src/librustc_typeck/astconv.rs | 4 +-- src/librustc_typeck/check/mod.rs | 4 +-- src/librustc_typeck/collect.rs | 6 +--- src/librustc_typeck/lib.rs | 1 - src/librustdoc/Cargo.toml | 1 - src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/lib.rs | 1 - 13 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index c4b5366d4a32..62b853480394 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -760,7 +760,6 @@ dependencies = [ "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -781,7 +780,6 @@ dependencies = [ "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_data_structures 0.0.0", "rustc_driver 0.0.0", "rustc_errors 0.0.0", diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 9315f7f58081..b4c5af940194 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,9 +11,12 @@ use self::ConstVal::*; pub use rustc_const_math::ConstInt; +use hir; +use hir::def::Def; use hir::def_id::DefId; -use ty::TyCtxt; +use ty::{self, TyCtxt}; use ty::subst::Substs; +use util::common::ErrorReported; use rustc_const_math::*; use graphviz::IntoCow; @@ -215,3 +218,35 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { self.struct_error(tcx, primary_span, primary_kind).emit(); } } + +/// Returns the value of the length-valued expression +pub fn eval_length(tcx: TyCtxt, + count: hir::BodyId, + reason: &str) + -> Result +{ + let count_expr = &tcx.hir.body(count).value; + let count_def_id = tcx.hir.body_owner_def_id(count); + match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) { + Ok(Integral(Usize(count))) => { + let val = count.as_u64(tcx.sess.target.uint_type); + assert_eq!(val as usize as u64, val); + Ok(val as usize) + }, + Ok(_) | + Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported), + Err(err) => { + let mut diag = err.struct_error(tcx, count_expr.span, reason); + + if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { + if let Def::Local(..) = path.def { + diag.note(&format!("`{}` is a variable", + tcx.hir.node_to_pretty_string(count_expr.id))); + } + } + + diag.emit(); + Err(ErrorReported) + } + } +} diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index b928bae620b6..bf8085be31c4 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -18,6 +18,7 @@ use rustc::traits; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use rustc::ty::subst::{Substs, Subst}; use rustc::traits::Reveal; @@ -163,12 +164,6 @@ pub struct ConstContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> ConstContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self { - let def_id = tcx.hir.body_owner_def_id(body); - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); - ConstContext::with_tables(tcx, tcx.item_tables(def_id)) - } - pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self { ConstContext { tcx: tcx, @@ -799,34 +794,20 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { } } - -/// Returns the value of the length-valued expression -pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - count: hir::BodyId, - reason: &str) - -> Result -{ - let count_expr = &tcx.hir.body(count).value; - match ConstContext::new(tcx, count).eval(count_expr) { - Ok(Integral(Usize(count))) => { - let val = count.as_u64(tcx.sess.target.uint_type); - assert_eq!(val as usize as u64, val); - Ok(val as usize) - }, - Ok(_) | - Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported), - Err(err) => { - let mut diag = err.struct_error(tcx, count_expr.span, reason); - - if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { - if let Def::Local(..) = path.def { - diag.note(&format!("`{}` is a variable", - tcx.hir.node_to_pretty_string(count_expr.id))); - } - } - - diag.emit(); - Err(ErrorReported) - } - } +pub fn provide(providers: &mut Providers) { + *providers = Providers { + monomorphic_const_eval, + ..*providers + }; +} + +fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> EvalResult<'tcx> { + ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id)); + + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let body = tcx.hir.body_owned_by(id); + cx.eval(&tcx.hir.body(body).value) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 48d9719e76c4..c856ea505ffe 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -37,7 +37,7 @@ use rustc_plugin::registry::Registry; use rustc_plugin as plugin; use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats, mir_stats}; -use rustc_const_eval::check_match; +use rustc_const_eval::{self, check_match}; use super::Compilation; use serialize::json; @@ -895,6 +895,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, typeck::provide(&mut local_providers); ty::provide(&mut local_providers); reachable::provide(&mut local_providers); + rustc_const_eval::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 595748c8c6fd..b7de50efe344 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -17,7 +17,6 @@ use hair::cx::to_ref::ToRef; use rustc::hir::map; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; -use rustc_const_eval::ConstContext; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -592,9 +591,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Now comes the rote stuff: hir::ExprRepeat(ref v, count) => { - let tcx = cx.tcx.global_tcx(); let c = &cx.tcx.hir.body(count).value; - let count = match ConstContext::new(tcx, count).eval(c) { + let def_id = cx.tcx.hir.body_owner_def_id(count); + let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 07998aa4a30e..194d37dcb81c 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -16,7 +16,6 @@ arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 66c4a81a5c0f..9426d601dfcc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -12,7 +12,7 @@ //! representation. The main routine here is `ast_ty_to_ty()`: each use //! is parameterized by an instance of `AstConv`. -use rustc_const_eval::eval_length; +use rustc::middle::const_val::eval_length; use rustc_data_structures::accumulate_vec::AccumulateVec; use hir; use hir::def::Def; @@ -1208,7 +1208,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0 } hir::TyArray(ref ty, length) => { - if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") { + if let Ok(length) = eval_length(tcx, length, "array length") { tcx.mk_array(self.ast_ty_to_ty(&ty), length) } else { self.tcx().types.err diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e7325275b81..d2c9fd119d72 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -126,7 +126,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::{self, PatKind}; use rustc::middle::lang_items; use rustc_back::slice; -use rustc_const_eval::eval_length; +use rustc::middle::const_val::eval_length; use rustc_const_math::ConstInt; mod assoc; @@ -3634,7 +3634,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.mk_array(element_ty, args.len()) } hir::ExprRepeat(ref element, count) => { - let count = eval_length(self.tcx.global_tcx(), count, "repeat count") + let count = eval_length(self.tcx, count, "repeat count") .unwrap_or(0); let uty = match expected { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4c7979ea3765..73e3de0cc76d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -59,14 +59,12 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; -use rustc_const_eval::ConstContext; use rustc::ty::subst::Substs; 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::dep_graph::DepNode; -use util::common::MemoizationMap; use util::nodemap::{NodeMap, FxHashMap}; use rustc_const_math::ConstInt; @@ -600,9 +598,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); - let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || { - ConstContext::new(tcx, e).eval(&tcx.hir.body(e).value) - }); + let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did); // enum variant evaluation happens before the global constant check // so we need to report the real error diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 12db76bf91c3..e9d52c5eb98d 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -94,7 +94,6 @@ extern crate fmt_macros; extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_back; extern crate rustc_const_math; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors as errors; diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 52f5d99838dc..e81acf7bdba8 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -14,7 +14,6 @@ env_logger = { version = "0.4", default-features = false } log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_driver = { path = "../librustc_driver" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3d233463bba3..47e1d0b7edb2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1715,7 +1715,7 @@ impl Clean for hir::Ty { } TySlice(ref ty) => Vector(box ty.clean(cx)), TyArray(ref ty, length) => { - use rustc_const_eval::eval_length; + use rustc::middle::const_val::eval_length; let n = eval_length(cx.tcx, length, "array length").unwrap(); FixedVector(box ty.clean(cx), n.to_string()) }, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 447d60018d91..d5b997001bb9 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -33,7 +33,6 @@ extern crate getopts; extern crate env_logger; extern crate libc; extern crate rustc; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_trans; extern crate rustc_driver; From 6dc21b71cfd8e5246e7953cf64ea5ee6a19ceb3d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 15 Apr 2017 04:14:44 +0300 Subject: [PATCH 538/905] rustc: use monomorphic const_eval for cross-crate enum discriminants. --- src/librustc/ty/mod.rs | 47 ++++++++++- src/librustc_const_eval/eval.rs | 11 ++- src/librustc_driver/driver.rs | 2 + .../persist/dirty_clean.rs | 11 +++ src/librustc_metadata/decoder.rs | 24 ++---- src/librustc_metadata/encoder.rs | 46 +++++++++-- src/librustc_metadata/schema.rs | 13 ++- src/librustc_trans/adt.rs | 20 ++--- src/librustc_trans/disr.rs | 82 ------------------- src/librustc_trans/lib.rs | 2 - src/librustc_trans/mir/constant.rs | 13 +-- src/librustc_trans/mir/rvalue.rs | 6 +- src/librustc_trans/mir/statement.rs | 3 +- src/test/incremental/hashes/enum_defs.rs | 8 +- 14 files changed, 139 insertions(+), 149 deletions(-) delete mode 100644 src/librustc_trans/disr.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 09eacb40aef7..0b5434f50e83 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1660,7 +1660,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.variants.iter().map(move |v| { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { - match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] { + match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { Ok(ConstVal::Integral(v)) => { discr = v; } @@ -1673,6 +1673,51 @@ impl<'a, 'gcx, 'tcx> AdtDef { }) } + /// Compute the discriminant value used by a specific variant. + /// Unlike `discriminants`, this is (amortized) constant-time, + /// only doing at most one query for evaluating an explicit + /// discriminant (the last one before the requested variant), + /// assuming there are no constant-evaluation errors there. + pub fn discriminant_for_variant(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + variant_index: usize) + -> ConstInt { + let repr_type = self.repr.discr_type(); + let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); + let mut explicit_index = variant_index; + loop { + match self.variants[explicit_index].discr { + ty::VariantDiscr::Relative(0) => break, + ty::VariantDiscr::Relative(distance) => { + explicit_index -= distance; + } + ty::VariantDiscr::Explicit(expr_did) => { + match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + Ok(ConstVal::Integral(v)) => { + explicit_value = v; + break; + } + _ => { + explicit_index -= 1; + } + } + } + } + } + let discr = explicit_value.to_u128_unchecked() + .wrapping_add((variant_index - explicit_index) as u128); + match repr_type { + attr::UnsignedInt(ty) => { + ConstInt::new_unsigned_truncating(discr, ty, + tcx.sess.target.uint_type) + } + attr::SignedInt(ty) => { + ConstInt::new_signed_truncating(discr as i128, ty, + tcx.sess.target.int_type) + } + } + } + pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { queries::adt_destructor::get(tcx, DUMMY_SP, self.did) } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index bf8085be31c4..9c5a669bef0d 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -804,10 +804,13 @@ pub fn provide(providers: &mut Providers) { fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> EvalResult<'tcx> { - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id)); - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - let body = tcx.hir.body_owned_by(id); - cx.eval(&tcx.hir.body(body).value) + let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { + ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + tcx.hir.body(tcx.hir.body_owned_by(id)) + } else { + tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap() + }; + cx.eval(&body.value) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c856ea505ffe..7632b40ab4f9 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -900,6 +900,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); ty::provide_extern(&mut extern_providers); + // FIXME(eddyb) get rid of this once we replace const_eval with miri. + rustc_const_eval::provide(&mut extern_providers); TyCtxt::create_and_enter(sess, local_providers, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index af5c1f05bd1f..b73b3e161f9b 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -266,6 +266,17 @@ impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, ' intravisit::walk_item(self, item); } + fn visit_variant(&mut self, + variant: &'tcx hir::Variant, + generics: &'tcx hir::Generics, + parent_id: ast::NodeId) { + if let Some(e) = variant.node.disr_expr { + self.check_item(e.node_id, variant.span); + } + + intravisit::walk_variant(self, variant, generics, parent_id); + } + fn visit_variant_data(&mut self, variant_data: &'tcx hir::VariantData, _: ast::Name, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d2512ff602a8..fac6079529e3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -511,11 +511,7 @@ impl<'a, 'tcx> CrateMetadata { def } - fn get_variant(&self, - item: &Entry<'tcx>, - index: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> (ty::VariantDef, Option) { + fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef { let data = match item.kind { EntryKind::Variant(data) | EntryKind::Struct(data, _) | @@ -523,13 +519,7 @@ impl<'a, 'tcx> CrateMetadata { _ => bug!(), }; - if let ty::VariantDiscr::Explicit(def_id) = data.discr { - // The original crate wouldn't have compiled if this is missing. - let result = Ok(data.evaluated_discr.unwrap()); - tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result); - } - - (ty::VariantDef { + ty::VariantDef { did: self.local_def_id(data.struct_ctor.unwrap_or(index)), name: self.item_name(index), fields: item.children.decode(self).map(|index| { @@ -542,7 +532,7 @@ impl<'a, 'tcx> CrateMetadata { }).collect(), discr: data.discr, ctor_kind: data.ctor_kind, - }, data.struct_ctor) + } } pub fn get_adt_def(&self, @@ -561,15 +551,11 @@ impl<'a, 'tcx> CrateMetadata { item.children .decode(self) .map(|index| { - let (variant, struct_ctor) = - self.get_variant(&self.entry(index), index, tcx); - assert_eq!(struct_ctor, None); - variant + self.get_variant(&self.entry(index), index) }) .collect() } else { - let (variant, _struct_ctor) = self.get_variant(&item, item_id, tcx); - vec![variant] + vec![self.get_variant(&item, item_id)] }; let (kind, repr) = match item.kind { EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr), diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0e204695e8f2..ce9f0a73fe2b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -269,12 +269,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: match variant.discr { - ty::VariantDiscr::Explicit(def_id) => { - ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok() - } - ty::VariantDiscr::Relative(_) => None - }, struct_ctor: None, }; @@ -408,7 +402,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: None, struct_ctor: Some(def_id.index), }; @@ -697,7 +690,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: None, struct_ctor: struct_ctor, }), repr_options) } @@ -708,7 +700,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - evaluated_discr: None, struct_ctor: None, }), repr_options) } @@ -1037,6 +1028,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { EntryBuilder::encode_info_for_foreign_item, (def_id, ni)); } + fn visit_variant(&mut self, + v: &'tcx hir::Variant, + g: &'tcx hir::Generics, + id: ast::NodeId) { + intravisit::walk_variant(self, v, g, id); + + if let Some(discr) = v.node.disr_expr { + let def_id = self.index.tcx.hir.body_owner_def_id(discr); + self.index.record(def_id, EntryBuilder::encode_info_for_embedded_const, def_id); + } + } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { intravisit::walk_generics(self, generics); self.index.encode_info_for_generics(generics); @@ -1160,6 +1162,32 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } } + fn encode_info_for_embedded_const(&mut self, def_id: DefId) -> Entry<'tcx> { + debug!("EntryBuilder::encode_info_for_embedded_const({:?})", def_id); + let tcx = self.tcx; + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let body = tcx.hir.body_owned_by(id); + + Entry { + kind: EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id)), + visibility: self.lazy(&ty::Visibility::Public), + span: self.lazy(&tcx.def_span(def_id)), + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: None, + deprecation: None, + + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + + ast: Some(self.encode_body(body)), + mir: self.encode_mir(def_id), + } + } + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { // NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because // we really on the HashStable specialization for [Attribute] diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 6cd35f1335ed..2f2e0e125aea 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -15,7 +15,6 @@ use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; use rustc::ich::StableHashingContext; -use rustc::middle::const_val::ConstVal; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; use rustc::mir; @@ -271,9 +270,9 @@ pub enum EntryKind<'tcx> { Type, Enum(ReprOptions), Field, - Variant(Lazy>), - Struct(Lazy>, ReprOptions), - Union(Lazy>, ReprOptions), + Variant(Lazy), + Struct(Lazy, ReprOptions), + Union(Lazy, ReprOptions), Fn(Lazy), ForeignFn(Lazy), Mod(Lazy), @@ -374,20 +373,18 @@ pub struct FnData { impl_stable_hash_for!(struct FnData { constness, arg_names }); #[derive(RustcEncodable, RustcDecodable)] -pub struct VariantData<'tcx> { +pub struct VariantData { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, - pub evaluated_discr: Option>, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. pub struct_ctor: Option, } -impl_stable_hash_for!(struct VariantData<'tcx> { +impl_stable_hash_for!(struct VariantData { ctor_kind, discr, - evaluated_discr, struct_ctor }); diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 0fe180253b5b..87ca410dece0 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -41,8 +41,6 @@ //! used unboxed and any field can have pointers (including mutable) //! taken to it, implementing them for Rust seems difficult. -use super::Disr; - use std; use llvm::{ValueRef, True, IntEQ, IntNE}; @@ -347,31 +345,31 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef, /// Set the discriminant for a new value of the given case of the given /// representation. -pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) { +pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: u64) { let l = bcx.ccx.layout_of(t); match *l { layout::CEnum{ discr, min, max, .. } => { - assert_discr_in_range(Disr(min), Disr(max), to); - bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true), + assert_discr_in_range(min, max, to); + bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true), val, None); } layout::General{ discr, .. } => { - bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true), + bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true), bcx.struct_gep(val, 0), None); } layout::Univariant { .. } | layout::UntaggedUnion { .. } | layout::Vector { .. } => { - assert_eq!(to, Disr(0)); + assert_eq!(to, 0); } layout::RawNullablePointer { nndiscr, .. } => { - if to.0 != nndiscr { + if to != nndiscr { let llptrty = val_ty(val).element_type(); bcx.store(C_null(llptrty), val, None); } } layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => { - if to.0 != nndiscr { + if to != nndiscr { if target_sets_discr_via_memset(bcx) { // Issue #34427: As workaround for LLVM bug on // ARM, use memset of 0 on whole struct rather @@ -397,7 +395,7 @@ fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &Builder<'a, 'tcx>) -> bool { bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64" } -pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) { +pub fn assert_discr_in_range(min: D, max: D, discr: D) { if min <= max { assert!(min <= discr && discr <= max) } else { @@ -415,7 +413,7 @@ fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a } /// (Not to be confused with `common::const_get_elt`, which operates on /// raw LLVM-level structs and arrays.) pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, - val: ValueRef, _discr: Disr, + val: ValueRef, ix: usize) -> ValueRef { let l = ccx.layout_of(t); match *l { diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs deleted file mode 100644 index a940faac8387..000000000000 --- a/src/librustc_trans/disr.rs +++ /dev/null @@ -1,82 +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 rustc::middle::const_val::ConstVal; -use rustc::ty::{self, TyCtxt}; -use rustc_const_math::ConstInt; - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -pub struct Disr(pub u64); - -impl Disr { - pub fn for_variant(tcx: TyCtxt, - def: &ty::AdtDef, - variant_index: usize) -> Self { - let mut explicit_index = variant_index; - let mut explicit_value = Disr(0); - loop { - match def.variants[explicit_index].discr { - ty::VariantDiscr::Relative(0) => break, - ty::VariantDiscr::Relative(distance) => { - explicit_index -= distance; - } - ty::VariantDiscr::Explicit(expr_did) => { - match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] { - Ok(ConstVal::Integral(v)) => { - explicit_value = Disr::from(v); - break; - } - _ => { - explicit_index -= 1; - } - } - } - } - } - let distance = variant_index - explicit_index; - explicit_value.wrapping_add(Disr::from(distance)) - } - - pub fn wrapping_add(self, other: Self) -> Self { - Disr(self.0.wrapping_add(other.0)) - } -} - -impl ::std::ops::BitAnd for Disr { - type Output = Disr; - fn bitand(self, other: Self) -> Self { - Disr(self.0 & other.0) - } -} - -impl From for Disr { - fn from(i: ConstInt) -> Disr { - // FIXME: what if discr has 128 bit discr? - Disr(i.to_u128_unchecked() as u64) - } -} - -impl From for Disr { - fn from(i: usize) -> Disr { - Disr(i as u64) - } -} - -impl PartialOrd for Disr { - fn partial_cmp(&self, other: &Disr) -> Option<::std::cmp::Ordering> { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for Disr { - fn cmp(&self, other: &Disr) -> ::std::cmp::Ordering { - self.0.cmp(&other.0) - } -} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index c5383fceb878..be214a0f6143 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -67,7 +67,6 @@ pub use rustc::lint; pub use rustc::util; pub use base::trans_crate; -pub use disr::Disr; pub mod back { pub use rustc::hir::svh; @@ -118,7 +117,6 @@ mod consts; mod context; mod debuginfo; mod declare; -mod disr; mod glue; mod intrinsic; mod machine; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 37d2b1952f49..8bce0cf85c08 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -22,7 +22,7 @@ use rustc::ty::layout::{self, LayoutTyper}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::subst::{Kind, Substs, Subst}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use {abi, adt, base, Disr, machine}; +use {abi, adt, base, machine}; use callee; use builder::Builder; use common::{self, CrateContext, const_get_elt, val_ty}; @@ -428,7 +428,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } mir::ProjectionElem::Field(ref field, _) => { let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval, - Disr(0), field.index()); + field.index()); let llextra = if is_sized { ptr::null_mut() } else { @@ -987,13 +987,14 @@ fn trans_const<'a, 'tcx>( layout::CEnum { discr: d, min, max, .. } => { let discr = match *kind { mir::AggregateKind::Adt(adt_def, _, _, _) => { - Disr::for_variant(ccx.tcx(), adt_def, variant_index) + adt_def.discriminant_for_variant(ccx.tcx(), variant_index) + .to_u128_unchecked() as u64 }, - _ => Disr(0), + _ => 0, }; assert_eq!(vals.len(), 0); - adt::assert_discr_in_range(Disr(min), Disr(max), discr); - C_integral(Type::from_integer(ccx, d), discr.0, true) + adt::assert_discr_in_range(min, max, discr); + C_integral(Type::from_integer(ccx, d), discr, true) } layout::General { discr: d, ref variants, .. } => { let variant = &variants[variant_index]; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index aa41720d717a..98e9008f829f 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -28,7 +28,6 @@ use type_::Type; use type_of; use tvec; use value::Value; -use Disr; use super::MirContext; use super::constant::const_scalar_checked_binop; @@ -107,9 +106,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::Rvalue::Aggregate(ref kind, ref operands) => { match *kind { mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => { - let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index); + let discr = adt_def.discriminant_for_variant(bcx.tcx(), variant_index) + .to_u128_unchecked() as u64; let dest_ty = dest.ty.to_ty(bcx.tcx()); - adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr); + adt::trans_set_discr(&bcx, dest_ty, dest.llval, discr); for (i, operand) in operands.iter().enumerate() { let op = self.trans_operand(&bcx, operand); // Do not generate stores and GEPis for zero-sized fields. diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 29a0648c8f8f..52c2afca4748 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -18,7 +18,6 @@ use builder::Builder; use super::MirContext; use super::LocalRef; use super::super::adt; -use super::super::disr::Disr; impl<'a, 'tcx> MirContext<'a, 'tcx> { pub fn trans_statement(&mut self, @@ -65,7 +64,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { adt::trans_set_discr(&bcx, ty, lvalue_transed.llval, - Disr::from(variant_index)); + variant_index as u64); bcx } mir::StatementKind::StorageLive(ref lvalue) => { diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index 37c6ef58f5e5..0f734683b60e 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -27,6 +27,7 @@ #![allow(warnings)] #![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] #![crate_type="rlib"] @@ -125,9 +126,12 @@ enum EnumChangeValueCStyleVariant0 { enum EnumChangeValueCStyleVariant0 { Variant1, - #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] - Variant2 = 22, + Variant2 = + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + 22, } #[cfg(cfail1)] From cd64ff943889b1cda1029a4a0d906d934a47abeb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 16 Apr 2017 06:25:18 +0300 Subject: [PATCH 539/905] rustc_typeck: fix binops needing more type informations to coerce. --- src/librustc_typeck/check/op.rs | 2 ++ src/test/run-pass/coerce-overloaded-autoderef.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 5b174aaf8953..42296006b79d 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -411,6 +411,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match method { Some(ok) => { let method = self.register_infer_ok_obligations(ok); + self.select_obligations_where_possible(); + let method_ty = method.ty; // HACK(eddyb) Fully qualified path to work around a resolve bug. diff --git a/src/test/run-pass/coerce-overloaded-autoderef.rs b/src/test/run-pass/coerce-overloaded-autoderef.rs index a053311a0403..091e29dd18a6 100644 --- a/src/test/run-pass/coerce-overloaded-autoderef.rs +++ b/src/test/run-pass/coerce-overloaded-autoderef.rs @@ -68,4 +68,8 @@ fn use_vec_ref(v: &Vec) { use_slice(&&&mut &&&v); } +fn use_op_rhs(s: &mut String) { + *s += {&String::from(" ")}; +} + pub fn main() {} From fcbd89850239a53a5dc459e99004c4b5b8e6146d Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 16 Apr 2017 16:17:13 +0300 Subject: [PATCH 540/905] Compress ReprOptions a little bit --- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/ty/layout.rs | 14 +++--- src/librustc/ty/mod.rs | 72 +++++++++++++++++++++--------- src/librustc/ty/sty.rs | 2 +- src/librustc_lint/types.rs | 6 +-- src/librustc_typeck/check/mod.rs | 2 +- 7 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 8926ff5c1fbb..342553593af3 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -162,7 +162,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { hir::ItemStruct(..) | hir::ItemUnion(..) => { let def_id = self.tcx.hir.local_def_id(item.id); let def = self.tcx.lookup_adt_def(def_id); - self.struct_has_extern_repr = def.repr.c; + self.struct_has_extern_repr = def.repr.c(); intravisit::walk_item(self, &item); } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 8dc298b9c2a1..942f8475eced 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -46,7 +46,7 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => return ty }; - if def.variants.len() == 2 && !def.repr.c && def.repr.int.is_none() { + if def.variants.len() == 2 && !def.repr.c() && def.repr.int.is_none() { let data_idx; if def.variants[0].fields.is_empty() { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index d7a4b3fda63b..df60eee8c024 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; +use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -479,7 +479,7 @@ impl Integer { return (discr, ity.is_signed()); } - if repr.c { + if repr.c() { match &tcx.sess.target.target.arch[..] { // WARNING: the ARM EABI has two variants; the one corresponding // to `at_least == I32` appears to be used on Linux and NetBSD, @@ -583,7 +583,7 @@ impl<'a, 'gcx, 'tcx> Struct { fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, repr: &ReprOptions, kind: StructKind, scapegoat: Ty<'gcx>) -> Result> { - let packed = repr.packed; + let packed = repr.packed(); let mut ret = Struct { align: if packed { dl.i8_align } else { dl.aggregate_align }, packed: packed, @@ -598,7 +598,7 @@ impl<'a, 'gcx, 'tcx> Struct { // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && !(repr.c || repr.packed || repr.linear || repr.simd); + && (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty(); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), @@ -1177,7 +1177,7 @@ impl<'a, 'gcx, 'tcx> Layout { } // SIMD vector types. - ty::TyAdt(def, ..) if def.repr.simd => { + ty::TyAdt(def, ..) if def.repr.simd() => { let element = ty.simd_type(tcx); match *element.layout(infcx)? { Scalar { value, .. } => { @@ -1255,7 +1255,7 @@ impl<'a, 'gcx, 'tcx> Layout { field.ty(tcx, substs).layout(infcx) }).collect::, _>>()?; let layout = if def.is_union() { - let mut un = Union::new(dl, def.repr.packed); + let mut un = Union::new(dl, def.repr.packed()); un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?; UntaggedUnion { variants: un } } else { @@ -1925,7 +1925,7 @@ impl<'a, 'tcx> TyLayout<'tcx> { ty::TyTuple(tys, _) => tys[i], // SIMD vector types. - ty::TyAdt(def, ..) if def.repr.simd => { + ty::TyAdt(def, ..) if def.repr.simd() => { self.ty.simd_type(tcx) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 09eacb40aef7..b4f2deabd234 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1438,51 +1438,81 @@ impl<'a, 'tcx> HashStable> for AdtDef { #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } +bitflags! { + #[derive(RustcEncodable, RustcDecodable, Default)] + flags ReprFlags: u8 { + const IS_C = 1 << 0, + const IS_PACKED = 1 << 1, + const IS_SIMD = 1 << 2, + // Internal only for now. If true, don't reorder fields. + const IS_LINEAR = 1 << 3, + + // Any of these flags being set prevent field reordering optimisation. + const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | + ReprFlags::IS_PACKED.bits | + ReprFlags::IS_SIMD.bits | + ReprFlags::IS_LINEAR.bits, + } +} + +impl_stable_hash_for!(struct ReprFlags { + bits +}); + + + /// Represents the repr options provided by the user, #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { - pub c: bool, - pub packed: bool, - pub simd: bool, pub int: Option, - // Internal only for now. If true, don't reorder fields. - pub linear: bool, + pub flags: ReprFlags, } impl_stable_hash_for!(struct ReprOptions { - c, - packed, - simd, int, - linear + flags }); impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { - let mut ret = ReprOptions::default(); + let mut flags = ReprFlags::empty(); + let mut size = None; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { - match r { - attr::ReprExtern => ret.c = true, - attr::ReprPacked => ret.packed = true, - attr::ReprSimd => ret.simd = true, - attr::ReprInt(i) => ret.int = Some(i), - } + flags.insert(match r { + attr::ReprExtern => ReprFlags::IS_C, + attr::ReprPacked => ReprFlags::IS_PACKED, + attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprInt(i) => { + size = Some(i); + ReprFlags::empty() + }, + }); } } // FIXME(eddyb) This is deprecated and should be removed. if tcx.has_attr(did, "simd") { - ret.simd = true; + flags.insert(ReprFlags::IS_SIMD); } // This is here instead of layout because the choice must make it into metadata. - ret.linear = !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", - tcx.item_path_str(did))); - ret + if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) { + flags.insert(ReprFlags::IS_LINEAR); + } + ReprOptions { int: size, flags: flags } } + #[inline] + pub fn simd(&self) -> bool { self.flags.contains(ReprFlags::IS_SIMD) } + #[inline] + pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } + #[inline] + pub fn packed(&self) -> bool { self.flags.contains(ReprFlags::IS_PACKED) } + #[inline] + pub fn linear(&self) -> bool { self.flags.contains(ReprFlags::IS_LINEAR) } + pub fn discr_type(&self) -> attr::IntType { self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is)) } @@ -1491,7 +1521,7 @@ impl ReprOptions { /// layout" optimizations, such as representing `Foo<&T>` as a /// single pointer. pub fn inhibit_enum_layout_opt(&self) -> bool { - self.c || self.int.is_some() + self.c() || self.int.is_some() } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0e3005847bc2..d59248170344 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1095,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { #[inline] pub fn is_simd(&self) -> bool { match self.sty { - TyAdt(def, _) => def.repr.simd, + TyAdt(def, _) => def.repr.simd(), _ => false, } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 2318bb81affe..3e60d8a5ada0 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -416,7 +416,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match def.adt_kind() { AdtKind::Struct => { - if !def.repr.c { + if !def.repr.c() { return FfiUnsafe("found struct without foreign-function-safe \ representation annotation in foreign module, \ consider adding a #[repr(C)] attribute to the type"); @@ -450,7 +450,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if all_phantom { FfiPhantom } else { FfiSafe } } AdtKind::Union => { - if !def.repr.c { + if !def.repr.c() { return FfiUnsafe("found union without foreign-function-safe \ representation annotation in foreign module, \ consider adding a #[repr(C)] attribute to the type"); @@ -489,7 +489,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check for a repr() attribute to specify the size of the // discriminant. - if !def.repr.c && def.repr.int.is_none() { + if !def.repr.c() && def.repr.int.is_none() { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, def, substs) { return FfiUnsafe("found enum without foreign-function-safe \ diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e7325275b81..daa18aaa556a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -918,7 +918,7 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); - if def.repr.simd { + if def.repr.simd() { check_simd(tcx, span, def_id); } } From 1bc9e5da2367cdeebd86afb4ad1a3d45aae53837 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 16 Apr 2017 09:33:13 -0600 Subject: [PATCH 541/905] Fix stdio descriptors in exec by removing cloexec if present. Use dup2 instead of dup --- src/libstd/sys/redox/process.rs | 21 ++++++++++++--------- src/libstd/sys/redox/syscall/call.rs | 5 +++++ src/libstd/sys/redox/syscall/number.rs | 1 + 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 707b4cbc6aca..95e9438cd719 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -270,19 +270,22 @@ impl Command { } if let Some(fd) = stdio.stderr.fd() { - let _ = syscall::close(2); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 2, &[]))); + let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(2, syscall::F_SETFL, flags))); } if let Some(fd) = stdio.stdout.fd() { - let _ = syscall::close(1); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 1, &[]))); + let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(1, syscall::F_SETFL, flags))); } if let Some(fd) = stdio.stdin.fd() { - let _ = syscall::close(0); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 0, &[]))); + let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(0, syscall::F_SETFL, flags))); } if let Some(g) = self.gid { diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs index f58c240f31e6..fadf7325d757 100644 --- a/src/libstd/sys/redox/syscall/call.rs +++ b/src/libstd/sys/redox/syscall/call.rs @@ -71,6 +71,11 @@ pub fn dup(fd: usize, buf: &[u8]) -> Result { unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } } +/// Copy and transform a file descriptor +pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result { + unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } +} + /// Replace the current process with a new executable pub fn execve(path: &str, args: &[[usize; 2]]) -> Result { unsafe { syscall4(SYS_EXECVE, path.as_ptr() as usize, path.len(), diff --git a/src/libstd/sys/redox/syscall/number.rs b/src/libstd/sys/redox/syscall/number.rs index 358746cd20a2..98f8b73e4e1b 100644 --- a/src/libstd/sys/redox/syscall/number.rs +++ b/src/libstd/sys/redox/syscall/number.rs @@ -28,6 +28,7 @@ pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; +pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; From 8c21b601367c4ee8c9b1554941189fdd09c8abb2 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 17 Apr 2017 00:24:46 +0200 Subject: [PATCH 542/905] Expand and add examples to std::path::{Prefix, PrefixComponent}'s docs Part of #29368. --- src/libstd/path.rs | 116 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index b751122e970d..77f0d9d95f29 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -145,34 +145,79 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; /// Path prefixes (Windows only). /// -/// Windows uses a variety of path styles, including references to drive -/// volumes (like `C:`), network shared folders (like `\\server\share`) and -/// others. In addition, some path prefixes are "verbatim", in which case -/// `/` is *not* treated as a separator and essentially no normalization is -/// performed. +/// Windows uses a variety of path prefix styles, including references to drive +/// volumes (like `C:`), network shared folders (like `\\server\share`), and +/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with +/// `\\?\`, in which case `/` is *not* treated as a separator and essentially no +/// normalization is performed. +/// +/// # Examples +/// +/// ``` +/// use std::path::{Component, Path, Prefix}; +/// use std::path::Prefix::*; +/// use std::ffi::OsStr; +/// +/// fn get_path_prefix(s: &str) -> Prefix { +/// let path = Path::new(s); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => prefix_component.kind(), +/// _ => panic!(), +/// } +/// } +/// +/// # if cfg!(windows) { +/// assert_eq!(Verbatim(OsStr::new("pictures")), +/// get_path_prefix(r"\\?\pictures\kittens")); +/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\?\UNC\server\share")); +/// assert_eq!(VerbatimDisk('C' as u8), get_path_prefix(r"\\?\c:\")); +/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")), +/// get_path_prefix(r"\\.\BrainInterface")); +/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")), +/// get_path_prefix(r"\\server\share")); +/// assert_eq!(Disk('C' as u8), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris")); +/// # } +/// ``` #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { - /// Prefix `\\?\`, together with the given component immediately following it. + /// Verbatim prefix, e.g. `\\?\cat_pics`. + /// + /// Verbatim prefixes consist of `\\?\` immediately followed by the given + /// component. #[stable(feature = "rust1", since = "1.0.0")] Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\?\UNC\`, with the "server" and "share" components following it. + /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_, + /// e.g. `\\?\UNC\server\share`. + /// + /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the + /// server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] VerbatimUNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, ), - /// Prefix like `\\?\C:\`, for the given drive letter + /// Verbatim disk prefix, e.g. `\\?\C:\`. + /// + /// Verbatim disk prefixes consist of `\\?\` immediately followed by the + /// drive letter and `:\`. #[stable(feature = "rust1", since = "1.0.0")] VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), - /// Prefix `\\.\`, together with the given component immediately following it. + /// Device namespace prefix, e.g. `\\.\COM42`. + /// + /// Device namespace prefixes consist of `\\.\` immediately followed by the + /// device name. #[stable(feature = "rust1", since = "1.0.0")] DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - /// Prefix `\\server\share`, with the given "server" and "share" components. + /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g. + /// `\\server\share`. + /// + /// UNC prefixes consist of the server's hostname and a share name. #[stable(feature = "rust1", since = "1.0.0")] UNC( #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, @@ -217,6 +262,20 @@ impl<'a> Prefix<'a> { } /// Determines if the prefix is verbatim, i.e. begins with `\\?\`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Prefix::*; + /// use std::ffi::OsStr; + /// + /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim()); + /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(VerbatimDisk('C' as u8).is_verbatim()); + /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim()); + /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); + /// assert!(!Disk('C' as u8).is_verbatim()); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { @@ -358,7 +417,39 @@ enum State { /// A Windows path prefix, e.g. `C:` or `\\server\share`. /// +/// In addition to the parsed [`Prefix`] information returned by [`kind`], +/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, +/// returned by [`as_os_str`]. +/// +/// Instances of this `struct` can be obtained by matching against the +/// [`Prefix` variant] on [`Component`]. +/// /// Does not occur on Unix. +/// +/// # Examples +/// +/// ``` +/// # if cfg!(windows) { +/// use std::path::{Component, Path, Prefix}; +/// use std::ffi::OsStr; +/// +/// let path = Path::new(r"c:\you\later\"); +/// match path.components().next().unwrap() { +/// Component::Prefix(prefix_component) => { +/// assert_eq!(Prefix::Disk('C' as u8), prefix_component.kind()); +/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str()); +/// } +/// _ => unreachable!(), +/// } +/// # } +/// ``` +/// +/// [`as_os_str`]: #method.as_os_str +/// [`Component`]: enum.Component.html +/// [`kind`]: #method.kind +/// [`OsStr`]: ../../std/ffi/struct.OsStr.html +/// [`Prefix` variant]: enum.Component.html#variant.Prefix +/// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Eq, Debug)] pub struct PrefixComponent<'a> { @@ -371,6 +462,11 @@ pub struct PrefixComponent<'a> { impl<'a> PrefixComponent<'a> { /// Returns the parsed prefix data. + /// + /// See [`Prefix`]'s documentation for more information on the different + /// kinds of prefixes. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> Prefix<'a> { self.parsed From bbdf190c6a2d5bc095c8d3addff0868395bff31f Mon Sep 17 00:00:00 2001 From: Evgeny Safronov Date: Mon, 17 Apr 2017 09:41:12 +0300 Subject: [PATCH 543/905] fix: remove `field_init_shorthand` from SUMMARY.md --- src/doc/unstable-book/src/SUMMARY.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9acb7b4afe7e..fe638fd64177 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -78,7 +78,6 @@ - [fmt_internals](fmt-internals.md) - [fn_traits](fn-traits.md) - [fnbox](fnbox.md) -- [field_init_shorthand](field-init-shorthand.md) - [from_utf8_error_as_bytes](from_utf8_error_as_bytes.md) - [fundamental](fundamental.md) - [fused](fused.md) From 08a955af68ae350dabb7b66b4981f4503ba74aa3 Mon Sep 17 00:00:00 2001 From: alexey zabelin Date: Mon, 17 Apr 2017 10:48:23 -0400 Subject: [PATCH 544/905] Adjust description --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0fddbca72cdc..ab4ac6f1b91e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4066,7 +4066,7 @@ impl<'a> Parser<'a> { }).emit(); } - // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) From 17fce06c18b9f362b74fb8548b64e3e41991cda5 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 17 Apr 2017 18:15:22 +0300 Subject: [PATCH 545/905] rustc: move associated_item_def_ids to an on-demand query. --- src/librustc/ty/mod.rs | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b4f2deabd234..e3d1a4cea98d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -31,7 +31,6 @@ use ty; use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; -use util::common::MemoizationMap; use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use serialize::{self, Encodable, Encoder}; @@ -2154,30 +2153,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { - if !def_id.is_local() { - return queries::associated_item_def_ids::get(self, DUMMY_SP, def_id); - } - - self.maps.associated_item_def_ids.memoize(def_id, || { - let id = self.hir.as_local_node_id(def_id).unwrap(); - let item = self.hir.expect_item(id); - let vec: Vec<_> = match item.node { - hir::ItemTrait(.., ref trait_item_refs) => { - trait_item_refs.iter() - .map(|trait_item_ref| trait_item_ref.id) - .map(|id| self.hir.local_def_id(id.node_id)) - .collect() - } - hir::ItemImpl(.., ref impl_item_refs) => { - impl_item_refs.iter() - .map(|impl_item_ref| impl_item_ref.id) - .map(|id| self.hir.local_def_id(id.node_id)) - .collect() - } - _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") - }; - Rc::new(vec) - }) + queries::associated_item_def_ids::get(self, DUMMY_SP, def_id) } #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. @@ -2708,9 +2684,33 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty } +fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Rc> { + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let item = tcx.hir.expect_item(id); + let vec: Vec<_> = match item.node { + hir::ItemTrait(.., ref trait_item_refs) => { + trait_item_refs.iter() + .map(|trait_item_ref| trait_item_ref.id) + .map(|id| tcx.hir.local_def_id(id.node_id)) + .collect() + } + hir::ItemImpl(.., ref impl_item_refs) => { + impl_item_refs.iter() + .map(|impl_item_ref| impl_item_ref.id) + .map(|id| tcx.hir.local_def_id(id.node_id)) + .collect() + } + _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") + }; + Rc::new(vec) +} + pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { associated_item, + associated_item_def_ids, adt_sized_constraint, ..*providers }; From 27bfbd56f08ab64122a79cb84446a27b99099590 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Mon, 21 Nov 2016 15:52:51 -0600 Subject: [PATCH 546/905] rustdoc: add a list of headings to the sidebar --- src/librustdoc/clean/mod.rs | 5 +- src/librustdoc/html/render.rs | 224 +++++++++++++++++++++++++++++++++- 2 files changed, 225 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac72d7d29a24..1b7615fa05b0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -292,7 +292,7 @@ impl Item { self.type_() == ItemType::Struct } pub fn is_enum(&self) -> bool { - self.type_() == ItemType::Module + self.type_() == ItemType::Enum } pub fn is_fn(&self) -> bool { self.type_() == ItemType::Function @@ -312,6 +312,9 @@ impl Item { pub fn is_primitive(&self) -> bool { self.type_() == ItemType::Primitive } + pub fn is_union(&self) -> bool { + self.type_() == ItemType::Union + } pub fn is_stripped(&self) -> bool { match self.inner { StrippedItem(..) => true, _ => false } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1e1202f04005..22e113e501b8 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2411,7 +2411,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, }).peekable(); if let doctree::Plain = s.struct_type { if fields.peek().is_some() { - write!(w, "

    Fields

    ")?; + write!(w, "

    Fields

    ")?; for (field, ty) in fields { let id = derive_id(format!("{}.{}", ItemType::StructField, @@ -2459,7 +2459,7 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } }).peekable(); if fields.peek().is_some() { - write!(w, "

    Fields

    ")?; + write!(w, "

    Fields

    ")?; for (field, ty) in fields { write!(w, "{name}: {ty} ", @@ -2535,7 +2535,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, document(w, cx, it)?; if !e.variants.is_empty() { - write!(w, "

    Variants

    \n")?; + write!(w, "

    Variants

    \n")?; for variant in &e.variants { let id = derive_id(format!("{}.{}", ItemType::Variant, @@ -3077,6 +3077,37 @@ impl<'a> fmt::Display for Sidebar<'a> { let it = self.item; let parentlen = cx.current.len() - if it.is_mod() {1} else {0}; + if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union() + || it.is_enum() || it.is_mod() + { + write!(fmt, "

    ")?; + match it.inner { + clean::StructItem(..) => write!(fmt, "Struct ")?, + clean::TraitItem(..) => write!(fmt, "Trait ")?, + clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, + clean::UnionItem(..) => write!(fmt, "Union ")?, + clean::EnumItem(..) => write!(fmt, "Enum ")?, + clean::ModuleItem(..) => if it.is_crate() { + write!(fmt, "Crate ")?; + } else { + write!(fmt, "Module ")?; + }, + _ => (), + } + write!(fmt, "{}", it.name.as_ref().unwrap())?; + write!(fmt, "

    ")?; + + match it.inner { + clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?, + clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?, + clean::PrimitiveItem(ref p) => sidebar_primitive(fmt, it, p)?, + clean::UnionItem(ref u) => sidebar_union(fmt, it, u)?, + clean::EnumItem(ref e) => sidebar_enum(fmt, it, e)?, + clean::ModuleItem(ref m) => sidebar_module(fmt, it, &m.items)?, + _ => (), + } + } + // The sidebar is designed to display sibling functions, modules and // other miscellaneous information. since there are lots of sibling // items (and that causes quadratic growth in large modules), @@ -3119,6 +3150,193 @@ impl<'a> fmt::Display for Sidebar<'a> { } } +fn sidebar_assoc_items(it: &clean::Item) -> String { + let mut out = String::new(); + let c = cache(); + if let Some(v) = c.impls.get(&it.def_id) { + if v.iter().any(|i| i.inner_impl().trait_.is_none()) { + out.push_str("
  • Methods
  • "); + } + + if v.iter().any(|i| i.inner_impl().trait_.is_some()) { + if let Some(impl_) = v.iter() + .filter(|i| i.inner_impl().trait_.is_some()) + .find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did) { + if let Some(target) = impl_.inner_impl().items.iter().filter_map(|item| { + match item.inner { + clean::TypedefItem(ref t, true) => Some(&t.type_), + _ => None, + } + }).next() { + let inner_impl = target.def_id().or(target.primitive_type().and_then(|prim| { + c.primitive_locations.get(&prim).cloned() + })).and_then(|did| c.impls.get(&did)); + if inner_impl.is_some() { + out.push_str("
  • "); + out.push_str(&format!("Methods from {:#}<Target={:#}>", + impl_.inner_impl().trait_.as_ref().unwrap(), + target)); + out.push_str("
  • "); + } + } + } + out.push_str("
  • Trait Implementations
  • "); + } + } + + out +} + +fn sidebar_struct(fmt: &mut fmt::Formatter, it: &clean::Item, + s: &clean::Struct) -> fmt::Result { + let mut sidebar = String::new(); + + if s.fields.iter() + .any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) { + if let doctree::Plain = s.struct_type { + sidebar.push_str("
  • Fields
  • "); + } + } + + sidebar.push_str(&sidebar_assoc_items(it)); + + if !sidebar.is_empty() { + write!(fmt, "
      {}
    ", sidebar)?; + } + Ok(()) +} + +fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item, + t: &clean::Trait) -> fmt::Result { + let mut sidebar = String::new(); + + let has_types = t.items.iter().any(|m| m.is_associated_type()); + let has_consts = t.items.iter().any(|m| m.is_associated_const()); + let has_required = t.items.iter().any(|m| m.is_ty_method()); + let has_provided = t.items.iter().any(|m| m.is_method()); + + if has_types { + sidebar.push_str("
  • Associated Types
  • "); + } + if has_consts { + sidebar.push_str("
  • Associated Constants
  • "); + } + if has_required { + sidebar.push_str("
  • Required Methods
  • "); + } + if has_provided { + sidebar.push_str("
  • Provided Methods
  • "); + } + + sidebar.push_str(&sidebar_assoc_items(it)); + + sidebar.push_str("
  • Implementors
  • "); + + write!(fmt, "
      {}
    ", sidebar) +} + +fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item, + _p: &clean::PrimitiveType) -> fmt::Result { + let sidebar = sidebar_assoc_items(it); + + if !sidebar.is_empty() { + write!(fmt, "
      {}
    ", sidebar)?; + } + Ok(()) +} + +fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item, + u: &clean::Union) -> fmt::Result { + let mut sidebar = String::new(); + + if u.fields.iter() + .any(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) { + sidebar.push_str("
  • Fields
  • "); + } + + sidebar.push_str(&sidebar_assoc_items(it)); + + if !sidebar.is_empty() { + write!(fmt, "
      {}
    ", sidebar)?; + } + Ok(()) +} + +fn sidebar_enum(fmt: &mut fmt::Formatter, it: &clean::Item, + e: &clean::Enum) -> fmt::Result { + let mut sidebar = String::new(); + + if !e.variants.is_empty() { + sidebar.push_str("
  • Variants
  • "); + } + + sidebar.push_str(&sidebar_assoc_items(it)); + + if !sidebar.is_empty() { + write!(fmt, "
      {}
    ", sidebar)?; + } + Ok(()) +} + +fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item, + items: &[clean::Item]) -> fmt::Result { + let mut sidebar = String::new(); + + if items.iter().any(|it| it.type_() == ItemType::ExternCrate || + it.type_() == ItemType::Import) { + sidebar.push_str(&format!("
  • {name}
  • ", + id = "reexports", + name = "Reexports")); + } + + // ordering taken from item_module, reorder, where it prioritized elements in a certain order + // to print its headings + for &myty in &[ItemType::Primitive, ItemType::Module, ItemType::Macro, ItemType::Struct, + ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait, + ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl, + ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant, + ItemType::AssociatedType, ItemType::AssociatedConst] { + if items.iter().any(|it| { + if let clean::DefaultImplItem(..) = it.inner { + false + } else { + !maybe_ignore_item(it) && !it.is_stripped() && it.type_() == myty + } + }) { + let (short, name) = match myty { + ItemType::ExternCrate | + ItemType::Import => ("reexports", "Reexports"), + ItemType::Module => ("modules", "Modules"), + ItemType::Struct => ("structs", "Structs"), + ItemType::Union => ("unions", "Unions"), + ItemType::Enum => ("enums", "Enums"), + ItemType::Function => ("functions", "Functions"), + ItemType::Typedef => ("types", "Type Definitions"), + ItemType::Static => ("statics", "Statics"), + ItemType::Constant => ("constants", "Constants"), + ItemType::Trait => ("traits", "Traits"), + ItemType::Impl => ("impls", "Implementations"), + ItemType::TyMethod => ("tymethods", "Type Methods"), + ItemType::Method => ("methods", "Methods"), + ItemType::StructField => ("fields", "Struct Fields"), + ItemType::Variant => ("variants", "Variants"), + ItemType::Macro => ("macros", "Macros"), + ItemType::Primitive => ("primitives", "Primitive Types"), + ItemType::AssociatedType => ("associated-types", "Associated Types"), + ItemType::AssociatedConst => ("associated-consts", "Associated Constants"), + }; + sidebar.push_str(&format!("
  • {name}
  • ", + id = short, + name = name)); + } + } + + if !sidebar.is_empty() { + write!(fmt, "
      {}
    ", sidebar)?; + } + Ok(()) +} + impl<'a> fmt::Display for Source<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let Source(s) = *self; From cbf8342efe8acface3c2751e347212ca582ed25d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Apr 2017 01:23:14 +0200 Subject: [PATCH 547/905] Hoedown big comeback! --- .gitmodules | 4 + src/librustdoc/Cargo.toml | 1 + src/librustdoc/build.rs | 30 +++++ src/librustdoc/html/markdown.rs | 191 ++++++++++++++++++++++++++++++++ src/librustdoc/markdown.rs | 3 +- src/librustdoc/test.rs | 34 +++++- src/rt/hoedown | 1 + 7 files changed, 257 insertions(+), 7 deletions(-) create mode 100644 src/librustdoc/build.rs create mode 160000 src/rt/hoedown diff --git a/.gitmodules b/.gitmodules index 4f29cef85700..9003f0750a23 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,6 +5,10 @@ [submodule "src/compiler-rt"] path = src/compiler-rt url = https://github.com/rust-lang/compiler-rt.git +[submodule "src/rt/hoedown"] + path = src/rt/hoedown + url = https://github.com/rust-lang/hoedown.git + branch = rust-2015-09-21-do-not-delete [submodule "src/jemalloc"] path = src/jemalloc url = https://github.com/rust-lang/jemalloc.git diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 52f5d99838dc..d1c98a5c6f16 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustdoc" version = "0.0.0" +build = "build.rs" [lib] name = "rustdoc" diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs new file mode 100644 index 000000000000..4189e3d2ac70 --- /dev/null +++ b/src/librustdoc/build.rs @@ -0,0 +1,30 @@ +// 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. + +extern crate build_helper; +extern crate gcc; + +fn main() { + let src_dir = std::path::Path::new("../rt/hoedown/src"); + build_helper::rerun_if_changed_anything_in_dir(src_dir); + let mut cfg = gcc::Config::new(); + cfg.file("../rt/hoedown/src/autolink.c") + .file("../rt/hoedown/src/buffer.c") + .file("../rt/hoedown/src/document.c") + .file("../rt/hoedown/src/escape.c") + .file("../rt/hoedown/src/html.c") + .file("../rt/hoedown/src/html_blocks.c") + .file("../rt/hoedown/src/html_smartypants.c") + .file("../rt/hoedown/src/stack.c") + .file("../rt/hoedown/src/version.c") + .include(src_dir) + .compile("libhoedown.a"); +} + diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c59101cc7799..b02b60531d10 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -25,6 +25,9 @@ #![allow(non_camel_case_types)] +use libc; +use std::slice; + use std::ascii::AsciiExt; use std::cell::RefCell; use std::collections::{HashMap, VecDeque}; @@ -357,6 +360,194 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { } } +const DEF_OUNIT: libc::size_t = 64; +const HOEDOWN_EXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 11; +const HOEDOWN_EXT_TABLES: libc::c_uint = 1 << 0; +const HOEDOWN_EXT_FENCED_CODE: libc::c_uint = 1 << 1; +const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; +const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; +const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; +const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; + +const HOEDOWN_EXTENSIONS: libc::c_uint = + HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | + HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK | + HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_SUPERSCRIPT | + HOEDOWN_EXT_FOOTNOTES; + +enum hoedown_document {} + +type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_buffer, *const hoedown_renderer_data, + libc::size_t); + +type blockquotefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_renderer_data, libc::size_t); + +type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + libc::c_int, *const hoedown_renderer_data, + libc::size_t); + +type blockhtmlfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_renderer_data, libc::size_t); + +type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_renderer_data, libc::size_t) -> libc::c_int; + +type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_buffer, *const hoedown_buffer, + *const hoedown_renderer_data, libc::size_t) -> libc::c_int; + +type entityfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_renderer_data, libc::size_t); + +type normaltextfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_renderer_data, libc::size_t); + +#[repr(C)] +struct hoedown_renderer_data { + opaque: *mut libc::c_void, +} + +#[repr(C)] +struct hoedown_renderer { + opaque: *mut libc::c_void, + + blockcode: Option, + blockquote: Option, + header: Option, + + other_block_level_callbacks: [libc::size_t; 11], + + blockhtml: Option, + + /* span level callbacks - NULL or return 0 prints the span verbatim */ + autolink: libc::size_t, // unused + codespan: Option, + other_span_level_callbacks_1: [libc::size_t; 7], + link: Option, + other_span_level_callbacks_2: [libc::size_t; 6], + + /* low level callbacks - NULL copies input directly into the output */ + entity: Option, + normal_text: Option, + + /* header and footer */ + other_callbacks: [libc::size_t; 2], +} + +#[repr(C)] +struct hoedown_html_renderer_state { + opaque: *mut libc::c_void, + toc_data: html_toc_data, + flags: libc::c_uint, + link_attributes: Option, +} + +#[repr(C)] +struct html_toc_data { + header_count: libc::c_int, + current_level: libc::c_int, + level_offset: libc::c_int, + nesting_level: libc::c_int, +} + +#[repr(C)] +struct hoedown_buffer { + data: *const u8, + size: libc::size_t, + asize: libc::size_t, + unit: libc::size_t, +} + +extern { + fn hoedown_html_renderer_new(render_flags: libc::c_uint, + nesting_level: libc::c_int) + -> *mut hoedown_renderer; + fn hoedown_html_renderer_free(renderer: *mut hoedown_renderer); + + fn hoedown_document_new(rndr: *const hoedown_renderer, + extensions: libc::c_uint, + max_nesting: libc::size_t) -> *mut hoedown_document; + fn hoedown_document_render(doc: *mut hoedown_document, + ob: *mut hoedown_buffer, + document: *const u8, + doc_size: libc::size_t); + fn hoedown_document_free(md: *mut hoedown_document); + + fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; + fn hoedown_buffer_free(b: *mut hoedown_buffer); +} + +impl hoedown_buffer { + fn as_bytes(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.data, self.size as usize) } + } +} + +pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { + extern fn block(_ob: *mut hoedown_buffer, + text: *const hoedown_buffer, + lang: *const hoedown_buffer, + data: *const hoedown_renderer_data, + line: libc::size_t) { + unsafe { + if text.is_null() { return } + let block_info = if lang.is_null() { + LangString::all_false() + } else { + let lang = (*lang).as_bytes(); + let s = str::from_utf8(lang).unwrap(); + LangString::parse(s) + }; + if !block_info.rust { return } + let opaque = (*data).opaque as *mut hoedown_html_renderer_state; + let tests = &mut *((*opaque).opaque as *mut ::test::Collector); + let line = tests.get_line() + line; + let filename = tests.get_filename(); + tests.add_old_test(line, filename); + } + } + + extern fn header(_ob: *mut hoedown_buffer, + text: *const hoedown_buffer, + level: libc::c_int, data: *const hoedown_renderer_data, + _: libc::size_t) { + unsafe { + let opaque = (*data).opaque as *mut hoedown_html_renderer_state; + let tests = &mut *((*opaque).opaque as *mut ::test::Collector); + if text.is_null() { + tests.register_header("", level as u32); + } else { + let text = (*text).as_bytes(); + let text = str::from_utf8(text).unwrap(); + tests.register_header(text, level as u32); + } + } + } + + tests.set_position(position); + + unsafe { + let ob = hoedown_buffer_new(DEF_OUNIT); + let renderer = hoedown_html_renderer_new(0, 0); + (*renderer).blockcode = Some(block); + (*renderer).header = Some(header); + (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque + = tests as *mut _ as *mut libc::c_void; + + let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); + hoedown_document_render(document, ob, doc.as_ptr(), + doc.len() as libc::size_t); + hoedown_document_free(document); + + hoedown_html_renderer_free(renderer); + hoedown_buffer_free(ob); + } +} + pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { tests.set_position(position); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 5fadda030a4b..f75144c23aca 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; use html::markdown; -use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; +use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code}; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -159,6 +159,7 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts, maybe_sysroot, None, Some(input.to_owned())); + old_find_testable_code(&input_str, &mut collector, DUMMY_SP); find_testable_code(&input_str, &mut collector, DUMMY_SP); test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&test_args, collector.tests); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index f6b7a07bdae0..fb681b20065f 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -380,6 +380,8 @@ fn partition_source(s: &str) -> (String, String) { pub struct Collector { pub tests: Vec, + // to be removed when hoedown will be definitely gone + pub old_tests: Vec, names: Vec, cfgs: Vec, libs: SearchPaths, @@ -401,6 +403,7 @@ impl Collector { codemap: Option>, filename: Option) -> Collector { Collector { tests: Vec::new(), + old_tests: Vec::new(), names: Vec::new(), cfgs: cfgs, libs: libs, @@ -417,11 +420,8 @@ impl Collector { } } - pub fn add_test(&mut self, test: String, - should_panic: bool, no_run: bool, should_ignore: bool, - as_test_harness: bool, compile_fail: bool, error_codes: Vec, - line: usize, filename: String) { - let name = if self.use_headers { + fn generate_name(&self, line: usize, filename: &str) -> String { + if self.use_headers { if let Some(ref header) = self.current_header { format!("{} - {} (line {})", filename, header, line) } else { @@ -429,7 +429,27 @@ impl Collector { } } else { format!("{} - {} (line {})", filename, self.names.join("::"), line) - }; + } + } + + pub fn add_old_test(&mut self, line: usize, filename: String) { + let name = self.generate_name(line, &filename); + self.old_tests.push(name); + } + + pub fn add_test(&mut self, test: String, + should_panic: bool, no_run: bool, should_ignore: bool, + as_test_harness: bool, compile_fail: bool, error_codes: Vec, + line: usize, filename: String) { + let name = self.generate_name(line, &filename); + if self.old_tests.iter().find(|&x| x == &name).is_none() { + let _ = writeln!(&mut io::stderr(), + "WARNING: {} Code block is not currently run as a test, but will in \ + future versions of rustdoc. Please ensure this code block is a \ + runnable test, or use the `ignore` directive.", + name); + return + } let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); let externs = self.externs.clone(); @@ -544,6 +564,8 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { attrs.unindent_doc_comments(); if let Some(doc) = attrs.doc_value() { self.collector.cnt = 0; + markdown::old_find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP)); markdown::find_testable_code(doc, self.collector, attrs.span.unwrap_or(DUMMY_SP)); } diff --git a/src/rt/hoedown b/src/rt/hoedown new file mode 160000 index 000000000000..da282f1bb727 --- /dev/null +++ b/src/rt/hoedown @@ -0,0 +1 @@ +Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 From 695354af9c76a88da07190299c95d9c867a51cfd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Apr 2017 13:03:48 +0200 Subject: [PATCH 548/905] Remove hoedown from tidy check --- src/tools/tidy/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 17f8b62117ad..44063e627a36 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -86,6 +86,7 @@ fn filter_dirs(path: &Path) -> bool { "src/rust-installer", "src/liblibc", "src/vendor", + "src/rt/hoedown", ]; skip.iter().any(|p| path.ends_with(p)) } From bee02913207ec24913ca4eeb007b402146ed1532 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Apr 2017 17:17:06 +0200 Subject: [PATCH 549/905] Add hoedown COPYRIGHT back --- COPYRIGHT | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/COPYRIGHT b/COPYRIGHT index 19559fa2950e..abe899803087 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -197,6 +197,28 @@ their own copyright notices and license terms: USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* Hoedown, the markdown parser, under src/rt/hoedown, is + licensed as follows. + + Copyright (c) 2008, Natacha PortΓ© + Copyright (c) 2011, Vicent MartΓ­ + Copyright (c) 2013, Devin Torres and the Hoedown authors + + Permission to use, copy, modify, and distribute this + software for any purpose with or without fee is hereby + granted, provided that the above copyright notice and + this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR + DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA + OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * libbacktrace, under src/libbacktrace: Copyright (C) 2012-2014 Free Software Foundation, Inc. From 1528cbefdb2c0c9fff37174d337c63617d6cb9fd Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Mon, 17 Apr 2017 17:49:35 +0100 Subject: [PATCH 550/905] Remove non-breaking spaces --- src/etc/natvis/libcollections.natvis | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/etc/natvis/libcollections.natvis b/src/etc/natvis/libcollections.natvis index 821c52361f86..e7e93be98695 100644 --- a/src/etc/natvis/libcollections.natvis +++ b/src/etc/natvis/libcollections.natvis @@ -1,16 +1,16 @@ -Β Β Β Β {{ size={len} }} -Β Β Β Β  + {{ size={len} }} + len buf.cap len buf.ptr.pointer.__0 -Β Β Β Β  -Β Β  + +
    {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} From d648c10e5bc313af758951c1e6f8ae4782712627 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 13 Apr 2017 22:37:05 +0300 Subject: [PATCH 551/905] libsyntax/parse: improve associated item error reporting Fixes #41161. Fixes #41239. --- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/parse/parser.rs | 167 +++++++++++-------- src/test/parse-fail/issue-21153.rs | 5 +- src/test/parse-fail/trait-pub-assoc-const.rs | 2 +- src/test/parse-fail/trait-pub-assoc-ty.rs | 2 +- src/test/parse-fail/trait-pub-method.rs | 2 +- src/test/ui/did_you_mean/issue-40006.rs | 12 ++ src/test/ui/did_you_mean/issue-40006.stderr | 68 +++++++- src/test/ui/token/issue-41155.stderr | 10 +- 9 files changed, 191 insertions(+), 81 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1b3352f73ade..20a858b80df4 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -617,14 +617,14 @@ impl<'a> Parser<'a> { ExpansionKind::TraitItems => { let mut items = SmallVector::new(); while self.token != token::Eof { - items.push(self.parse_trait_item()?); + items.push(self.parse_trait_item(&mut false)?); } Expansion::TraitItems(items) } ExpansionKind::ImplItems => { let mut items = SmallVector::new(); while self.token != token::Eof { - items.push(self.parse_impl_item()?); + items.push(self.parse_impl_item(&mut false)?); } Expansion::ImplItems(items) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 58be43526fd9..dfb82d40d568 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -85,12 +85,18 @@ pub enum PathStyle { Expr, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum SemiColonMode { Break, Ignore, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BlockMode { + Break, + Ignore, +} + /// Possibly accept an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of /// macro expansion). Placement of these is not as complex as I feared it would @@ -1204,7 +1210,7 @@ impl<'a> Parser<'a> { } /// Parse the items in a trait declaration - pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { + pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; let lo = self.span; @@ -1214,7 +1220,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; (ident, TraitItemKind::Type(bounds, default)) } else if self.is_const_item() { - self.expect_keyword(keywords::Const)?; + self.expect_keyword(keywords::Const)?; let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -1231,9 +1237,17 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { // trait item macro. // code copied from parse_macro_use_or_failure... abstraction! + let prev_span = self.prev_span; let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + + if pth.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err("trait", prev_span)); + } + } else { + self.expect(&token::Not)?; + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; @@ -1246,25 +1260,7 @@ impl<'a> Parser<'a> { } else { let (constness, unsafety, abi) = match self.parse_fn_front_matter() { Ok(cua) => cua, - Err(e) => { - loop { - match self.token { - token::Eof => break, - token::CloseDelim(token::Brace) | - token::Semi => { - self.bump(); - break; - } - token::OpenDelim(token::Brace) => { - self.parse_token_tree(); - break; - } - _ => self.bump(), - } - } - - return Err(e); - } + Err(e) => return Err(e), }; let ident = self.parse_ident()?; @@ -1289,11 +1285,13 @@ impl<'a> Parser<'a> { let body = match self.token { token::Semi => { self.bump(); + *at_end = true; debug!("parse_trait_methods(): parsing required method"); None } token::OpenDelim(token::Brace) => { debug!("parse_trait_methods(): parsing provided method"); + *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(inner_attrs.iter().cloned()); Some(body) @@ -1315,18 +1313,6 @@ impl<'a> Parser<'a> { }) } - - /// Parse the items in a trait declaration - pub fn parse_trait_items(&mut self) -> PResult<'a, Vec> { - self.parse_unspanned_seq( - &token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::none(), - |p| -> PResult<'a, TraitItem> { - p.parse_trait_item() - }) - } - /// Parse optional return type [ -> TY ] in function decl pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { @@ -3641,22 +3627,33 @@ impl<'a> Parser<'a> { // // We terminate when we find an unmatched `}` (without consuming it). fn recover_stmt(&mut self) { - self.recover_stmt_(SemiColonMode::Ignore) + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) } + // If `break_on_semi` is `Break`, then we will stop consuming tokens after // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is // approximate - it can mean we break too early due to macros, but that // shoud only lead to sub-optimal recovery, not inaccurate parsing). - fn recover_stmt_(&mut self, break_on_semi: SemiColonMode) { + // + // If `break_on_block` is `Break`, then we will stop consuming tokens + // after finding (and consuming) a brace-delimited block. + fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { let mut brace_depth = 0; let mut bracket_depth = 0; - debug!("recover_stmt_ enter loop"); + let mut in_block = false; + debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", + break_on_semi, break_on_block); loop { debug!("recover_stmt_ loop {:?}", self.token); match self.token { token::OpenDelim(token::DelimToken::Brace) => { brace_depth += 1; self.bump(); + if break_on_block == BlockMode::Break && + brace_depth == 1 && + bracket_depth == 0 { + in_block = true; + } } token::OpenDelim(token::DelimToken::Bracket) => { bracket_depth += 1; @@ -3669,6 +3666,10 @@ impl<'a> Parser<'a> { } brace_depth -= 1; self.bump(); + if in_block && bracket_depth == 0 && brace_depth == 0 { + debug!("recover_stmt_ return - block end {:?}", self.token); + return; + } } token::CloseDelim(token::DelimToken::Bracket) => { bracket_depth -= 1; @@ -3700,7 +3701,7 @@ impl<'a> Parser<'a> { fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option { self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| { e.emit(); - self.recover_stmt_(SemiColonMode::Break); + self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None }) } @@ -3974,7 +3975,7 @@ impl<'a> Parser<'a> { e.span_suggestion(stmt_span, "try placing this code inside a block", sugg); } Err(mut e) => { - self.recover_stmt_(SemiColonMode::Break); + self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); self.cancel(&mut e); } _ => () @@ -4663,7 +4664,7 @@ impl<'a> Parser<'a> { } /// Parse an impl item. - pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> { + pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> { maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; @@ -4686,7 +4687,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; (name, ast::ImplItemKind::Const(typ, expr)) } else { - let (name, inner_attrs, node) = self.parse_impl_method(&vis)?; + let (name, inner_attrs, node) = self.parse_impl_method(&vis, at_end)?; attrs.extend(inner_attrs); (name, node) }; @@ -4731,43 +4732,50 @@ impl<'a> Parser<'a> { } } + fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span) + -> DiagnosticBuilder<'a> + { + // Given this code `path(`, it seems like this is not + // setting the visibility of a macro invocation, but rather + // a mistyped method declaration. + // Create a diagnostic pointing out that `fn` is missing. + // + // x | pub path(&self) { + // | ^ missing `fn`, `type`, or `const` + // pub path( + // ^^ `sp` below will point to this + let sp = prev_span.between(self.prev_span); + let mut err = self.diagnostic().struct_span_err( + sp, + &format!("missing `fn`, `type`, or `const` for {}-item declaration", + item_type)); + err.span_label(sp, &"missing `fn`, `type`, or `const`"); + err + } + /// Parse a method or a macro invocation in a trait impl. - fn parse_impl_method(&mut self, vis: &Visibility) + fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool) -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { // Method macro. let prev_span = self.prev_span; - // Before complaining about trying to set a macro as `pub`, - // check if `!` comes after the path. - let err = self.complain_if_pub_macro_diag(&vis, prev_span); let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - let bang_err = self.expect(&token::Not); - if let Err(mut err) = err { - if let Err(mut bang_err) = bang_err { - // Given this code `pub path(`, it seems like this is not setting the - // visibility of a macro invocation, but rather a mistyped method declaration. - // Create a diagnostic pointing out that `fn` is missing. - // - // x | pub path(&self) { - // | ^ missing `fn` for method declaration - - err.cancel(); - bang_err.cancel(); - // pub path( - // ^^ `sp` below will point to this - let sp = prev_span.between(self.prev_span); - err = self.diagnostic() - .struct_span_err(sp, "missing `fn` for method declaration"); - err.span_label(sp, &"missing `fn`"); + if pth.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err("impl", prev_span)); } - return Err(err); + } else { + self.expect(&token::Not)?; } + self.complain_if_pub_macro(&vis, prev_span); + // eat a matched-delimiter token tree: + *at_end = true; let (delim, tts) = self.expect_delimited_token_tree()?; if delim != token::Brace { self.expect(&token::Semi)? @@ -4781,6 +4789,7 @@ impl<'a> Parser<'a> { let mut generics = self.parse_generics()?; let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; + *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig { generics: generics, @@ -4806,8 +4815,21 @@ impl<'a> Parser<'a> { tps.where_clause = self.parse_where_clause()?; - let meths = self.parse_trait_items()?; - Ok((ident, ItemKind::Trait(unsafety, tps, bounds, meths), None)) + self.expect(&token::OpenDelim(token::Brace))?; + let mut trait_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + let mut at_end = false; + match self.parse_trait_item(&mut at_end) { + Ok(item) => trait_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } + } + Ok((ident, ItemKind::Trait(unsafety, tps, bounds, trait_items), None)) } /// Parses items implementations variants @@ -4882,7 +4904,16 @@ impl<'a> Parser<'a> { let mut impl_items = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { - impl_items.push(self.parse_impl_item()?); + let mut at_end = false; + match self.parse_impl_item(&mut at_end) { + Ok(item) => impl_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } } Ok((keywords::Invalid.ident(), diff --git a/src/test/parse-fail/issue-21153.rs b/src/test/parse-fail/issue-21153.rs index c03e0ef73217..b6d95ffb911c 100644 --- a/src/test/parse-fail/issue-21153.rs +++ b/src/test/parse-fail/issue-21153.rs @@ -10,7 +10,6 @@ // compile-flags: -Z parse-only -trait MyTrait: Iterator { - Item = T; //~ ERROR expected one of `!` or `::`, found `=` - //~| ERROR expected item, found `=` +trait MyTrait: Iterator { //~ ERROR missing `fn`, `type`, or `const` + Item = T; } diff --git a/src/test/parse-fail/trait-pub-assoc-const.rs b/src/test/parse-fail/trait-pub-assoc-const.rs index adce0d7bbf4b..6bc24e2081d1 100644 --- a/src/test/parse-fail/trait-pub-assoc-const.rs +++ b/src/test/parse-fail/trait-pub-assoc-const.rs @@ -10,7 +10,7 @@ trait Foo { pub const Foo: u32; - //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub` + //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` } fn main() {} diff --git a/src/test/parse-fail/trait-pub-assoc-ty.rs b/src/test/parse-fail/trait-pub-assoc-ty.rs index dab6c433aba4..493ff087eaf9 100644 --- a/src/test/parse-fail/trait-pub-assoc-ty.rs +++ b/src/test/parse-fail/trait-pub-assoc-ty.rs @@ -10,7 +10,7 @@ trait Foo { pub type Foo; - //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub` + //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` } fn main() {} diff --git a/src/test/parse-fail/trait-pub-method.rs b/src/test/parse-fail/trait-pub-method.rs index 7cb9363830c4..c2ee3c31d885 100644 --- a/src/test/parse-fail/trait-pub-method.rs +++ b/src/test/parse-fail/trait-pub-method.rs @@ -10,7 +10,7 @@ trait Foo { pub fn foo(); - //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub` + //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` } fn main() {} diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs index cf75929bae20..d68c25faa8a8 100644 --- a/src/test/ui/did_you_mean/issue-40006.rs +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -8,8 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +impl X { + Y +} + struct S; +trait X { + X() {} + fn xxx() { ### } + L = M; + Z = { 2 + 3 }; + ::Y (); +} + impl S { pub hello_method(&self) { println!("Hello"); diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 460958027ad0..29ff0cee3af5 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,8 +1,68 @@ -error: missing `fn` for method declaration - --> $DIR/issue-40006.rs:14:8 +error: missing `fn`, `type`, or `const` for impl-item declaration + --> $DIR/issue-40006.rs:11:9 | -14 | pub hello_method(&self) { - | ^ missing `fn` +11 | impl X { + | _________^ starting here... +12 | | Y + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: missing `fn`, `type`, or `const` for trait-item declaration + --> $DIR/issue-40006.rs:17:10 + | +17 | trait X { + | __________^ starting here... +18 | | X() {} + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: expected `[`, found `#` + --> $DIR/issue-40006.rs:19:17 + | +19 | fn xxx() { ### } + | ^ + +error: missing `fn`, `type`, or `const` for trait-item declaration + --> $DIR/issue-40006.rs:19:21 + | +19 | fn xxx() { ### } + | _____________________^ starting here... +20 | | L = M; + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: missing `fn`, `type`, or `const` for trait-item declaration + --> $DIR/issue-40006.rs:20:11 + | +20 | L = M; + | ___________^ starting here... +21 | | Z = { 2 + 3 }; + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` + --> $DIR/issue-40006.rs:21:18 + | +21 | Z = { 2 + 3 }; + | ^ expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}` here + +error: expected one of `!` or `::`, found `(` + --> $DIR/issue-40006.rs:22:9 + | +22 | ::Y (); + | -^ unexpected token + | | + | expected one of `!` or `::` here + +error: missing `fn`, `type`, or `const` for impl-item declaration + --> $DIR/issue-40006.rs:26:8 + | +26 | pub hello_method(&self) { + | ^ missing `fn`, `type`, or `const` + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-40006.rs:11:6 + | +11 | impl X { + | ^ the trait `X` cannot be made into an object + | + = note: method `xxx` has no receiver error: aborting due to previous error diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr index 0da3abd4eaf9..a6ad1206b14d 100644 --- a/src/test/ui/token/issue-41155.stderr +++ b/src/test/ui/token/issue-41155.stderr @@ -6,5 +6,13 @@ error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsa 13 | } | ^ unexpected token -error: aborting due to previous error +error[E0412]: cannot find type `S` in this scope + --> $DIR/issue-41155.rs:11:6 + | +11 | impl S { + | ^ not found in this scope + +error: main function not found + +error: aborting due to 3 previous errors From 51ca5fe716c48b2dd4adbe4e2379d952b60afca8 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 17 Apr 2017 22:37:27 +0200 Subject: [PATCH 552/905] Restructure and redistribute std::path's module docs Part of #29368. * Added a new summary paragraph about std::path's parsing facilities * Slightly exanded `Component`'s docs * removed the now redundant section on component types from the module docs * moved the section on path normalization during parsing to the docs on `Path::components` * Clarified difference between `Prefix` and `PrefixComponent` in their respecive summary sentences --- src/libstd/path.rs | 119 +++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 64 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 77f0d9d95f29..9c8eeb0c5216 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -10,11 +10,18 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] +//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] //! and [`str`]), for working with paths abstractly. These types are thin wrappers //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. //! +//! Paths can be parsed into [`Component`]s by iterating over the structure +//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly +//! correspond to the substrings between path separators (`/` or `\`). You can +//! reconstruct an equivalent path from components with the [`push`] method on +//! [`PathBuf`]; note that the paths may differ syntactically by the +//! normalization described in the documentation for the [`components`] method. +//! //! ## Simple usage //! //! Path manipulation includes both parsing components from slices and building @@ -50,62 +57,11 @@ //! path.set_extension("dll"); //! ``` //! -//! ## Path components and normalization -//! -//! The path APIs are built around the notion of "components", which roughly -//! correspond to the substrings between path separators (`/` and, on Windows, -//! `\`). The APIs for path parsing are largely specified in terms of the path's -//! components, so it's important to clearly understand how those are -//! determined. -//! -//! A path can always be reconstructed into an *equivalent* path by -//! putting together its components via `push`. Syntactically, the -//! paths may differ by the normalization described below. -//! -//! ### Component types -//! -//! Components come in several types: -//! -//! * Normal components are the default: standard references to files or -//! directories. The path `a/b` has two normal components, `a` and `b`. -//! -//! * Current directory components represent the `.` character. For example, -//! `./a` has a current directory component and a normal component `a`. -//! -//! * The root directory component represents a separator that designates -//! starting from root. For example, `/a/b` has a root directory component -//! followed by normal components `a` and `b`. -//! -//! On Windows, an additional component type comes into play: -//! -//! * Prefix components, of which there is a large variety. For example, `C:` -//! and `\\server\share` are prefixes. The path `C:windows` has a prefix -//! component `C:` and a normal component `windows`; the path `C:\windows` has a -//! prefix component `C:`, a root directory component, and a normal component -//! `windows`. -//! -//! ### Normalization -//! -//! Aside from splitting on the separator(s), there is a small amount of -//! "normalization": -//! -//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a` -//! and `b`. -//! -//! * Occurrences of `.` are normalized away, *except* if they are at -//! the beginning of the path (in which case they are often meaningful -//! in terms of path searching). So, for example, `a/./b`, `a/b/`, -//! `/a/b/.` and `a/b` all have components `a` and `b`, but `./a/b` -//! has a leading current directory component. -//! -//! No other normalization takes place by default. In particular, -//! `a/c` and `a/b/../c` are distinct, to account for the possibility -//! that `b` is a symbolic link (so its parent isn't `a`). Further -//! normalization is possible to build on top of the components APIs, -//! and will be included in this library in the near future. -//! +//! [`Component`]: ../../std/path/enum.Component.html +//! [`components`]: ../../std/path/struct.Path.html#method.components //! [`PathBuf`]: ../../std/path/struct.PathBuf.html //! [`Path`]: ../../std/path/struct.Path.html +//! [`push`]: ../../std/path/struct.PathBuf.html#method.push //! [`String`]: ../../std/string/struct.String.html //! [`str`]: ../../std/primitive.str.html //! [`OsString`]: ../../std/ffi/struct.OsString.html @@ -143,7 +99,7 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// -/// Path prefixes (Windows only). +/// Windows path prefixes, e.g. `C:` or `\\server\share`. /// /// Windows uses a variety of path prefix styles, including references to drive /// volumes (like `C:`), network shared folders (like `\\server\share`), and @@ -415,7 +371,8 @@ enum State { Done = 3, } -/// A Windows path prefix, e.g. `C:` or `\\server\share`. +/// A structure wrapping a Windows path prefix as well as its unparsed string +/// representation. /// /// In addition to the parsed [`Prefix`] information returned by [`kind`], /// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, @@ -511,11 +468,11 @@ impl<'a> Hash for PrefixComponent<'a> { /// A single component of a path. /// -/// See the module documentation for an in-depth explanation of components and -/// their role in the API. +/// A `Component` roughtly corresponds to a substring between path separators +/// (`/` or `\`). /// -/// This `enum` is created from iterating over the [`path::Components`] -/// `struct`. +/// This `enum` is created by iterating over [`Components`], which in turn is +/// created by the [`components`][`Path::components`] method on [`Path`]. /// /// # Examples /// @@ -532,19 +489,28 @@ impl<'a> Hash for PrefixComponent<'a> { /// ]); /// ``` /// -/// [`path::Components`]: struct.Components.html +/// [`Components`]: struct.Components.html +/// [`Path`]: struct.Path.html +/// [`Path::components`]: struct.Path.html#method.components #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Component<'a> { /// A Windows path prefix, e.g. `C:` or `\\server\share`. /// + /// There is a large variety of prefix types, see [`Prefix`]'s documentation + /// for more. + /// /// Does not occur on Unix. + /// + /// [`Prefix`]: enum.Prefix.html #[stable(feature = "rust1", since = "1.0.0")] Prefix( #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a> ), /// The root directory component, appears after any prefix and before anything else. + /// + /// It represents a deperator that designates that a path starts from root. #[stable(feature = "rust1", since = "1.0.0")] RootDir, @@ -557,6 +523,9 @@ pub enum Component<'a> { ParentDir, /// A normal component, e.g. `a` and `b` in `a/b`. + /// + /// This variant is the most common one, it represents references to files + /// or directories. #[stable(feature = "rust1", since = "1.0.0")] Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), } @@ -1992,7 +1961,21 @@ impl Path { buf } - /// Produces an iterator over the components of the path. + /// Produces an iterator over the [`Component`]s of the path. + /// + /// When parsing the path, there is a small amount of normalization: + /// + /// * Repeated seperators are ignored, so `a/b` and `a//b` both have + /// `a` and `b` as components. + /// + /// * Occurentces of `.` are normalized away, exept if they are at the + /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and + /// `a/b` all have `a` and `b` as components, but `./a/b` starts with + /// an additional [`CurDir`] component. + /// + /// Note that no other normalization takes place; in particular, `a/c` + /// and `a/b/../c` are distinct, to account for the possibility that `b` + /// is a symbolic link (so its parent isn't `a`). /// /// # Examples /// @@ -2007,6 +1990,9 @@ impl Path { /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); /// assert_eq!(components.next(), None) /// ``` + /// + /// [`Component`]: enum.Component.html + /// [`CurDir`]: enum.Component.html#variant.CurDir #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); @@ -2019,8 +2005,13 @@ impl Path { } } - /// Produces an iterator over the path's components viewed as [`OsStr`] slices. + /// Produces an iterator over the path's components viewed as [`OsStr`] + /// slices. /// + /// For more information about the particulars of how the path is separated + /// into components, see [`components`]. + /// + /// [`components`]: #method.components /// [`OsStr`]: ../ffi/struct.OsStr.html /// /// # Examples From 32132d9fb66d95ab3bfbc5eff969a1e084310705 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 17 Apr 2017 22:51:12 +0200 Subject: [PATCH 553/905] Expand std::path::Display's docs Part of #29368. * Added explanation for why the struct exists * Added link to where it is created * Added example --- src/libstd/path.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9c8eeb0c5216..ce13b57f0a28 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2236,7 +2236,26 @@ impl fmt::Debug for Path { } } -/// Helper struct for safely printing paths with `format!()` and `{}` +/// Helper struct for safely printing paths with [`format!`] and `{}`. +/// +/// A [`Path`] might contain non-Unicode data. This `struct` implements the +/// [`Display`] trait in a way that mitigates that. It is created by the +/// [`display`][`Path::display`] method on [`Path`]. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo.rs"); +/// +/// println!("{}", path.display()); +/// ``` +/// +/// [`Display`]: ../../std/fmt/trait.Display.html +/// [`format!`]: ../../std/macro.format.html +/// [`Path`]: struct.Path.html +/// [`Path::display`]: struct.Path.html#method.display #[stable(feature = "rust1", since = "1.0.0")] pub struct Display<'a> { path: &'a Path, From 2877a01febe7a0667051463ed1bb431fe17c4d18 Mon Sep 17 00:00:00 2001 From: Dylan Maccora Date: Tue, 18 Apr 2017 08:29:05 +1000 Subject: [PATCH 554/905] Address review comments --- src/libcore/convert.rs | 43 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index abab4bb0f63b..084736685e3a 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -35,7 +35,7 @@ //! - [`From`]` for T` implies [`Into`]` for U` //! - [`TryFrom`]` for T` implies [`TryInto`]` for U` //! - [`From`] and [`Into`] are reflexive, which means that all types can -//! `into()` themselves and `from()` themselves +//! `into` themselves and `from` themselves //! //! See each trait for usage examples. //! @@ -59,14 +59,15 @@ use str::FromStr; /// `AsRef` is to be used when wishing to convert to a reference of another /// type. /// `Borrow` is more related to the notion of taking the reference. It is -/// useful when wishing to abstract -/// over the type of reference (`&T`, `&mut T`) or allow both the referenced -/// and owned type to be treated in the same manner. +/// useful when wishing to abstract over the type of reference +/// (`&T`, `&mut T`) or allow both the referenced and owned type to be treated +/// in the same manner. +/// /// 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 +/// type of borrow and if is reference or value /// /// See [the book][book] for a more detailed comparison. /// @@ -82,8 +83,8 @@ use str::FromStr; /// # Generic Implementations /// /// - `AsRef` 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`) +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) /// /// # Examples /// @@ -124,8 +125,8 @@ 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`) +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) /// /// # Examples /// @@ -203,9 +204,11 @@ pub trait Into: Sized { /// /// When constructing a function that is capable of failing the return type /// will generally be of the form `Result`. +/// /// The `From` trait allows for simplification of error handling by providing a /// means of returning a single error type that encapsulates numerous possible /// erroneous situations. +/// /// This trait is not limited to error handling, rather the general case for /// this trait would be in any type conversions to have an explicit definition /// of how they are performed. @@ -310,8 +313,7 @@ pub trait TryFrom: Sized { // As lifts over & #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T - where T: AsRef +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { fn as_ref(&self) -> &U { >::as_ref(*self) @@ -320,8 +322,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T // As lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T - where T: AsRef +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { fn as_ref(&self) -> &U { >::as_ref(*self) @@ -338,8 +339,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T // AsMut lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T - where T: AsMut +impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { fn as_mut(&mut self) -> &mut U { (*self).as_mut() @@ -356,8 +356,7 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T // From implies Into #[stable(feature = "rust1", since = "1.0.0")] -impl Into for T - where U: From +impl Into for T where U: From { fn into(self) -> U { U::from(self) @@ -367,16 +366,13 @@ impl Into for T // From (and thus Into) is reflexive #[stable(feature = "rust1", since = "1.0.0")] impl From for T { - fn from(t: T) -> T { - t - } + fn from(t: T) -> T { t } } // TryFrom implies TryInto #[unstable(feature = "try_from", issue = "33417")] -impl TryInto for T - where U: TryFrom +impl TryInto for T where U: TryFrom { type Error = U::Error; @@ -413,8 +409,7 @@ impl AsRef for str { // FromStr implies TryFrom<&str> #[unstable(feature = "try_from", issue = "33417")] -impl<'a, T> TryFrom<&'a str> for T - where T: FromStr +impl<'a, T> TryFrom<&'a str> for T where T: FromStr { type Error = ::Err; From 32a43da68ae26bc3e22dbaca12ebb02ddc742cc7 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 24 Jan 2017 18:15:11 +0100 Subject: [PATCH 555/905] Add functions to safely transmute float to int --- src/libstd/f32.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/f64.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + 3 files changed, 103 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index dd8318006835..8e7b7ee0923a 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1226,6 +1226,45 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + + /// Raw transmutation to `u32`. + /// + /// Converts the `f32` into its raw memory representation, + /// similar to the `transmute` function. + /// + /// Note that this function is distinct from casting. + /// + /// ``` + /// #![feature(float_bits_conv)] + /// assert!((1f32).to_bits() != 1f32 as u32); // to_bits() is not casting! + /// assert_eq!((12.5f32).to_bits(), 0x41480000); + /// + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[inline] + pub fn to_bits(self) -> u32 { + unsafe { ::mem::transmute(self) } + } + + /// Raw transmutation from `u32`. + /// + /// Converts the given `u32` containing the float's raw memory + /// representation into the `f32` type, similar to the + /// `transmute` function. + /// + /// Note that this function is distinct from casting. + /// + /// ``` + /// #![feature(float_bits_conv)] + /// use std::f32; + /// let difference = (f32::from_bits(0x41480000) - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[inline] + pub fn from_bits(v: u32) -> Self { + unsafe { ::mem::transmute(v) } + } } #[cfg(test)] @@ -1870,4 +1909,16 @@ mod tests { assert_approx_eq!(ln_2, 2f32.ln()); assert_approx_eq!(ln_10, 10f32.ln()); } + + #[test] + fn test_float_bits_conv() { + assert_eq!((1f32).to_bits(), 0x3f800000); + assert_eq!((12.5f32).to_bits(), 0x41480000); + assert_eq!((1337f32).to_bits(), 0x44a72000); + assert_eq!((-14.25f32).to_bits(), 0xc1640000); + assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 2f02e01935a4..f9a5a2705ae4 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1118,6 +1118,45 @@ impl f64 { } } } + + /// Raw transmutation to `u64`. + /// + /// Converts the `f64` into its raw memory representation, + /// similar to the `transmute` function. + /// + /// Note that this function is distinct from casting. + /// + /// ``` + /// #![feature(float_bits_conv)] + /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! + /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + /// + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[inline] + pub fn to_bits(self) -> u64 { + unsafe { ::mem::transmute(self) } + } + + /// Raw transmutation from `u64`. + /// + /// Converts the given `u64` containing the float's raw memory + /// representation into the `f64` type, similar to the + /// `transmute` function. + /// + /// Note that this function is distinct from casting. + /// + /// ``` + /// #![feature(float_bits_conv)] + /// use std::f64; + /// let difference = (f64::from_bits(0x4029000000000000) - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[inline] + pub fn from_bits(v: u64) -> Self { + unsafe { ::mem::transmute(v) } + } } #[cfg(test)] @@ -1755,4 +1794,16 @@ mod tests { assert_approx_eq!(ln_2, 2f64.ln()); assert_approx_eq!(ln_10, 10f64.ln()); } + + #[test] + fn test_float_bits_conv() { + assert_eq!((1f64).to_bits(), 0x3ff0000000000000); + assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + assert_eq!((1337f64).to_bits(), 0x4094e40000000000); + assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4f6d170560c1..8de6e1a24f1f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -321,6 +321,7 @@ #![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(stage0, feature(pub_restricted))] +#![cfg_attr(test, feature(float_bits_conv))] // Explicitly import the prelude. The compiler uses this same unstable attribute // to import the prelude implicitly when building crates that depend on std. From 82eead0d0b687c79cc79029e45325aecd9c9ef73 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 24 Jan 2017 20:49:33 +0100 Subject: [PATCH 556/905] Return Err(()) when trying to convert sNaN representation to float --- src/libstd/f32.rs | 24 +++++++++++++++++------- src/libstd/f64.rs | 24 +++++++++++++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8e7b7ee0923a..ec0547662ccc 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1254,16 +1254,26 @@ impl f32 { /// /// Note that this function is distinct from casting. /// + /// Returns `Err(())` if the representation of a signaling NaN "sNaN" + /// float, is passed to the function. + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f32; - /// let difference = (f32::from_bits(0x41480000) - 12.5).abs(); + /// let v = f32::from_bits(0x41480000).unwrap(); + /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); + /// // Example for a signaling NaN value: + /// assert_eq!(f32::from_bits(0x7F800001), Err(())); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] #[inline] - pub fn from_bits(v: u32) -> Self { - unsafe { ::mem::transmute(v) } + pub fn from_bits(v: u32) -> Result { + match v { + 0x7F800001 ... 0x7FBFFFFF | + 0xFF800001 ... 0xFFBFFFFF => Err(()), + _ => Ok(unsafe { ::mem::transmute(v) }), + } } } @@ -1916,9 +1926,9 @@ mod tests { assert_eq!((12.5f32).to_bits(), 0x41480000); assert_eq!((1337f32).to_bits(), 0x44a72000); assert_eq!((-14.25f32).to_bits(), 0xc1640000); - assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); - assert_approx_eq!(f32::from_bits(0x41480000), 12.5); - assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); - assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); + assert_approx_eq!(f32::from_bits(0x3f800000).unwrap(), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000).unwrap(), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000).unwrap(), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000).unwrap(), -14.25); } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f9a5a2705ae4..456ea9c14112 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1146,16 +1146,26 @@ impl f64 { /// /// Note that this function is distinct from casting. /// + /// Returns `Err(())` if the representation of a signaling NaN "sNaN" + /// float, is passed to the function. + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f64; - /// let difference = (f64::from_bits(0x4029000000000000) - 12.5).abs(); + /// let v = f64::from_bits(0x4029000000000000).unwrap(); + /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); + /// // Example for a signaling NaN value: + /// assert_eq!(f64::from_bits(0x7FF0000000000001), Err(())); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] #[inline] - pub fn from_bits(v: u64) -> Self { - unsafe { ::mem::transmute(v) } + pub fn from_bits(v: u64) -> Result { + match v { + 0x7FF0000000000001 ... 0x7FF7FFFFFFFFFFFF | + 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => Err(()), + _ => Ok(unsafe { ::mem::transmute(v) }), + } } } @@ -1801,9 +1811,9 @@ mod tests { assert_eq!((12.5f64).to_bits(), 0x4029000000000000); assert_eq!((1337f64).to_bits(), 0x4094e40000000000); assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); - assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); - assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); - assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); - assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000).unwrap(), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000).unwrap(), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000).unwrap(), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000).unwrap(), -14.25); } } From 56760abf3b0202a74fcfb1b62bc53cfbddd8259c Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 24 Jan 2017 21:28:12 +0100 Subject: [PATCH 557/905] Add examples heading --- src/libstd/f32.rs | 4 ++++ src/libstd/f64.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ec0547662ccc..5ec01e2e215c 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1234,6 +1234,8 @@ impl f32 { /// /// Note that this function is distinct from casting. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// assert!((1f32).to_bits() != 1f32 as u32); // to_bits() is not casting! @@ -1257,6 +1259,8 @@ impl f32 { /// Returns `Err(())` if the representation of a signaling NaN "sNaN" /// float, is passed to the function. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f32; diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 456ea9c14112..96d38f67ee21 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1126,6 +1126,8 @@ impl f64 { /// /// Note that this function is distinct from casting. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! @@ -1149,6 +1151,8 @@ impl f64 { /// Returns `Err(())` if the representation of a signaling NaN "sNaN" /// float, is passed to the function. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f64; From bdab5cdc6336793968d790b1512fdfeeed2260e4 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 13 Mar 2017 10:25:50 +0100 Subject: [PATCH 558/905] assert_ne and tracking issue --- src/libstd/f32.rs | 6 +++--- src/libstd/f64.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 5ec01e2e215c..76b629fb1d4c 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1238,11 +1238,11 @@ impl f32 { /// /// ``` /// #![feature(float_bits_conv)] - /// assert!((1f32).to_bits() != 1f32 as u32); // to_bits() is not casting! + /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! /// assert_eq!((12.5f32).to_bits(), 0x41480000); /// /// ``` - #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn to_bits(self) -> u32 { unsafe { ::mem::transmute(self) } @@ -1270,7 +1270,7 @@ impl f32 { /// // Example for a signaling NaN value: /// assert_eq!(f32::from_bits(0x7F800001), Err(())); /// ``` - #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn from_bits(v: u32) -> Result { match v { diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 96d38f67ee21..f553e580f0fa 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1134,7 +1134,7 @@ impl f64 { /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); /// /// ``` - #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn to_bits(self) -> u64 { unsafe { ::mem::transmute(self) } @@ -1162,7 +1162,7 @@ impl f64 { /// // Example for a signaling NaN value: /// assert_eq!(f64::from_bits(0x7FF0000000000001), Err(())); /// ``` - #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn from_bits(v: u64) -> Result { match v { From fc028b81803277f7552355052bb277b10a066249 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 29 Mar 2017 02:39:59 +0200 Subject: [PATCH 559/905] Convert sNaN to quiet NaN instead of returning errors --- src/libstd/f32.rs | 30 ++++++++++++++++++------------ src/libstd/f64.rs | 30 ++++++++++++++++++------------ 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 76b629fb1d4c..40bf7f17c3aa 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1254,29 +1254,35 @@ impl f32 { /// representation into the `f32` type, similar to the /// `transmute` function. /// - /// Note that this function is distinct from casting. + /// There is only one difference to a bare `transmute`: + /// Due to the implications onto Rust's safety promises being + /// uncertain, if the representation of a signaling NaN "sNaN" float + /// is passed to the function, a quiet NaN will be returned + /// instead. /// - /// Returns `Err(())` if the representation of a signaling NaN "sNaN" - /// float, is passed to the function. + /// Note that this function is distinct from casting. /// /// # Examples /// /// ``` /// #![feature(float_bits_conv)] /// use std::f32; - /// let v = f32::from_bits(0x41480000).unwrap(); + /// let v = f32::from_bits(0x41480000); /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); /// // Example for a signaling NaN value: - /// assert_eq!(f32::from_bits(0x7F800001), Err(())); + /// let snan = 0x7F800001; + /// assert_ne!(f32::from_bits(snan).to_bits(), snan); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u32) -> Result { + pub fn from_bits(v: u32) -> Self { match v { + // sNaN limits source: + // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html 0x7F800001 ... 0x7FBFFFFF | - 0xFF800001 ... 0xFFBFFFFF => Err(()), - _ => Ok(unsafe { ::mem::transmute(v) }), + 0xFF800001 ... 0xFFBFFFFF => ::f32::NAN, + _ => unsafe { ::mem::transmute(v) }, } } } @@ -1930,9 +1936,9 @@ mod tests { assert_eq!((12.5f32).to_bits(), 0x41480000); assert_eq!((1337f32).to_bits(), 0x44a72000); assert_eq!((-14.25f32).to_bits(), 0xc1640000); - assert_approx_eq!(f32::from_bits(0x3f800000).unwrap(), 1.0); - assert_approx_eq!(f32::from_bits(0x41480000).unwrap(), 12.5); - assert_approx_eq!(f32::from_bits(0x44a72000).unwrap(), 1337.0); - assert_approx_eq!(f32::from_bits(0xc1640000).unwrap(), -14.25); + assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f553e580f0fa..80bc149b1a40 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1146,29 +1146,35 @@ impl f64 { /// representation into the `f64` type, similar to the /// `transmute` function. /// - /// Note that this function is distinct from casting. + /// There is only one difference to a bare `transmute`: + /// Due to the implications onto Rust's safety promises being + /// uncertain, if the representation of a signaling NaN "sNaN" float + /// is passed to the function, a quiet NaN will be returned + /// instead. /// - /// Returns `Err(())` if the representation of a signaling NaN "sNaN" - /// float, is passed to the function. + /// Note that this function is distinct from casting. /// /// # Examples /// /// ``` /// #![feature(float_bits_conv)] /// use std::f64; - /// let v = f64::from_bits(0x4029000000000000).unwrap(); + /// let v = f64::from_bits(0x4029000000000000); /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); /// // Example for a signaling NaN value: - /// assert_eq!(f64::from_bits(0x7FF0000000000001), Err(())); + /// let snan = 0x7FF0000000000001; + /// assert_ne!(f64::from_bits(snan).to_bits(), snan); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u64) -> Result { + pub fn from_bits(v: u64) -> Self { match v { + // sNaN limits source: + // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html 0x7FF0000000000001 ... 0x7FF7FFFFFFFFFFFF | - 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => Err(()), - _ => Ok(unsafe { ::mem::transmute(v) }), + 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => ::f64::NAN, + _ => unsafe { ::mem::transmute(v) }, } } } @@ -1815,9 +1821,9 @@ mod tests { assert_eq!((12.5f64).to_bits(), 0x4029000000000000); assert_eq!((1337f64).to_bits(), 0x4094e40000000000); assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); - assert_approx_eq!(f64::from_bits(0x3ff0000000000000).unwrap(), 1.0); - assert_approx_eq!(f64::from_bits(0x4029000000000000).unwrap(), 12.5); - assert_approx_eq!(f64::from_bits(0x4094e40000000000).unwrap(), 1337.0); - assert_approx_eq!(f64::from_bits(0xc02c800000000000).unwrap(), -14.25); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); } } From 3993eb4a276079af826c75e233e1a1d2ab93de13 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 30 Mar 2017 01:49:06 +0200 Subject: [PATCH 560/905] Preserve sNaN payload when converting them to quiet NaNs --- src/libstd/f32.rs | 32 +++++++++++++++++++++++++------- src/libstd/f64.rs | 17 ++++++++++------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 40bf7f17c3aa..8759f103dff1 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1276,14 +1276,17 @@ impl f32 { /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u32) -> Self { - match v { - // sNaN limits source: - // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html - 0x7F800001 ... 0x7FBFFFFF | - 0xFF800001 ... 0xFFBFFFFF => ::f32::NAN, - _ => unsafe { ::mem::transmute(v) }, + pub fn from_bits(mut v: u32) -> Self { + const EXP_MASK: u32 = 0x7F800000; + const QNAN_MASK: u32 = 0x00400000; + const FRACT_MASK: u32 = 0x007FFFFF; + if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { + // If we have a NaN value, we + // convert signaling NaN values to quiet NaN + // by setting the the highest bit of the fraction + v |= QNAN_MASK; } + unsafe { ::mem::transmute(v) } } } @@ -1941,4 +1944,19 @@ mod tests { assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); } + #[test] + fn test_snan_masking() { + let snan: u32 = 0x7F801337; + const PAYLOAD_MASK: u32 = 0x003FFFFF; + const QNAN_MASK: u32 = 0x00400000; + let nan_masked_fl = f32::from_bits(snan); + let nan_masked = nan_masked_fl.to_bits(); + // Ensure that signaling NaNs don't stay the same + assert_ne!(nan_masked, snan); + // Ensure that we have a quiet NaN + assert_ne!(nan_masked & QNAN_MASK, 0); + assert!(nan_masked_fl.is_nan()); + // Ensure the payload wasn't touched during conversion + assert_eq!(nan_masked & PAYLOAD_MASK, snan & PAYLOAD_MASK); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 80bc149b1a40..a4645c3a70f9 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1168,14 +1168,17 @@ impl f64 { /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u64) -> Self { - match v { - // sNaN limits source: - // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html - 0x7FF0000000000001 ... 0x7FF7FFFFFFFFFFFF | - 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => ::f64::NAN, - _ => unsafe { ::mem::transmute(v) }, + pub fn from_bits(mut v: u64) -> Self { + const EXP_MASK: u64 = 0x7FF0000000000000; + const QNAN_MASK: u64 = 0x0001000000000000; + const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF; + if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { + // If we have a NaN value, we + // convert signaling NaN values to quiet NaN + // by setting the the highest bit of the fraction + v |= QNAN_MASK; } + unsafe { ::mem::transmute(v) } } } From 873a3b0363fd8f211f720c3b021a4e1c4c11f754 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 31 Mar 2017 00:40:02 +0200 Subject: [PATCH 561/905] Allow us to remove masking in the future --- src/libstd/f32.rs | 4 ++-- src/libstd/f64.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8759f103dff1..316e6841c4fe 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1257,8 +1257,8 @@ impl f32 { /// There is only one difference to a bare `transmute`: /// Due to the implications onto Rust's safety promises being /// uncertain, if the representation of a signaling NaN "sNaN" float - /// is passed to the function, a quiet NaN will be returned - /// instead. + /// is passed to the function, the implementation is allowed to + /// return a quiet NaN instead. /// /// Note that this function is distinct from casting. /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a4645c3a70f9..be55cb80c92f 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1149,8 +1149,8 @@ impl f64 { /// There is only one difference to a bare `transmute`: /// Due to the implications onto Rust's safety promises being /// uncertain, if the representation of a signaling NaN "sNaN" float - /// is passed to the function, a quiet NaN will be returned - /// instead. + /// is passed to the function, the implementation is allowed to + /// return a quiet NaN instead. /// /// Note that this function is distinct from casting. /// From 0c148153f4de0c32206582ed9b51346f9769f10c Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 18 Apr 2017 02:55:47 +0200 Subject: [PATCH 562/905] Add float_bits_conv to unstable book --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/float-bits-conv.md | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/doc/unstable-book/src/float-bits-conv.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 42af79b8bb07..173845047946 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -72,6 +72,7 @@ - [fd](fd.md) - [fd_read](fd-read.md) - [fixed_size_array](fixed-size-array.md) +- [float_bits_conv](float-bits-conv.md) - [float_extras](float-extras.md) - [flt2dec](flt2dec.md) - [fmt_flags_align](fmt-flags-align.md) diff --git a/src/doc/unstable-book/src/float-bits-conv.md b/src/doc/unstable-book/src/float-bits-conv.md new file mode 100644 index 000000000000..f519545ac78b --- /dev/null +++ b/src/doc/unstable-book/src/float-bits-conv.md @@ -0,0 +1,7 @@ +# `float_bits_conv` + +The tracking issue for this feature is: [#40470] + +[#40470]: https://github.com/rust-lang/rust/issues/40470 + +------------------------ From e3ad1b58f560ba0557d21c1aceb25da3442ba3f6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 17 Apr 2017 17:17:11 -0700 Subject: [PATCH 563/905] Disable debuginfo when compiling tools Currently the Cargo binary has jumped from 14M to 34M on the beta channel, which appears to be due to the fact that we're compiling tools with debug information inside them. This additionally means that the `rls` binary is 62M right now! This wasn't an intentional change, so be sure to disable debuginfo when compiling tools as it's just intended for the standard library and compile for now. --- src/bootstrap/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d711b63ea2e2..5e046f41673e 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -464,8 +464,6 @@ impl Build { .env("RUSTC", self.out.join("bootstrap/debug/rustc")) .env("RUSTC_REAL", self.compiler_path(compiler)) .env("RUSTC_STAGE", stage.to_string()) - .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) - .env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()) .env("RUSTC_CODEGEN_UNITS", self.config.rust_codegen_units.to_string()) .env("RUSTC_DEBUG_ASSERTIONS", @@ -477,6 +475,13 @@ impl Build { .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + // Tools don't get debuginfo right now, e.g. cargo and rls don't get + // compiled with debuginfo. + if mode != Mode::Tool { + cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) + .env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()); + } + // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); self.add_rust_test_threads(&mut cargo); From 1dbc72b28e4ed4a530801f2689ed8ffb56f4fc21 Mon Sep 17 00:00:00 2001 From: Richo Healey Date: Mon, 17 Apr 2017 19:30:18 -0700 Subject: [PATCH 564/905] bootstrap: Don't workaround uname -m on Darwin This no longer manifests on any versions of OSX that I could find. --- src/bootstrap/bootstrap.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 2e33b4511949..3233a73b007c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -404,14 +404,6 @@ class RustBuild(object): raise Exception(err) sys.exit(err) - # Darwin's `uname -s` lies and always returns i386. We have to use - # sysctl instead. - if ostype == 'Darwin' and cputype == 'i686': - args = ['sysctl', 'hw.optional.x86_64'] - sysctl = subprocess.check_output(args).decode(default_encoding) - if ': 1' in sysctl: - cputype = 'x86_64' - # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. if ostype == 'Linux': From 810e0151afe652ab4c8310543f9bcd5463eb8d2f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 18 Apr 2017 05:57:39 -0400 Subject: [PATCH 565/905] convert calls to `visit_all_item_likes_in_krate` We no longer need to track the tasks in these cases since these particular tasks have no outputs (except, potentially, errors...) and they always execute. --- src/librustc/dep_graph/dep_node.rs | 20 --------- src/librustc/middle/intrinsicck.rs | 3 +- src/librustc/middle/stability.rs | 2 +- src/librustc_const_eval/check_match.rs | 5 +-- src/librustc_mir/mir_map.rs | 2 +- src/librustc_passes/consts.rs | 18 ++++---- src/librustc_typeck/check/mod.rs | 6 +-- src/librustc_typeck/coherence/orphan.rs | 3 +- src/librustc_typeck/coherence/overlap.rs | 2 +- src/librustc_typeck/collect.rs | 53 ++---------------------- src/librustc_typeck/impl_wf_check.rs | 3 +- 11 files changed, 21 insertions(+), 96 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 59d04ea8c771..dfec80aafcd6 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -61,8 +61,6 @@ pub enum DepNode { RegionResolveCrate, PluginRegistrar, StabilityIndex, - CollectItem(D), - CollectItemSig(D), Coherence, Resolve, EntryPoint, @@ -71,15 +69,9 @@ pub enum DepNode { CoherenceCheckImpl(D), CoherenceOverlapCheck(D), CoherenceOverlapCheckSpecial(D), - CoherenceOrphanCheck(D), Variance, - WfCheck(D), - TypeckItemType(D), UnusedTraitCheck, - CheckConst(D), PrivacyAccessLevels(CrateNum), - IntrinsicCheck(D), - MatchCheck(D), // Represents the MIR for a fn; also used as the task node for // things read/modify that MIR. @@ -92,7 +84,6 @@ pub enum DepNode { RvalueCheck(D), Reachability, DeadCheck, - StabilityCheck(D), LateLintCheck, TransCrate, TransCrateItem(D), @@ -184,12 +175,10 @@ impl DepNode { } check! { - CollectItem, BorrowCheck, Hir, HirBody, TransCrateItem, - TypeckItemType, AssociatedItems, ItemSignature, AssociatedItemDefIds, @@ -237,18 +226,10 @@ impl DepNode { Hir(ref d) => op(d).map(Hir), HirBody(ref d) => op(d).map(HirBody), MetaData(ref d) => op(d).map(MetaData), - CollectItem(ref d) => op(d).map(CollectItem), - CollectItemSig(ref d) => op(d).map(CollectItemSig), CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait), CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial), - CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck), - WfCheck(ref d) => op(d).map(WfCheck), - TypeckItemType(ref d) => op(d).map(TypeckItemType), - CheckConst(ref d) => op(d).map(CheckConst), - IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck), - MatchCheck(ref d) => op(d).map(MatchCheck), Mir(ref d) => op(d).map(Mir), MirShim(ref def_ids) => { let def_ids: Option> = def_ids.iter().map(op).collect(); @@ -256,7 +237,6 @@ impl DepNode { } BorrowCheck(ref d) => op(d).map(BorrowCheck), RvalueCheck(ref d) => op(d).map(RvalueCheck), - StabilityCheck(ref d) => op(d).map(StabilityCheck), TransCrateItem(ref d) => op(d).map(TransCrateItem), TransInlinedItem(ref d) => op(d).map(TransInlinedItem), AssociatedItems(ref d) => op(d).map(AssociatedItems), diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 942f8475eced..ecc0bb9fe497 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::DepNode; use hir::def::Def; use hir::def_id::DefId; use infer::InferCtxt; @@ -25,7 +24,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = ItemVisitor { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::IntrinsicCheck, &mut visitor.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct ItemVisitor<'a, 'tcx: 'a> { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 2b5ea61d4e85..f618386c610b 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -424,7 +424,7 @@ impl<'a, 'tcx> Index<'tcx> { /// features and possibly prints errors. pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut checker = Checker { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::StabilityCheck, &mut checker.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut checker.as_deep_visitor()); } struct Checker<'a, 'tcx: 'a> { diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index f1ab6a00aa2e..2e0afe789c62 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -14,8 +14,6 @@ use _match::WitnessPreference::*; use pattern::{Pattern, PatternContext, PatternError, PatternKind}; -use rustc::dep_graph::DepNode; - use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor as euv; @@ -56,8 +54,7 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::MatchCheck, - &mut OuterVisitor { tcx: tcx }.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut OuterVisitor { tcx: tcx }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 8c138d779c10..9dfe1a34c9ce 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -68,7 +68,7 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { NestedVisitorMap::None } } - tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut GatherCtors { + tcx.hir.krate().visit_all_item_likes(&mut GatherCtors { tcx: tcx }.as_deep_visitor()); } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 44d3026d80c3..2c4439f80a23 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -24,7 +24,6 @@ // - It's not possible to take the address of a static item with unsafe interior. This is enforced // by borrowck::gather_loans -use rustc::dep_graph::DepNode; use rustc::ty::cast::CastKind; use rustc_const_eval::ConstContext; use rustc::middle::const_val::ConstEvalErr; @@ -459,15 +458,14 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::CheckConst, - &mut CheckCrateVisitor { - tcx: tcx, - tables: &ty::TypeckTables::empty(), - in_fn: false, - promotable: false, - mut_rvalue_borrows: NodeSet(), - param_env: tcx.empty_parameter_environment(), - }.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut CheckCrateVisitor { + tcx: tcx, + tables: &ty::TypeckTables::empty(), + in_fn: false, + promotable: false, + mut_rvalue_borrows: NodeSet(), + param_env: tcx.empty_parameter_environment(), + }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f894c0d32e04..32aeeeb11055 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -82,7 +82,6 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; use astconv::AstConv; -use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -577,14 +576,13 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { tcx.sess.track_errors(|| { let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut visit.as_deep_visitor()); }) } pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { tcx.sess.track_errors(|| { - tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType, - &mut CheckItemTypesVisitor { tcx }); + tcx.hir.krate().visit_all_item_likes(&mut CheckItemTypesVisitor { tcx }); }) } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index ee361ab6073d..8ded3003c78e 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -13,13 +13,12 @@ use rustc::traits; use rustc::ty::{self, TyCtxt}; -use rustc::dep_graph::DepNode; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut orphan = OrphanChecker { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan); + tcx.hir.krate().visit_all_item_likes(&mut orphan); } struct OrphanChecker<'cx, 'tcx: 'cx> { diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index d334d0c4338f..74edc7bff495 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -24,7 +24,7 @@ pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // this secondary walk specifically checks for some other cases, // like defaulted traits, for which additional overlap rules exist - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); + tcx.hir.krate().visit_all_item_likes(&mut overlap); } pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 73e3de0cc76d..af0ef279e4f0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -64,7 +64,6 @@ 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::dep_graph::DepNode; use util::nodemap::{NodeMap, FxHashMap}; use rustc_const_math::ConstInt; @@ -87,7 +86,7 @@ use rustc::hir::def_id::DefId; pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = CollectItemTypesVisitor { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } pub fn provide(providers: &mut Providers) { @@ -126,57 +125,13 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } -impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> { - /// Collect item types is structured into two tasks. The outer - /// task, `CollectItem`, walks the entire content of an item-like - /// thing, including its body. It also spawns an inner task, - /// `CollectItemSig`, which walks only the signature. This inner - /// task is the one that writes the item-type into the various - /// maps. This setup ensures that the item body is never - /// accessible to the task that computes its signature, so that - /// changes to the body don't affect the signature. - /// - /// Consider an example function `foo` that also has a closure in its body: - /// - /// ``` - /// fn foo() { - /// ... - /// let bar = || ...; // we'll label this closure as "bar" below - /// } - /// ``` - /// - /// This results in a dep-graph like so. I've labeled the edges to - /// document where they arise. - /// - /// ``` - /// [HirBody(foo)] -2--> [CollectItem(foo)] -4-> [ItemSignature(bar)] - /// ^ ^ - /// 1 3 - /// [Hir(foo)] -----------+-6-> [CollectItemSig(foo)] -5-> [ItemSignature(foo)] - /// ``` - /// - /// 1. This is added by the `visit_all_item_likes_in_krate`. - /// 2. This is added when we fetch the item body. - /// 3. This is added because `CollectItem` launches `CollectItemSig`. - /// - it is arguably false; if we refactor the `with_task` system; - /// we could get probably rid of it, but it is also harmless enough. - /// 4. This is added by the code in `visit_expr` when we write to `item_types`. - /// 5. This is added by the code in `convert_item` when we write to `item_types`; - /// note that this write occurs inside the `CollectItemSig` task. - /// 6. Added by reads from within `op`. - fn with_collect_item_sig(&self, id: ast::NodeId, op: fn(TyCtxt<'a, 'tcx, 'tcx>, ast::NodeId)) { - let def_id = self.tcx.hir.local_def_id(id); - self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), self.tcx, id, op); - } -} - impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::OnlyBodies(&self.tcx.hir) } fn visit_item(&mut self, item: &'tcx hir::Item) { - self.with_collect_item_sig(item.id, convert_item); + convert_item(self.tcx, item.id); intravisit::walk_item(self, item); } @@ -209,12 +164,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.with_collect_item_sig(trait_item.id, convert_trait_item); + convert_trait_item(self.tcx, trait_item.id); intravisit::walk_trait_item(self, trait_item); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.with_collect_item_sig(impl_item.id, convert_impl_item); + convert_impl_item(self.tcx, impl_item.id); intravisit::walk_impl_item(self, impl_item); } } diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 3df25825a71f..5751dc5ab8a0 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -19,7 +19,6 @@ //! fixed, but for the moment it's easier to do these checks early. use constrained_type_params as ctp; -use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::def_id::DefId; @@ -63,7 +62,7 @@ pub fn impl_wf_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // We will tag this as part of the WF check -- logically, it is, // but it's one that we must perform earlier than the rest of // WfCheck. - tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { tcx: tcx }); + tcx.hir.krate().visit_all_item_likes(&mut ImplWfCheck { tcx: tcx }); } struct ImplWfCheck<'a, 'tcx: 'a> { From 3e473b1aaa4adf205c4d825a35fcd7b74dad1518 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 18 Apr 2017 15:05:04 +0300 Subject: [PATCH 566/905] use Lvalue helper functions in rustc_mir::shim --- src/librustc_mir/shim.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 0cec84d16a81..4d70540a7c68 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -205,12 +205,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, patch: MirPatch::new(&mir), tcx, param_env }; - let dropee = Lvalue::Projection( - box Projection { - base: Lvalue::Local(Local::new(1+0)), - elem: ProjectionElem::Deref - } - ); + let dropee = Lvalue::Local(Local::new(1+0)).deref(); let resume_block = elaborator.patch.resume_block(); elaborate_drops::elaborate_drop( &mut elaborator, @@ -310,9 +305,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, let rcvr = match rcvr_adjustment { Adjustment::Identity => Operand::Consume(rcvr_l), - Adjustment::Deref => Operand::Consume(Lvalue::Projection( - box Projection { base: rcvr_l, elem: ProjectionElem::Deref } - )), + Adjustment::Deref => Operand::Consume(rcvr_l.deref()), Adjustment::RefMut => { // let rcvr = &mut rcvr; let re_erased = tcx.mk_region(ty::ReErased); @@ -352,10 +345,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, if let Some(untuple_args) = untuple_args { args.extend(untuple_args.iter().enumerate().map(|(i, ity)| { let arg_lv = Lvalue::Local(Local::new(1+1)); - Operand::Consume(Lvalue::Projection(box Projection { - base: arg_lv, - elem: ProjectionElem::Field(Field::new(i), *ity) - })) + Operand::Consume(arg_lv.field(Field::new(i), *ity)) })); } else { args.extend((1..sig.inputs().len()).map(|i| { From ed3810bf5e284b243b4500951652839235dd2113 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 18 Apr 2017 15:05:27 +0300 Subject: [PATCH 567/905] lower `move_val_init` during MIR construction Because of its "magic" order-of-evaluation semantics, `move_val_init` must be lowered during MIR construction in order to work. --- src/librustc_mir/build/expr/as_temp.rs | 7 +-- src/librustc_mir/build/expr/into.rs | 62 ++++++++++++++++++-------- src/librustc_trans/mir/block.rs | 10 ----- src/test/codegen/move-val-init.rs | 29 ++++++++++++ 4 files changed, 77 insertions(+), 31 deletions(-) create mode 100644 src/test/codegen/move-val-init.rs diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index e4598b414387..a334923546fb 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -38,9 +38,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("expr_as_temp(block={:?}, expr={:?})", block, expr); let this = self; - if let ExprKind::Scope { .. } = expr.kind { - span_bug!(expr.span, "unexpected scope expression in as_temp: {:?}", - expr); + if let ExprKind::Scope { extent, value } = expr.kind { + return this.in_scope(extent, block, |this| { + this.as_temp(block, temp_lifetime, value) + }); } let expr_ty = expr.ty.clone(); diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index a5a114c61bcf..5982d3bdc81a 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -16,6 +16,8 @@ use hair::*; use rustc::ty; use rustc::mir::*; +use syntax::abi::Abi; + impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. @@ -206,25 +208,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => false }; - let fun = unpack!(block = this.as_local_operand(block, fun)); - let args: Vec<_> = - args.into_iter() - .map(|arg| unpack!(block = this.as_local_operand(block, arg))) - .collect(); - - let success = this.cfg.start_new_block(); - let cleanup = this.diverge_cleanup(); - this.cfg.terminate(block, source_info, TerminatorKind::Call { - func: fun, - args: args, - cleanup: cleanup, - destination: if diverges { - None - } else { - Some ((destination.clone(), success)) + let intrinsic = match ty.sty { + ty::TyFnDef(def_id, _, ref f) if + f.abi() == Abi::RustIntrinsic || + f.abi() == Abi::PlatformIntrinsic => + { + Some(this.hir.tcx().item_name(def_id).as_str()) } - }); - success.unit() + _ => None + }; + let intrinsic = intrinsic.as_ref().map(|s| &s[..]); + let fun = unpack!(block = this.as_local_operand(block, fun)); + if intrinsic == Some("move_val_init") { + // `move_val_init` has "magic" semantics - the second argument is + // always evaluated "directly" into the first one. + + let mut args = args.into_iter(); + let ptr = args.next().expect("0 arguments to `move_val_init`"); + let val = args.next().expect("1 argument to `move_val_init`"); + assert!(args.next().is_none(), ">2 arguments to `move_val_init`"); + + let topmost_scope = this.topmost_scope(); + let ptr = unpack!(block = this.as_temp(block, Some(topmost_scope), ptr)); + this.into(&ptr.deref(), block, val) + } else { + let args: Vec<_> = + args.into_iter() + .map(|arg| unpack!(block = this.as_local_operand(block, arg))) + .collect(); + + let success = this.cfg.start_new_block(); + let cleanup = this.diverge_cleanup(); + this.cfg.terminate(block, source_info, TerminatorKind::Call { + func: fun, + args: args, + cleanup: cleanup, + destination: if diverges { + None + } else { + Some ((destination.clone(), success)) + } + }); + success.unit() + } } // These cases don't actually need a destination diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 0976859e27f4..0f5a38ac7f6b 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -418,16 +418,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let intrinsic = intrinsic.as_ref().map(|s| &s[..]); - if intrinsic == Some("move_val_init") { - let &(_, target) = destination.as_ref().unwrap(); - // The first argument is a thin destination pointer. - let llptr = self.trans_operand(&bcx, &args[0]).immediate(); - let val = self.trans_operand(&bcx, &args[1]); - self.store_operand(&bcx, llptr, None, val); - funclet_br(self, bcx, target); - return; - } - if intrinsic == Some("transmute") { let &(ref dest, target) = destination.as_ref().unwrap(); self.trans_transmute(&bcx, &args[0], dest); diff --git a/src/test/codegen/move-val-init.rs b/src/test/codegen/move-val-init.rs new file mode 100644 index 000000000000..98b7db60b68f --- /dev/null +++ b/src/test/codegen/move-val-init.rs @@ -0,0 +1,29 @@ +// 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: -C no-prepopulate-passes + +#![feature(core_intrinsics)] +#![crate_type = "lib"] + +// test that `move_val_init` actually avoids big allocas + +use std::intrinsics::move_val_init; + +pub struct Big { + pub data: [u8; 65536] +} + +// CHECK-LABEL: @test_mvi +#[no_mangle] +pub unsafe fn test_mvi(target: *mut Big, make_big: fn() -> Big) { + // CHECK: call void %1(%Big*{{[^%]*}} %0) + move_val_init(target, make_big()); +} From 8388772f422ebb869fd9f43eff9fe3d5fe1f709d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 18 Apr 2017 08:20:12 -0400 Subject: [PATCH 568/905] kill a bunch of one off tasks --- src/librustc/dep_graph/dep_node.rs | 20 -------------------- src/librustc/middle/dead.rs | 2 -- src/librustc/middle/entry.rs | 3 --- src/librustc/middle/lang_items.rs | 2 -- src/librustc/middle/resolve_lifetime.rs | 2 -- src/librustc/middle/stability.rs | 4 ---- src/librustc_driver/derive_registrar.rs | 2 -- src/librustc_plugin/build.rs | 2 -- src/librustc_trans/back/link.rs | 2 -- src/librustc_trans/base.rs | 4 +--- src/librustc_typeck/check_unused.rs | 3 --- src/librustc_typeck/coherence/mod.rs | 2 -- src/librustc_typeck/lib.rs | 2 -- 13 files changed, 1 insertion(+), 49 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index dfec80aafcd6..fd9750dbfe3f 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -56,21 +56,14 @@ pub enum DepNode { WorkProduct(Arc), // Represents different phases in the compiler. - CollectLanguageItems, - ResolveLifetimes, RegionResolveCrate, - PluginRegistrar, - StabilityIndex, Coherence, Resolve, - EntryPoint, - CheckEntryFn, CoherenceCheckTrait(D), CoherenceCheckImpl(D), CoherenceOverlapCheck(D), CoherenceOverlapCheckSpecial(D), Variance, - UnusedTraitCheck, PrivacyAccessLevels(CrateNum), // Represents the MIR for a fn; also used as the task node for @@ -83,13 +76,10 @@ pub enum DepNode { BorrowCheck(D), RvalueCheck(D), Reachability, - DeadCheck, LateLintCheck, - TransCrate, TransCrateItem(D), TransInlinedItem(D), TransWriteMetadata, - LinkBinary, // Nodes representing bits of computed IR in the tcx. Each shared // table in the tcx (or elsewhere) maps to one of these @@ -200,24 +190,14 @@ impl DepNode { BorrowCheckKrate => Some(BorrowCheckKrate), MirKrate => Some(MirKrate), TypeckBodiesKrate => Some(TypeckBodiesKrate), - CollectLanguageItems => Some(CollectLanguageItems), - ResolveLifetimes => Some(ResolveLifetimes), RegionResolveCrate => Some(RegionResolveCrate), - PluginRegistrar => Some(PluginRegistrar), - StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), Resolve => Some(Resolve), - EntryPoint => Some(EntryPoint), - CheckEntryFn => Some(CheckEntryFn), Variance => Some(Variance), - UnusedTraitCheck => Some(UnusedTraitCheck), PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)), Reachability => Some(Reachability), - DeadCheck => Some(DeadCheck), LateLintCheck => Some(LateLintCheck), - TransCrate => Some(TransCrate), TransWriteMetadata => Some(TransWriteMetadata), - LinkBinary => Some(LinkBinary), // work product names do not need to be mapped, because // they are always absolute. diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 342553593af3..63d90d93bb51 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -12,7 +12,6 @@ // closely. The idea is that all reachable symbols are live, codes called // from live codes are live, and everything else is dead. -use dep_graph::DepNode; use hir::map as hir_map; use hir::{self, PatKind}; use hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -594,7 +593,6 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::DeadCheck); let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); let krate = tcx.hir.krate(); let live_symbols = find_live(tcx, access_levels, krate); diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index ff7adfb327ad..8da7560387f8 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -9,7 +9,6 @@ // except according to those terms. -use dep_graph::DepNode; use hir::map as hir_map; use hir::def_id::{CRATE_DEF_INDEX}; use session::{config, Session}; @@ -57,8 +56,6 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { } pub fn find_entry_point(session: &Session, hir_map: &hir_map::Map) { - let _task = hir_map.dep_graph.in_task(DepNode::EntryPoint); - let any_exe = session.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeExecutable }); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 81a415a2f530..5989fa9007c4 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -21,7 +21,6 @@ pub use self::LangItem::*; -use dep_graph::DepNode; use hir::map as hir_map; use session::Session; use hir::def_id::DefId; @@ -236,7 +235,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option { pub fn collect_language_items(session: &Session, map: &hir_map::Map) -> LanguageItems { - let _task = map.dep_graph.in_task(DepNode::CollectLanguageItems); let krate: &hir::Crate = map.krate(); let mut collector = LanguageItemCollector::new(session, map); collector.collect(krate); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index b9938a04047c..a1aabc775a31 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -15,7 +15,6 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore we break lifetime name resolution into a separate pass. -use dep_graph::DepNode; use hir::map::Map; use session::Session; use hir::def::Def; @@ -259,7 +258,6 @@ const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; pub fn krate(sess: &Session, hir_map: &Map) -> Result { - let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes); let krate = hir_map.krate(); let mut map = NamedRegionMap { defs: NodeMap(), diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f618386c610b..1e856f6716ef 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -13,7 +13,6 @@ pub use self::StabilityLevel::*; -use dep_graph::DepNode; use hir::map as hir_map; use lint; use hir::def::Def; @@ -383,7 +382,6 @@ impl<'a, 'tcx> Index<'tcx> { // Put the active features into a map for quick lookup self.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); - let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); let krate = tcx.hir.krate(); let mut annotator = Annotator { tcx: tcx, @@ -397,7 +395,6 @@ impl<'a, 'tcx> Index<'tcx> { } pub fn new(hir_map: &hir_map::Map) -> Index<'tcx> { - let _task = hir_map.dep_graph.in_task(DepNode::StabilityIndex); let krate = hir_map.krate(); let mut is_staged_api = false; @@ -662,7 +659,6 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api { - let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); let krate = tcx.hir.krate(); let mut missing = MissingStabilityAnnotations { tcx: tcx, diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index 6a884bafce75..9983efce6af0 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::dep_graph::DepNode; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map::Map; use rustc::hir; @@ -16,7 +15,6 @@ use syntax::ast; use syntax::attr; pub fn find(hir_map: &Map) -> Option { - let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar); let krate = hir_map.krate(); let mut finder = Finder { registrar: None }; diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index 34ebd12de9c1..88af8b49b9e7 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -14,7 +14,6 @@ use syntax::ast; use syntax::attr; use errors; use syntax_pos::Span; -use rustc::dep_graph::DepNode; use rustc::hir::map::Map; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; @@ -44,7 +43,6 @@ impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { pub fn find_plugin_registrar(diagnostic: &errors::Handler, hir_map: &Map) -> Option { - let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar); let krate = hir_map.krate(); let mut finder = RegistrarFinder { registrars: Vec::new() }; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 7468f4ace1b1..7c0522a9c8cf 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -192,8 +192,6 @@ pub fn link_binary(sess: &Session, trans: &CrateTranslation, outputs: &OutputFilenames, crate_name: &str) -> Vec { - let _task = sess.dep_graph.in_task(DepNode::LinkBinary); - 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. diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c770bbdb90f7..cb8022efedb8 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -38,7 +38,7 @@ use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; use middle::cstore::EncodedMetadata; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::dep_graph::{AssertDepGraphSafe, DepNode}; +use rustc::dep_graph::AssertDepGraphSafe; use rustc::middle::cstore::LinkMeta; use rustc::hir::map as hir_map; use rustc::util::common::time; @@ -1057,8 +1057,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, analysis: ty::CrateAnalysis, incremental_hashes_map: &IncrementalHashesMap) -> CrateTranslation { - let _task = tcx.dep_graph.in_task(DepNode::TransCrate); - // Be careful with this krate: obviously it gives access to the // entire contents of the krate. So if you push any subtasks of // `TransCrate`, you need to be careful to register "reads" of the diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 3791079dc812..c9479c5cebc3 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -9,7 +9,6 @@ // except according to those terms. use lint; -use rustc::dep_graph::DepNode; use rustc::ty::TyCtxt; use syntax::ast; @@ -62,8 +61,6 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CheckVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck); - let mut used_trait_imports = DefIdSet(); for &body_id in tcx.hir.krate().bodies.keys() { let item_id = tcx.hir.body_owner(body_id); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index b3a7b612dd5b..b385ddc49c1e 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -18,7 +18,6 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::ty::maps::Providers; -use rustc::dep_graph::DepNode; use syntax::ast; use syntax_pos::DUMMY_SP; @@ -132,7 +131,6 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::Coherence); for &trait_def_id in tcx.hir.krate().trait_impls.keys() { ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id)); } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e9d52c5eb98d..e9a606dc0ab1 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -104,7 +104,6 @@ pub use rustc::middle; pub use rustc::session; pub use rustc::util; -use dep_graph::DepNode; use hir::map as hir_map; use rustc::infer::InferOk; use rustc::ty::subst::Substs; @@ -273,7 +272,6 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn); if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() { match tcx.sess.entry_type.get() { Some(config::EntryMain) => check_main_fn_ty(tcx, id, sp), From c8427831eaad76c92b49e7661e2f23864fb16ce0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 18 Apr 2017 08:22:52 -0400 Subject: [PATCH 569/905] update `dep-graph-struct-signature` test case the `CollectItem` task no longer exists --- src/test/compile-fail/dep-graph-struct-signature.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/test/compile-fail/dep-graph-struct-signature.rs b/src/test/compile-fail/dep-graph-struct-signature.rs index 36382e776ce2..7ed8b95f88b0 100644 --- a/src/test/compile-fail/dep-graph-struct-signature.rs +++ b/src/test/compile-fail/dep-graph-struct-signature.rs @@ -35,44 +35,36 @@ mod signatures { use WillChange; #[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path - #[rustc_then_this_would_need(CollectItem)] //~ ERROR no path trait Bar { #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK - #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK fn do_something(x: WillChange); } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK - #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK fn some_fn(x: WillChange) { } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK - #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK fn new_foo(x: u32, y: u32) -> WillChange { WillChange { x: x, y: y } } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK - #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK impl WillChange { fn new(x: u32, y: u32) -> WillChange { loop { } } } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK - #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK impl WillChange { fn method(&self, x: u32) { } } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK - #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK struct WillChanges { x: WillChange, y: WillChange } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK - #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK fn indirect(x: WillChanges) { } } @@ -80,17 +72,14 @@ mod invalid_signatures { use WontChange; #[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path - #[rustc_then_this_would_need(CollectItem)] //~ ERROR no path trait A { fn do_something_else_twice(x: WontChange); } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path - #[rustc_then_this_would_need(CollectItem)] //~ ERROR no path fn b(x: WontChange) { } #[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path from `WillChange` - #[rustc_then_this_would_need(CollectItem)] //~ ERROR no path from `WillChange` fn c(x: u32) { } } From d6f7577279b28ab0551e60820b737aebf4f61105 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Tue, 18 Apr 2017 15:03:41 +0200 Subject: [PATCH 570/905] Fix typos in std::path's docs * Closed an unclosed paren * seperator -> separator * deperator -> separator --- src/libstd/path.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ce13b57f0a28..22889b5de4c2 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -104,8 +104,8 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; /// Windows uses a variety of path prefix styles, including references to drive /// volumes (like `C:`), network shared folders (like `\\server\share`), and /// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with -/// `\\?\`, in which case `/` is *not* treated as a separator and essentially no -/// normalization is performed. +/// `\\?\`), in which case `/` is *not* treated as a separator and essentially +/// no normalization is performed. /// /// # Examples /// @@ -510,7 +510,7 @@ pub enum Component<'a> { /// The root directory component, appears after any prefix and before anything else. /// - /// It represents a deperator that designates that a path starts from root. + /// It represents a separator that designates that a path starts from root. #[stable(feature = "rust1", since = "1.0.0")] RootDir, @@ -1965,7 +1965,7 @@ impl Path { /// /// When parsing the path, there is a small amount of normalization: /// - /// * Repeated seperators are ignored, so `a/b` and `a//b` both have + /// * Repeated separators are ignored, so `a/b` and `a//b` both have /// `a` and `b` as components. /// /// * Occurentces of `.` are normalized away, exept if they are at the From e46a8bde3c2ef7b1281f3d01e31febc687be2d12 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Mar 2017 14:13:27 -0700 Subject: [PATCH 571/905] std: Back out backtrace pruning logic It was discovered #40264 that this backtrace pruning logic is a little too aggressive, so while we figure how out to handle #40264 this commit backs out the changes to prune frames. Note that other cosmetic changes, such as better path printing and such remain. --- src/libstd/sys_common/backtrace.rs | 84 ++---------------------------- 1 file changed, 4 insertions(+), 80 deletions(-) diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index f5c188f7a753..04fe5f78b03c 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -93,87 +93,11 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { Ok(()) } -fn filter_frames(frames: &[Frame], - format: PrintFormat, - context: &BacktraceContext) -> (usize, usize) +fn filter_frames(_frames: &[Frame], + _format: PrintFormat, + _context: &BacktraceContext) -> (usize, usize) { - if format == PrintFormat::Full { - return (0, 0); - } - - // We want to filter out frames with some prefixes - // from both top and bottom of the call stack. - static BAD_PREFIXES_TOP: &'static [&'static str] = &[ - "_ZN3std3sys3imp9backtrace", - "ZN3std3sys3imp9backtrace", - "std::sys::imp::backtrace", - "_ZN3std10sys_common9backtrace", - "ZN3std10sys_common9backtrace", - "std::sys_common::backtrace", - "_ZN3std9panicking", - "ZN3std9panicking", - "std::panicking", - "_ZN4core9panicking", - "ZN4core9panicking", - "core::panicking", - "_ZN4core6result13unwrap_failed", - "ZN4core6result13unwrap_failed", - "core::result::unwrap_failed", - "rust_begin_unwind", - "_ZN4drop", - "mingw_set_invalid_parameter_handler", - ]; - static BAD_PREFIXES_BOTTOM: &'static [&'static str] = &[ - "_ZN3std9panicking", - "ZN3std9panicking", - "std::panicking", - "_ZN3std5panic", - "ZN3std5panic", - "std::panic", - "_ZN4core9panicking", - "ZN4core9panicking", - "core::panicking", - "_ZN3std2rt10lang_start", - "ZN3std2rt10lang_start", - "std::rt::lang_start", - "panic_unwind::__rust_maybe_catch_panic", - "__rust_maybe_catch_panic", - "_rust_maybe_catch_panic", - "__libc_start_main", - "__rust_try", - "_start", - "main", - "BaseThreadInitThunk", - "RtlInitializeExceptionChain", - "__scrt_common_main_seh", - "_ZN4drop", - "mingw_set_invalid_parameter_handler", - ]; - - let is_good_frame = |frame: Frame, bad_prefixes: &[&str]| { - resolve_symname(frame, |symname| { - if let Some(mangled_symbol_name) = symname { - if !bad_prefixes.iter().any(|s| mangled_symbol_name.starts_with(s)) { - return Ok(()) - } - } - Err(io::Error::from(io::ErrorKind::Other)) - }, context).is_ok() - }; - - let skipped_before = frames.iter().position(|frame| { - is_good_frame(*frame, BAD_PREFIXES_TOP) - }).unwrap_or(frames.len()); - let skipped_after = frames[skipped_before..].iter().rev().position(|frame| { - is_good_frame(*frame, BAD_PREFIXES_BOTTOM) - }).unwrap_or(frames.len() - skipped_before); - - if skipped_before + skipped_after == frames.len() { - // Avoid showing completely empty backtraces - return (0, 0); - } - - (skipped_before, skipped_after) + (0, 0) } /// Controls how the backtrace should be formated. From 43d92bb585aa520436d9039ce74fb5339c5d8786 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Tue, 18 Apr 2017 11:01:20 -0400 Subject: [PATCH 572/905] update mdbook --- src/Cargo.lock | 6 +++--- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 62b853480394..80a8596a499c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -269,7 +269,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.18" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -425,7 +425,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1004,7 +1004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" +"checksum mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "2598843aeda0c5bb2e8e4d714564f1c3fc40f7844157e34563bf96ae3866b56e" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index d5b95c08306b..e32093306722 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT/Apache-2.0" clap = "2.19.3" [dependencies.mdbook] -version = "0.0.18" +version = "0.0.19" default-features = false From 0a69bf4cdd01a279f8b99280de950e0083c85725 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 18 Apr 2017 08:57:56 -0700 Subject: [PATCH 573/905] Bump stage0 to fix ARM LLVM There was a serious ARM codegen bug in LLVM that was fixed by #40779, also backported to beta. This updates stage0 to 1.17.0-beta.3 to pick up that change, so ARM can bootstrap natively again. Fixes #41291 cc @arielb1 --- src/stage0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stage0.txt b/src/stage0.txt index 60fbcadf4915..dc6931c1d0bd 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,4 +12,4 @@ # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was # released on `$date` -rustc: beta-2017-03-21 +rustc: beta-2017-04-05 From a42c0257c7ed05558f685a77db0de08379feeef8 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Tue, 18 Apr 2017 13:40:00 -0300 Subject: [PATCH 574/905] Add bootstrap support for android --- src/bootstrap/bootstrap.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 2e33b4511949..e27f4091b191 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -415,7 +415,11 @@ class RustBuild(object): # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. if ostype == 'Linux': - ostype = 'unknown-linux-gnu' + os = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding) + if os == 'Android': + ostype = 'linux-android' + else: + ostype = 'unknown-linux-gnu' elif ostype == 'FreeBSD': ostype = 'unknown-freebsd' elif ostype == 'DragonFly': @@ -472,15 +476,21 @@ class RustBuild(object): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' + if ostype == 'linux-android': + ostype = 'linux-androideabi' elif cputype == 'armv6l': cputype = 'arm' - ostype += 'eabihf' + if ostype == 'linux-android': + ostype = 'linux-androideabi' + else: + ostype += 'eabihf' elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' - ostype += 'eabihf' - elif cputype == 'aarch64': - cputype = 'aarch64' - elif cputype == 'arm64': + if ostype == 'linux-android': + ostype = 'linux-androideabi' + else: + ostype += 'eabihf' + elif cputype in {'aarch64', 'arm64'}: cputype = 'aarch64' elif cputype == 'mips': if sys.byteorder == 'big': From 82ed7830ad5d8d30751ec608ef07c8d42792c878 Mon Sep 17 00:00:00 2001 From: Nicolas Bigaouette Date: Tue, 18 Apr 2017 14:00:08 -0400 Subject: [PATCH 575/905] Use an (over-writable) environment variable for the `gdb` command Instead of hard-coding the command to run, using the environment variable `GDB_CMD` (that defaults to `gdb`) allows using a different debugger than the default `gdb` executable. This gives the possibility to use `cgdb` as the debugger, which provides a nicer user interface. Note that one has to use `GDB_CMD="cgdb --"` to use cgdb (note the trailing `--`) to let cgdb pass the proper arguments to `gdb`. --- src/etc/rust-gdb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index 520a108da914..ef1689886cb8 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -17,7 +17,10 @@ RUSTC_SYSROOT=`rustc --print=sysroot` GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # Run GDB with the additional arguments that load the pretty printers -PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" gdb \ +# Set the environment variable `GDB_CMD` to overwrite the call to a +# different/specific command (defaults to `gdb`). +GDB_CMD="${GDB_CMD:-gdb}" +PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${GDB_CMD} \ -d "$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ "$@" From 6383de15b186254f892bd7298abb48a46f127e6d Mon Sep 17 00:00:00 2001 From: Cengiz Can Date: Wed, 12 Apr 2017 00:37:40 +0300 Subject: [PATCH 576/905] fixes #40013 --- src/librustc/diagnostics.rs | 52 ++++ src/librustc/traits/error_reporting.rs | 127 ++++++--- src/librustc_typeck/check/writeback.rs | 253 ++++++------------ src/librustc_typeck/diagnostics.rs | 48 +--- ...12-2.rs => cannot_infer_local_or_array.rs} | 2 +- .../cannot_infer_local_or_array.stderr | 10 + ...-38812.rs => cannot_infer_local_or_vec.rs} | 0 ...tderr => cannot_infer_local_or_vec.stderr} | 2 +- .../cannot_infer_local_or_vec_in_tuples.rs} | 6 +- ...annot_infer_local_or_vec_in_tuples.stderr} | 6 +- .../type-check}/issue-22897.rs | 6 +- src/test/ui/type-check/issue-22897.stderr | 8 + .../type-check/unknown_type_for_closure.rs} | 7 +- .../unknown_type_for_closure.stderr | 8 + 14 files changed, 260 insertions(+), 275 deletions(-) rename src/test/ui/type-check/{issue-38812-2.rs => cannot_infer_local_or_array.rs} (94%) create mode 100644 src/test/ui/type-check/cannot_infer_local_or_array.stderr rename src/test/ui/type-check/{issue-38812.rs => cannot_infer_local_or_vec.rs} (100%) rename src/test/ui/type-check/{issue-38812.stderr => cannot_infer_local_or_vec.stderr} (86%) rename src/test/{compile-fail/E0101.rs => ui/type-check/cannot_infer_local_or_vec_in_tuples.rs} (73%) rename src/test/ui/type-check/{issue-38812-2.stderr => cannot_infer_local_or_vec_in_tuples.stderr} (60%) rename src/test/{compile-fail => ui/type-check}/issue-22897.rs (63%) create mode 100644 src/test/ui/type-check/issue-22897.stderr rename src/test/{compile-fail/E0102.rs => ui/type-check/unknown_type_for_closure.rs} (67%) create mode 100644 src/test/ui/type-check/unknown_type_for_closure.stderr diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 8a391f9cde3a..ec4444ac4e36 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1807,6 +1807,58 @@ makes a difference in practice.) [rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md "##, +/* + +E0101: r##" +#### Note: this error code is no longer emitted by the compiler. + +You hit this error because the compiler lacks the information to +determine a type for this expression. Erroneous code example: + +```ignore +let x = |_| {}; // error: cannot determine a type for this expression +``` + +You have two possibilities to solve this situation: + +* Give an explicit definition of the expression +* Infer the expression + +Examples: + +``` +let x = |_ : u32| {}; // ok! +// or: +let x = |_| {}; +x(0u32); +``` +"##, + +E0102: r##" +#### Note: this error code is no longer emitted by the compiler. + +You hit this error because the compiler lacks the information to +determine the type of this variable. Erroneous code example: + +```ignore +// could be an array of anything +let x = []; // error: cannot determine a type for this local variable +``` + +To solve this situation, constrain the type of the variable. +Examples: + +``` +#![allow(unused_variables)] + +fn main() { + let x: [u8; 0] = []; +} +``` +"##, + +*/ + } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f7a7d0e2071f..8a8a5ef3e3af 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -25,7 +25,7 @@ use super::{ use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; -use hir::{intravisit, Local, Pat}; +use hir::{self, intravisit, Local, Pat, Body}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::map::NodeExpr; use hir::def_id::DefId; @@ -33,8 +33,8 @@ use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; -use syntax::ast; -use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use syntax::ast::{self, NodeId}; +use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -66,38 +66,53 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, target_ty: &'a Ty<'tcx>, - found_pattern: Option<&'a Pat>, + hir_map: &'a hir::map::Map<'gcx>, + found_local_pattern: Option<&'gcx Pat>, + found_arg_pattern: Option<&'gcx Pat>, } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn is_match(&self, ty: Ty<'tcx>) -> bool { - ty == *self.target_ty || match (&ty.sty, &self.target_ty.sty) { - (&ty::TyInfer(ty::TyVar(a_vid)), &ty::TyInfer(ty::TyVar(b_vid))) => - self.infcx.type_variables - .borrow_mut() - .sub_unified(a_vid, b_vid), - + fn node_matches_type(&mut self, node_id: &'gcx NodeId) -> bool { + match self.infcx.tables.borrow().node_types.get(node_id) { + Some(&ty) => { + let ty = self.infcx.resolve_type_vars_if_possible(&ty); + ty.walk().any(|inner_ty| { + inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) { + (&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => { + self.infcx + .type_variables + .borrow_mut() + .sub_unified(a_vid, b_vid) + } + _ => false, + } + }) + } _ => false, } } } -impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { - NestedVisitorMap::None +impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { + NestedVisitorMap::OnlyBodies(&self.hir_map) } - fn visit_local(&mut self, local: &'a Local) { - if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) { - let ty = self.infcx.resolve_type_vars_if_possible(&ty); - let is_match = ty.walk().any(|t| self.is_match(t)); - - if is_match && self.found_pattern.is_none() { - self.found_pattern = Some(&*local.pat); - } + fn visit_local(&mut self, local: &'gcx Local) { + if self.found_local_pattern.is_none() && self.node_matches_type(&local.id) { + self.found_local_pattern = Some(&*local.pat); } intravisit::walk_local(self, local); } + + fn visit_body(&mut self, body: &'gcx Body) { + for argument in &body.arguments { + if self.found_arg_pattern.is_none() && self.node_matches_type(&argument.id) { + self.found_arg_pattern = Some(&*argument.pat); + } + } + intravisit::walk_body(self, body); + } } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { @@ -721,6 +736,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // coherence violation, so we don't report it here. let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); + let body_id = hir::BodyId { node_id: obligation.cause.body_id }; + let span = obligation.cause.span; debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", predicate, @@ -768,10 +785,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lang_items.sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - self.need_type_info(obligation, self_ty); + self.need_type_info(body_id, span, self_ty); } else { let mut err = struct_span_err!(self.tcx.sess, - obligation.cause.span, E0283, + span, E0283, "type annotations required: \ cannot resolve `{}`", predicate); @@ -785,7 +802,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Same hacky approach as above to avoid deluging user // with error messages. if !ty.references_error() && !self.tcx.sess.has_errors() { - self.need_type_info(obligation, ty); + self.need_type_info(body_id, span, ty); } } @@ -796,7 +813,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info(obligation, a); + self.need_type_info(hir::BodyId { node_id: obligation.cause.body_id }, + obligation.cause.span, + a); } } @@ -874,42 +893,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn need_type_info(&self, obligation: &PredicateObligation<'tcx>, ty: Ty<'tcx>) { + pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) { let ty = self.resolve_type_vars_if_possible(&ty); let name = self.extract_type_name(&ty); - let ref cause = obligation.cause; - let mut err = struct_span_err!(self.tcx.sess, - cause.span, - E0282, - "type annotations needed"); - - err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); + let mut err_span = span; + let mut labels = vec![(span, format!("cannot infer type for `{}`", name))]; let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, target_ty: &ty, - found_pattern: None, + hir_map: &self.tcx.hir, + found_local_pattern: None, + found_arg_pattern: None, }; // #40294: cause.body_id can also be a fn declaration. // Currently, if it's anything other than NodeExpr, we just ignore it - match self.tcx.hir.find(cause.body_id) { + match self.tcx.hir.find(body_id.node_id) { Some(NodeExpr(expr)) => local_visitor.visit_expr(expr), _ => () } - if let Some(pattern) = local_visitor.found_pattern { - let pattern_span = pattern.span; + if let Some(pattern) = local_visitor.found_arg_pattern { + err_span = pattern.span; + // We don't want to show the default label for closures. + // + // So, before clearing, the output would look something like this: + // ``` + // let x = |_| { }; + // - ^^^^ cannot infer type for `[_; 0]` + // | + // consider giving this closure parameter a type + // ``` + // + // After clearing, it looks something like this: + // ``` + // let x = |_| { }; + // ^ consider giving this closure parameter a type + // ``` + labels.clear(); + labels.push((pattern.span, format!("consider giving this closure parameter a type"))); + } + + if let Some(pattern) = local_visitor.found_local_pattern { if let Some(simple_name) = pattern.simple_name() { - err.span_label(pattern_span, - &format!("consider giving `{}` a type", - simple_name)); + labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); } else { - err.span_label(pattern_span, &format!("consider giving a type to pattern")); + labels.push((pattern.span, format!("consider giving a type to pattern"))); } } + let mut err = struct_span_err!(self.tcx.sess, + err_span, + E0282, + "type annotations needed"); + + for (target_span, label_message) in labels { + err.span_label(target_span, &label_message); + } + err.emit(); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 7fffbd14e216..f196aa82b1ef 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -11,22 +11,18 @@ // Type resolution: the phase that finds all the types in the AST with // unresolved type variables and replaces "ty_var" types with their // substitutions. -use self::ResolveReason::*; use check::FnCtxt; +use rustc::hir; +use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::infer::{InferCtxt}; use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee}; use rustc::ty::adjustment; use rustc::ty::fold::{TypeFolder,TypeFoldable}; -use rustc::infer::{InferCtxt, FixupError}; use rustc::util::nodemap::{DefIdMap, DefIdSet}; - -use std::mem; - use syntax::ast; use syntax_pos::Span; - -use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir; +use std::mem; /////////////////////////////////////////////////////////////////////////// // Entry point @@ -37,9 +33,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let item_id = self.tcx.hir.body_owner(body.id()); let item_def_id = self.tcx.hir.local_def_id(item_id); - let mut wbcx = WritebackCx::new(self); + let mut wbcx = WritebackCx::new(self, body); for arg in &body.arguments { - wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); + wbcx.visit_node_id(arg.pat.span, arg.id); } wbcx.visit_body(body); wbcx.visit_upvar_borrow_map(); @@ -80,15 +76,19 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { // early-bound versions of them, visible from the // outside of the function. This is needed by, and // only populated if there are any `impl Trait`. - free_to_bound_regions: DefIdMap<&'gcx ty::Region> + free_to_bound_regions: DefIdMap<&'gcx ty::Region>, + + body: &'gcx hir::Body, } impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { - fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>) -> WritebackCx<'cx, 'gcx, 'tcx> { + fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body) + -> WritebackCx<'cx, 'gcx, 'tcx> { let mut wbcx = WritebackCx { fcx: fcx, tables: ty::TypeckTables::empty(), - free_to_bound_regions: DefIdMap() + free_to_bound_regions: DefIdMap(), + body: body }; // Only build the reverse mapping if `impl Trait` is used. @@ -195,21 +195,20 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_stmt(&mut self, s: &'gcx hir::Stmt) { - self.visit_node_id(ResolvingExpr(s.span), s.node.id()); + self.visit_node_id(s.span, s.node.id()); intravisit::walk_stmt(self, s); } fn visit_expr(&mut self, e: &'gcx hir::Expr) { self.fix_scalar_builtin_expr(e); - self.visit_node_id(ResolvingExpr(e.span), e.id); - self.visit_method_map_entry(ResolvingExpr(e.span), - MethodCall::expr(e.id)); + self.visit_node_id(e.span, e.id); + self.visit_method_map_entry(e.span, MethodCall::expr(e.id)); if let hir::ExprClosure(_, _, body, _) = e.node { let body = self.fcx.tcx.hir.body(body); for arg in &body.arguments { - self.visit_node_id(ResolvingExpr(e.span), arg.id); + self.visit_node_id(e.span, arg.id); } self.visit_body(body); @@ -219,20 +218,20 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_block(&mut self, b: &'gcx hir::Block) { - self.visit_node_id(ResolvingExpr(b.span), b.id); + self.visit_node_id(b.span, b.id); intravisit::walk_block(self, b); } fn visit_pat(&mut self, p: &'gcx hir::Pat) { - self.visit_node_id(ResolvingPattern(p.span), p.id); + self.visit_node_id(p.span, p.id); intravisit::walk_pat(self, p); } fn visit_local(&mut self, l: &'gcx hir::Local) { - let var_ty = self.fcx.local_ty(l.span, l.id); - let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span)); - self.write_ty_to_tables(l.id, var_ty); intravisit::walk_local(self, l); + let var_ty = self.fcx.local_ty(l.span, l.id); + let var_ty = self.resolve(&var_ty, &l.span); + self.write_ty_to_tables(l.id, var_ty); } } @@ -243,7 +242,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { let r = upvar_borrow.region; - let r = self.resolve(&r, ResolvingUpvar(*upvar_id)); + let r = self.resolve(&r, &upvar_id.var_id); ty::UpvarCapture::ByRef( ty::UpvarBorrow { kind: upvar_borrow.kind, region: r }) } @@ -257,7 +256,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_closures(&mut self) { for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() { - let closure_ty = self.resolve(closure_ty, ResolvingClosure(id)); + let closure_ty = self.resolve(closure_ty, &id); self.tables.closure_tys.insert(id, closure_ty); } @@ -282,8 +281,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_anon_types(&mut self) { let gcx = self.tcx().global_tcx(); for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() { - let reason = ResolvingAnonTy(node_id); - let inside_ty = self.resolve(&concrete_ty, reason); + let inside_ty = self.resolve(&concrete_ty, &node_id); // Convert the type from the function into a type valid outside // the function, by replacing free regions with early-bound ones. @@ -305,7 +303,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::ReLateBound(..) | ty::ReScope(_) | ty::ReSkolemized(..) => { - let span = reason.span(self.tcx()); + let span = node_id.to_span(&self.fcx.tcx); span_err!(self.tcx().sess, span, E0564, "only named lifetimes are allowed in `impl Trait`, \ but `{}` was found in the type `{}`", r, inside_ty); @@ -314,7 +312,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::ReVar(_) | ty::ReErased => { - let span = reason.span(self.tcx()); + let span = node_id.to_span(&self.fcx.tcx); span_bug!(span, "invalid region in impl Trait: {:?}", r); } } @@ -324,37 +322,37 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_node_id(&mut self, reason: ResolveReason, id: ast::NodeId) { + fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) { // Export associated path extensions. - if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&id) { - self.tables.type_relative_path_defs.insert(id, def); + if let Some(def) = self.fcx.tables.borrow_mut().type_relative_path_defs.remove(&node_id) { + self.tables.type_relative_path_defs.insert(node_id, def); } - // Resolve any borrowings for the node with id `id` - self.visit_adjustments(reason, id); + // Resolve any borrowings for the node with id `node_id` + self.visit_adjustments(span, node_id); - // Resolve the type of the node with id `id` - let n_ty = self.fcx.node_ty(id); - let n_ty = self.resolve(&n_ty, reason); - self.write_ty_to_tables(id, n_ty); - debug!("Node {} has type {:?}", id, n_ty); + // Resolve the type of the node with id `node_id` + let n_ty = self.fcx.node_ty(node_id); + let n_ty = self.resolve(&n_ty, &span); + self.write_ty_to_tables(node_id, n_ty); + debug!("Node {} has type {:?}", node_id, n_ty); // Resolve any substitutions - self.fcx.opt_node_ty_substs(id, |item_substs| { - let item_substs = self.resolve(item_substs, reason); + self.fcx.opt_node_ty_substs(node_id, |item_substs| { + let item_substs = self.resolve(item_substs, &span); if !item_substs.is_noop() { - debug!("write_substs_to_tcx({}, {:?})", id, item_substs); + debug!("write_substs_to_tcx({}, {:?})", node_id, item_substs); assert!(!item_substs.substs.needs_infer()); - self.tables.item_substs.insert(id, item_substs); + self.tables.item_substs.insert(node_id, item_substs); } }); } - fn visit_adjustments(&mut self, reason: ResolveReason, id: ast::NodeId) { - let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&id); + fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) { + let adjustments = self.fcx.tables.borrow_mut().adjustments.remove(&node_id); match adjustments { None => { - debug!("No adjustments for node {}", id); + debug!("No adjustments for node {}", node_id); } Some(adjustment) => { @@ -381,29 +379,29 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { for autoderef in 0..autoderefs { - let method_call = MethodCall::autoderef(id, autoderef as u32); - self.visit_method_map_entry(reason, method_call); + let method_call = MethodCall::autoderef(node_id, autoderef as u32); + self.visit_method_map_entry(span, method_call); } adjustment::Adjust::DerefRef { autoderefs: autoderefs, - autoref: self.resolve(&autoref, reason), + autoref: self.resolve(&autoref, &span), unsize: unsize, } } }; let resolved_adjustment = adjustment::Adjustment { kind: resolved_adjustment, - target: self.resolve(&adjustment.target, reason) + target: self.resolve(&adjustment.target, &span) }; - debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); - self.tables.adjustments.insert(id, resolved_adjustment); + debug!("Adjustments for node {}: {:?}", node_id, resolved_adjustment); + self.tables.adjustments.insert(node_id, resolved_adjustment); } } } fn visit_method_map_entry(&mut self, - reason: ResolveReason, + method_span: Span, method_call: MethodCall) { // Resolve any method map entry let new_method = match self.fcx.tables.borrow_mut().method_map.remove(&method_call) { @@ -413,8 +411,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { method); let new_method = MethodCallee { def_id: method.def_id, - ty: self.resolve(&method.ty, reason), - substs: self.resolve(&method.substs, reason), + ty: self.resolve(&method.ty, &method_span), + substs: self.resolve(&method.substs, &method_span), }; Some(new_method) @@ -430,72 +428,49 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_liberated_fn_sigs(&mut self) { for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() { - let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id)); + let fn_sig = self.resolve(fn_sig, &node_id); self.tables.liberated_fn_sigs.insert(node_id, fn_sig.clone()); } } fn visit_fru_field_types(&mut self) { for (&node_id, ftys) in self.fcx.tables.borrow().fru_field_types.iter() { - let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id)); + let ftys = self.resolve(ftys, &node_id); self.tables.fru_field_types.insert(node_id, ftys); } } fn visit_type_nodes(&self) { for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() { - let ty = self.resolve(ty, ResolvingTyNode(id)); + let ty = self.resolve(ty, &id); self.fcx.tcx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty); } } - fn resolve(&self, x: &T, reason: ResolveReason) -> T::Lifted + fn resolve(&self, x: &T, span: &Locatable) -> T::Lifted where T: TypeFoldable<'tcx> + ty::Lift<'gcx> { - let x = x.fold_with(&mut Resolver::new(self.fcx, reason)); + let x = x.fold_with(&mut Resolver::new(self.fcx, span, self.body)); if let Some(lifted) = self.tcx().lift_to_global(&x) { lifted } else { - span_bug!(reason.span(self.tcx()), - "writeback: `{:?}` missing from the global type context", x); + span_bug!(span.to_span(&self.fcx.tcx), + "writeback: `{:?}` missing from the global type context", + x); } } } -/////////////////////////////////////////////////////////////////////////// -// Resolution reason. - -#[derive(Copy, Clone, Debug)] -enum ResolveReason { - ResolvingExpr(Span), - ResolvingLocal(Span), - ResolvingPattern(Span), - ResolvingUpvar(ty::UpvarId), - ResolvingClosure(ast::NodeId), - ResolvingFnSig(ast::NodeId), - ResolvingFieldTypes(ast::NodeId), - ResolvingAnonTy(ast::NodeId), - ResolvingTyNode(ast::NodeId), +trait Locatable { + fn to_span(&self, tcx: &TyCtxt) -> Span; } -impl<'a, 'gcx, 'tcx> ResolveReason { - fn span(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Span { - match *self { - ResolvingExpr(s) => s, - ResolvingLocal(s) => s, - ResolvingPattern(s) => s, - ResolvingUpvar(upvar_id) => { - tcx.expr_span(upvar_id.closure_expr_id) - } - ResolvingClosure(id) | - ResolvingFnSig(id) | - ResolvingFieldTypes(id) | - ResolvingTyNode(id) | - ResolvingAnonTy(id) => { - tcx.hir.span(id) - } - } - } +impl Locatable for Span { + fn to_span(&self, _: &TyCtxt) -> Span { *self } +} + +impl Locatable for ast::NodeId { + fn to_span(&self, tcx: &TyCtxt) -> Span { tcx.hir.span(*self) } } /////////////////////////////////////////////////////////////////////////// @@ -505,82 +480,25 @@ impl<'a, 'gcx, 'tcx> ResolveReason { struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, - reason: ResolveReason, + span: &'cx Locatable, + body: &'gcx hir::Body, } impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> { - fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, - reason: ResolveReason) - -> Resolver<'cx, 'gcx, 'tcx> + fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, span: &'cx Locatable, body: &'gcx hir::Body) + -> Resolver<'cx, 'gcx, 'tcx> { - Resolver::from_infcx(fcx, reason) + Resolver { + tcx: fcx.tcx, + infcx: fcx, + span: span, + body: body, + } } - fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, - reason: ResolveReason) - -> Resolver<'cx, 'gcx, 'tcx> - { - Resolver { infcx: infcx, - tcx: infcx.tcx, - reason: reason } - } - - fn report_error(&self, e: FixupError) { + fn report_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { - match self.reason { - ResolvingExpr(span) => { - struct_span_err!( - self.tcx.sess, span, E0101, - "cannot determine a type for this expression: {}", e) - .span_label(span, &format!("cannot resolve type of expression")) - .emit(); - } - - ResolvingLocal(span) => { - struct_span_err!( - self.tcx.sess, span, E0102, - "cannot determine a type for this local variable: {}", e) - .span_label(span, &format!("cannot resolve type of variable")) - .emit(); - } - - ResolvingPattern(span) => { - span_err!(self.tcx.sess, span, E0103, - "cannot determine a type for this pattern binding: {}", e); - } - - ResolvingUpvar(upvar_id) => { - let span = self.reason.span(self.tcx); - span_err!(self.tcx.sess, span, E0104, - "cannot resolve lifetime for captured variable `{}`: {}", - self.tcx.local_var_name_str(upvar_id.var_id), e); - } - - ResolvingClosure(_) => { - let span = self.reason.span(self.tcx); - span_err!(self.tcx.sess, span, E0196, - "cannot determine a type for this closure") - } - - ResolvingFnSig(_) | - ResolvingFieldTypes(_) | - ResolvingTyNode(_) => { - // any failures here should also fail when - // resolving the patterns, closure types, or - // something else. - let span = self.reason.span(self.tcx); - self.tcx.sess.delay_span_bug( - span, - &format!("cannot resolve some aspect of data for {:?}: {}", - self.reason, e)); - } - - ResolvingAnonTy(_) => { - let span = self.reason.span(self.tcx); - span_err!(self.tcx.sess, span, E0563, - "cannot determine a type for this `impl Trait`: {}", e) - } - } + self.infcx.need_type_info(self.body.id(), self.span.to_span(&self.tcx), t); } } } @@ -593,20 +511,21 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match self.infcx.fully_resolve(&t) { Ok(t) => t, - Err(e) => { + Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); - self.report_error(e); + self.report_error(t); self.tcx().types.err } } } + // FIXME This should be carefully checked + // We could use `self.report_error` but it doesn't accept a ty::Region, right now. fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { match self.infcx.fully_resolve(&r) { Ok(r) => r, - Err(e) => { - self.report_error(e); + Err(_) => { self.tcx.mk_region(ty::ReStatic) } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 2d72052f1e5a..36094d6a8f6b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1351,50 +1351,6 @@ extern "rust-intrinsic" { ``` "##, -E0101: r##" -You hit this error because the compiler lacks the information to -determine a type for this expression. Erroneous code example: - -```compile_fail,E0101 -let x = |_| {}; // error: cannot determine a type for this expression -``` - -You have two possibilities to solve this situation: - -* Give an explicit definition of the expression -* Infer the expression - -Examples: - -``` -let x = |_ : u32| {}; // ok! -// or: -let x = |_| {}; -x(0u32); -``` -"##, - -E0102: r##" -You hit this error because the compiler lacks the information to -determine the type of this variable. Erroneous code example: - -```compile_fail,E0282 -// could be an array of anything -let x = []; // error: cannot determine a type for this local variable -``` - -To solve this situation, constrain the type of the variable. -Examples: - -``` -#![allow(unused_variables)] - -fn main() { - let x: [u8; 0] = []; -} -``` -"##, - E0107: r##" This error means that an incorrect number of lifetime parameters were provided for a type (like a struct or enum) or trait: @@ -4146,8 +4102,6 @@ register_diagnostics! { // E0068, // E0085, // E0086, - E0103, // @GuillaumeGomez: I was unable to get this error, try your best! - E0104, // E0123, // E0127, // E0129, @@ -4164,7 +4118,7 @@ register_diagnostics! { // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object - E0196, // cannot determine a type for this closure + E0196, // cannot determine a type for this closure // @cengizIO: this is no longer thrown. should I DELETE THIS? E0203, // type parameter has more than one relaxed default bound, // and only one is supported E0208, diff --git a/src/test/ui/type-check/issue-38812-2.rs b/src/test/ui/type-check/cannot_infer_local_or_array.rs similarity index 94% rename from src/test/ui/type-check/issue-38812-2.rs rename to src/test/ui/type-check/cannot_infer_local_or_array.rs index c476657d2079..0b35a9c3dbeb 100644 --- a/src/test/ui/type-check/issue-38812-2.rs +++ b/src/test/ui/type-check/cannot_infer_local_or_array.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let (x,) = (vec![],); + let x = []; } diff --git a/src/test/ui/type-check/cannot_infer_local_or_array.stderr b/src/test/ui/type-check/cannot_infer_local_or_array.stderr new file mode 100644 index 000000000000..8c52bb5a1d3a --- /dev/null +++ b/src/test/ui/type-check/cannot_infer_local_or_array.stderr @@ -0,0 +1,10 @@ +error[E0282]: type annotations needed + --> $DIR/cannot_infer_local_or_array.rs:12:13 + | +12 | let x = []; + | - ^^ cannot infer type for `_` + | | + | consider giving `x` a type + +error: aborting due to previous error + diff --git a/src/test/ui/type-check/issue-38812.rs b/src/test/ui/type-check/cannot_infer_local_or_vec.rs similarity index 100% rename from src/test/ui/type-check/issue-38812.rs rename to src/test/ui/type-check/cannot_infer_local_or_vec.rs diff --git a/src/test/ui/type-check/issue-38812.stderr b/src/test/ui/type-check/cannot_infer_local_or_vec.stderr similarity index 86% rename from src/test/ui/type-check/issue-38812.stderr rename to src/test/ui/type-check/cannot_infer_local_or_vec.stderr index 6365e761453f..4788fad20889 100644 --- a/src/test/ui/type-check/issue-38812.stderr +++ b/src/test/ui/type-check/cannot_infer_local_or_vec.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-38812.rs:12:13 + --> $DIR/cannot_infer_local_or_vec.rs:12:13 | 12 | let x = vec![]; | - ^^^^^^ cannot infer type for `T` diff --git a/src/test/compile-fail/E0101.rs b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.rs similarity index 73% rename from src/test/compile-fail/E0101.rs rename to src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.rs index 0005da048e4a..8d32c1ff683b 100644 --- a/src/test/compile-fail/E0101.rs +++ b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -9,7 +9,5 @@ // except according to those terms. fn main() { - let x = |_| {}; - //~^ ERROR E0101 - //~| NOTE cannot resolve type of expression + let (x, ) = (vec![], ); } diff --git a/src/test/ui/type-check/issue-38812-2.stderr b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr similarity index 60% rename from src/test/ui/type-check/issue-38812-2.stderr rename to src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr index 156a6bdee997..3431a1d5bb92 100644 --- a/src/test/ui/type-check/issue-38812-2.stderr +++ b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/issue-38812-2.rs:12:17 + --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:12:18 | -12 | let (x,) = (vec![],); - | ---- ^^^^^^ cannot infer type for `T` +12 | let (x, ) = (vec![], ); + | ----- ^^^^^^ cannot infer type for `T` | | | consider giving a type to pattern | diff --git a/src/test/compile-fail/issue-22897.rs b/src/test/ui/type-check/issue-22897.rs similarity index 63% rename from src/test/compile-fail/issue-22897.rs rename to src/test/ui/type-check/issue-22897.rs index c6bbf2d4abcc..296dc81a89bc 100644 --- a/src/test/compile-fail/issue-22897.rs +++ b/src/test/ui/type-check/issue-22897.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -10,10 +10,6 @@ fn main() { } -// Before these errors would ICE as "cat_expr Errd" because the errors -// were unknown when the bug was triggered. - fn unconstrained_type() { []; - //~^ ERROR cannot determine a type for this expression: unconstrained type } diff --git a/src/test/ui/type-check/issue-22897.stderr b/src/test/ui/type-check/issue-22897.stderr new file mode 100644 index 000000000000..956841188519 --- /dev/null +++ b/src/test/ui/type-check/issue-22897.stderr @@ -0,0 +1,8 @@ +error[E0282]: type annotations needed + --> $DIR/issue-22897.rs:14:5 + | +14 | []; + | ^^ cannot infer type for `[_; 0]` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/E0102.rs b/src/test/ui/type-check/unknown_type_for_closure.rs similarity index 67% rename from src/test/compile-fail/E0102.rs rename to src/test/ui/type-check/unknown_type_for_closure.rs index 6a17ddebd1dc..f1d357df12c4 100644 --- a/src/test/compile-fail/E0102.rs +++ b/src/test/ui/type-check/unknown_type_for_closure.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -9,8 +9,5 @@ // except according to those terms. fn main() { - let x = []; - //~^ ERROR type annotations needed - //~| NOTE consider giving `x` a type - //~| NOTE cannot infer type for `_` + let x = |_| { }; } diff --git a/src/test/ui/type-check/unknown_type_for_closure.stderr b/src/test/ui/type-check/unknown_type_for_closure.stderr new file mode 100644 index 000000000000..afbd15ca486b --- /dev/null +++ b/src/test/ui/type-check/unknown_type_for_closure.stderr @@ -0,0 +1,8 @@ +error[E0282]: type annotations needed + --> $DIR/unknown_type_for_closure.rs:12:14 + | +12 | let x = |_| { }; + | ^ consider giving this closure parameter a type + +error: aborting due to previous error + From 8b45a21bd1900fa7935fea96bdaf8583e1002832 Mon Sep 17 00:00:00 2001 From: Cengiz Can Date: Tue, 18 Apr 2017 16:56:08 +0300 Subject: [PATCH 577/905] comment out removed error codes --- src/librustc/diagnostics.rs | 54 ++---------------------------- src/librustc_typeck/diagnostics.rs | 4 ++- 2 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index ec4444ac4e36..618561f3b025 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1807,63 +1807,13 @@ makes a difference in practice.) [rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md "##, -/* - -E0101: r##" -#### Note: this error code is no longer emitted by the compiler. - -You hit this error because the compiler lacks the information to -determine a type for this expression. Erroneous code example: - -```ignore -let x = |_| {}; // error: cannot determine a type for this expression -``` - -You have two possibilities to solve this situation: - -* Give an explicit definition of the expression -* Infer the expression - -Examples: - -``` -let x = |_ : u32| {}; // ok! -// or: -let x = |_| {}; -x(0u32); -``` -"##, - -E0102: r##" -#### Note: this error code is no longer emitted by the compiler. - -You hit this error because the compiler lacks the information to -determine the type of this variable. Erroneous code example: - -```ignore -// could be an array of anything -let x = []; // error: cannot determine a type for this local variable -``` - -To solve this situation, constrain the type of the variable. -Examples: - -``` -#![allow(unused_variables)] - -fn main() { - let x: [u8; 0] = []; -} -``` -"##, - -*/ - } register_diagnostics! { // E0006 // merged with E0005 +// E0101, // replaced with E0282 +// E0102, // replaced with E0282 // E0134, // E0135, E0278, // requirement is not satisfied diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 36094d6a8f6b..68afcae2b674 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4102,6 +4102,8 @@ register_diagnostics! { // E0068, // E0085, // E0086, +// E0103, +// E0104, // E0123, // E0127, // E0129, @@ -4118,7 +4120,7 @@ register_diagnostics! { // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object - E0196, // cannot determine a type for this closure // @cengizIO: this is no longer thrown. should I DELETE THIS? +// E0196, // cannot determine a type for this closure E0203, // type parameter has more than one relaxed default bound, // and only one is supported E0208, From 3092ac40b617ec26dc03cd56558267be03c25cbd Mon Sep 17 00:00:00 2001 From: Cengiz Can Date: Tue, 18 Apr 2017 21:42:55 +0300 Subject: [PATCH 578/905] change note for patterns --- src/librustc/traits/error_reporting.rs | 2 +- src/test/compile-fail/issue-12187-1.rs | 2 +- src/test/compile-fail/issue-12187-2.rs | 2 +- .../ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8a8a5ef3e3af..71dff3b2bb94 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -940,7 +940,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some(simple_name) = pattern.simple_name() { labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); } else { - labels.push((pattern.span, format!("consider giving a type to pattern"))); + labels.push((pattern.span, format!("consider giving the pattern a type"))); } } diff --git a/src/test/compile-fail/issue-12187-1.rs b/src/test/compile-fail/issue-12187-1.rs index 6aeb9442c40e..a79021d3cd5d 100644 --- a/src/test/compile-fail/issue-12187-1.rs +++ b/src/test/compile-fail/issue-12187-1.rs @@ -16,5 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` - //~| NOTE consider giving a type to pattern + //~| NOTE consider giving the pattern a type } diff --git a/src/test/compile-fail/issue-12187-2.rs b/src/test/compile-fail/issue-12187-2.rs index d52ed06c4085..38b3c5d4e9a6 100644 --- a/src/test/compile-fail/issue-12187-2.rs +++ b/src/test/compile-fail/issue-12187-2.rs @@ -16,5 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` - //~| NOTE consider giving a type to pattern + //~| NOTE consider giving the pattern a type } diff --git a/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr index 3431a1d5bb92..ccffadebe9ee 100644 --- a/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr +++ b/src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed 12 | let (x, ) = (vec![], ); | ----- ^^^^^^ cannot infer type for `T` | | - | consider giving a type to pattern + | consider giving the pattern a type | = note: this error originates in a macro outside of the current crate From fd325a1b485b1698f86e791a5586cda79e64fdbd Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Tue, 18 Apr 2017 23:33:38 +0100 Subject: [PATCH 579/905] Fix a few stability attributes These show up in rustdoc so need to be correct. --- src/libcollections/btree/map.rs | 5 +++++ src/libcollections/btree/set.rs | 5 +++++ src/libcollections/vec_deque.rs | 2 +- src/libcore/macros.rs | 10 +++++----- src/libstd/error.rs | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index b986c0275502..fb0b852d1027 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1442,6 +1442,7 @@ impl<'a, K, V> Clone for Values<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for Range<'a, K, V> { type Item = (&'a K, &'a V); @@ -1517,6 +1518,7 @@ impl<'a, K, V> Range<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a V)> { if self.front == self.back { @@ -1562,6 +1564,7 @@ impl<'a, K, V> Range<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Range<'a, K, V> {} +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Clone for Range<'a, K, V> { fn clone(&self) -> Range<'a, K, V> { Range { @@ -1571,6 +1574,7 @@ impl<'a, K, V> Clone for Range<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for RangeMut<'a, K, V> { type Item = (&'a K, &'a mut V); @@ -1615,6 +1619,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { if self.front == self.back { diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index ffca6964c5fd..dfff44e30c59 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -941,11 +941,14 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> Clone for Range<'a, T> { fn clone(&self) -> Range<'a, T> { Range { iter: self.iter.clone() } } } + +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> Iterator for Range<'a, T> { type Item = &'a T; @@ -953,6 +956,8 @@ impl<'a, T> Iterator for Range<'a, T> { self.iter.next().map(|(k, _)| k) } } + +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> DoubleEndedIterator for Range<'a, T> { fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back().map(|(k, _)| k) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 2ce3b92843bd..2a73a78adbe5 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -2272,7 +2272,7 @@ macro_rules! __impl_slice_eq1 { __impl_slice_eq1! { $Lhs, $Rhs, Sized } }; ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - #[stable(feature = "vec-deque-partial-eq-slice", since = "1.16.0")] + #[stable(feature = "vec-deque-partial-eq-slice", since = "1.17.0")] impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { fn eq(&self, other: &$Rhs) -> bool { if self.len() != other.len() { diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 2a28d108df77..bf4e414d4168 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -150,7 +150,7 @@ macro_rules! assert_eq { /// assert_ne!(a, b, "we are testing that the values are not equal"); /// ``` #[macro_export] -#[stable(feature = "assert_ne", since = "1.12.0")] +#[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! assert_ne { ($left:expr, $right:expr) => ({ match (&$left, &$right) { @@ -268,7 +268,7 @@ macro_rules! debug_assert_eq { /// debug_assert_ne!(a, b); /// ``` #[macro_export] -#[stable(feature = "assert_ne", since = "1.12.0")] +#[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! debug_assert_ne { ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); }) } @@ -379,7 +379,7 @@ macro_rules! try { /// assert_eq!(v, b"s = \"abc 123\""); /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! write { ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) } @@ -479,7 +479,7 @@ macro_rules! writeln { /// } /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! unreachable { () => ({ panic!("internal error: entered unreachable code") @@ -540,7 +540,7 @@ macro_rules! unreachable { /// } /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! unimplemented { () => (panic!("not yet implemented")) } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3d80120f6b2b..9ff7d7467338 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -216,7 +216,7 @@ impl<'a> From<&'a str> for Box { } } -#[stable(feature = "never_error", since = "1.18.0")] +#[unstable(feature = "never_type_impls", issue = "35121")] impl Error for ! { fn description(&self) -> &str { *self } } From cba0c6ad6da735d00819d5a0df3953b3a8ebfe3e Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 18 Apr 2017 23:59:25 +0300 Subject: [PATCH 580/905] rustc_trans: do not treat byval as using up registers. --- src/librustc_trans/cabi_x86_64.rs | 6 +++--- .../run-make/extern-fn-struct-passing-abi/test.c | 15 +++++++++++++++ .../run-make/extern-fn-struct-passing-abi/test.rs | 8 ++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 2daebf5cf3d6..2cfab7df8b30 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -229,12 +229,12 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType }; if in_mem { - // `sret` / `byval` parameter thus one less integer register available - int_regs -= 1; - arg.make_indirect(ccx); if is_arg { arg.attrs.set(ArgAttribute::ByVal); + } else { + // `sret` parameter thus one less integer register available + int_regs -= 1; } } else { // split into sized chunks passed individually diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.c b/src/test/run-make/extern-fn-struct-passing-abi/test.c index 4e09928edc6d..44a940a17a98 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.c +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.c @@ -137,6 +137,21 @@ void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d, assert(s.d == 556); } +// System V x86_64 ABI: +// a, b, d, e, f should be byval pointer (on the stack) +// g passed via register (fixes #41375) +// +// Win64 ABI: +// a, b, d, e, f, g should be byval pointer +void byval_rect_with_many_huge(struct Huge a, struct Huge b, struct Huge c, + struct Huge d, struct Huge e, struct Huge f, + struct Rect g) { + assert(g.a == 123); + assert(g.b == 456); + assert(g.c == 789); + assert(g.d == 420); +} + // System V x86_64 & Win64 ABI: // a, b should be in registers // s should be split across 2 integer registers diff --git a/src/test/run-make/extern-fn-struct-passing-abi/test.rs b/src/test/run-make/extern-fn-struct-passing-abi/test.rs index ff845a644b11..aaae7ae4fb49 100644 --- a/src/test/run-make/extern-fn-struct-passing-abi/test.rs +++ b/src/test/run-make/extern-fn-struct-passing-abi/test.rs @@ -64,6 +64,8 @@ extern { fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect); + fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect); + fn split_rect(a: i32, b: i32, s: Rect); fn split_rect_floats(a: f32, b: f32, s: FloatRect); @@ -95,6 +97,12 @@ fn main() { byval_many_rect(1, 2, 3, 4, 5, 6, s); byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u); byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s); + byval_rect_with_many_huge(v, v, v, v, v, v, Rect { + a: 123, + b: 456, + c: 789, + d: 420 + }); split_rect(1, 2, s); split_rect_floats(1., 2., u); split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s); From fea357663364c3b9464b1d907d8e1f11e859bc2b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 13 Apr 2017 13:12:44 -0400 Subject: [PATCH 581/905] Add top level sections to the Unstable Book. Prior to this commit, the contents of the Unstable Book were assumed to be unstable features. This commit moves features into 'language features' or 'library features' subsections. It also moves the 'linker_flavor' compiler flag into a new 'Compiler Flags' subsection. Even though it was helpful, I removed the tidy check that cross-references the SUMMARY.md links with the Unstable Book directory contents just because it would be difficult to maintain. Relevant PR: https://github.com/rust-lang/rust/issues/41142. --- src/Cargo.lock | 3 - src/doc/guide-plugins.md | 2 +- src/doc/unstable-book/src/SUMMARY.md | 450 +++++++++--------- src/doc/unstable-book/src/compiler-flags.md | 1 + .../src/{ => compiler-flags}/linker-flavor.md | 0 .../unstable-book/src/language-features.md | 1 + .../abi-msp430-interrupt.md | 0 .../src/{ => language-features}/abi-ptx.md | 0 .../src/{ => language-features}/abi-sysv64.md | 0 .../{ => language-features}/abi-unadjusted.md | 0 .../{ => language-features}/abi-vectorcall.md | 0 .../abi-x86-interrupt.md | 0 .../advanced-slice-patterns.md | 0 .../src/{ => language-features}/allocator.md | 0 .../allow-internal-unstable.md | 0 .../src/{ => language-features}/asm.md | 0 .../associated-consts.md | 0 .../associated-type-defaults.md | 0 .../{ => language-features}/attr-literals.md | 0 .../{ => language-features}/box-patterns.md | 0 .../src/{ => language-features}/box-syntax.md | 0 .../src/{ => language-features}/catch-expr.md | 0 .../cfg-target-feature.md | 0 .../cfg-target-has-atomic.md | 0 .../cfg-target-thread-local.md | 0 .../cfg-target-vendor.md | 0 .../closure-to-fn-coercion.md | 0 .../compiler-builtins.md | 0 .../{ => language-features}/concat-idents.md | 0 .../conservative-impl-trait.md | 0 .../src/{ => language-features}/const-fn.md | 0 .../{ => language-features}/const-indexing.md | 0 .../custom-attribute.md | 0 .../{ => language-features}/custom-derive.md | 0 .../default-type-parameter-fallback.md | 0 .../drop-types-in-const.md | 0 .../dropck-eyepatch.md | 0 .../dropck-parametricity.md | 0 .../exclusive-range-pattern.md | 0 .../{ => language-features}/fundamental.md | 0 .../generic-param-attrs.md | 0 .../src/{ => language-features}/global_asm.md | 0 .../src/{ => language-features}/i128-type.md | 0 .../inclusive-range-syntax.md | 0 .../src/{ => language-features}/intrinsics.md | 0 .../src/{ => language-features}/lang-items.md | 0 .../src/{ => language-features}/link-args.md | 0 .../src/{ => language-features}/link-cfg.md | 0 .../link-llvm-intrinsics.md | 0 .../src/{ => language-features}/linkage.md | 0 .../src/{ => language-features}/log-syntax.md | 0 .../loop-break-value.md | 0 .../{ => language-features}/macro-reexport.md | 0 .../macro-vis-matcher.md | 0 .../src/{ => language-features}/main.md | 0 .../naked-functions.md | 0 .../needs-allocator.md | 0 .../needs-panic-runtime.md | 0 .../src/{ => language-features}/never-type.md | 0 .../src/{ => language-features}/no-core.md | 0 .../src/{ => language-features}/no-debug.md | 0 .../non-ascii-idents.md | 0 .../omit-gdb-pretty-printer-section.md | 0 .../on-unimplemented.md | 0 .../optin-builtin-traits.md | 0 .../overlapping-marker-traits.md | 0 .../{ => language-features}/panic-runtime.md | 0 .../placement-in-syntax.md | 0 .../platform-intrinsics.md | 0 .../plugin-registrar.md | 0 .../src/{ => language-features}/plugin.md | 0 .../{ => language-features}/prelude-import.md | 0 .../src/{ => language-features}/proc-macro.md | 0 .../src/{ => language-features}/quote.md | 0 .../{ => language-features}/relaxed-adts.md | 0 .../src/{ => language-features}/repr-simd.md | 0 .../{ => language-features}/rustc-attrs.md | 0 .../rustc-diagnostic-macros.md | 0 .../rvalue-static-promotion.md | 0 .../sanitizer-runtime.md | 0 .../src/{ => language-features}/simd-ffi.md | 0 .../src/{ => language-features}/simd.md | 0 .../{ => language-features}/slice-patterns.md | 0 .../{ => language-features}/specialization.md | 0 .../src/{ => language-features}/staged-api.md | 0 .../src/{ => language-features}/start.md | 0 .../static-nobundle.md | 0 .../stmt-expr-attributes.md | 0 .../struct-field-attributes.md | 0 .../structural-match.md | 0 .../{ => language-features}/target-feature.md | 0 .../{ => language-features}/thread-local.md | 0 .../{ => language-features}/trace-macros.md | 0 .../type-ascription.md | 0 .../unboxed-closures.md | 0 .../untagged-unions.md | 0 .../unwind-attributes.md | 0 .../use-extern-macros.md | 0 .../src/{ => language-features}/used.md | 0 src/doc/unstable-book/src/library-features.md | 1 + .../{ => library-features}/alloc-jemalloc.md | 0 .../{ => library-features}/alloc-system.md | 0 .../src/{ => library-features}/alloc.md | 0 .../src/{ => library-features}/as-c-str.md | 0 .../{ => library-features}/as-unsafe-cell.md | 0 .../src/{ => library-features}/ascii-ctype.md | 0 .../binary-heap-extras.md | 0 .../binary-heap-peek-mut-pop.md | 0 .../{ => library-features}/borrow-state.md | 0 .../src/{ => library-features}/box-heap.md | 0 .../{ => library-features}/c-void-variant.md | 0 .../char-escape-debug.md | 0 .../{ => library-features}/coerce-unsized.md | 0 .../collection-placement.md | 0 .../collections-range.md | 0 .../src/{ => library-features}/collections.md | 0 .../{ => library-features}/command-envs.md | 0 .../compiler-builtins-lib.md | 0 .../{ => library-features}/compiler-fences.md | 0 .../concat-idents-macro.md | 0 .../{ => library-features}/core-char-ext.md | 0 .../src/{ => library-features}/core-float.md | 0 .../{ => library-features}/core-intrinsics.md | 0 .../src/{ => library-features}/core-panic.md | 0 .../core-private-bignum.md | 0 .../core-private-diy-float.md | 0 .../{ => library-features}/core-slice-ext.md | 0 .../{ => library-features}/core-str-ext.md | 0 .../src/{ => library-features}/dec2flt.md | 0 .../src/{ => library-features}/decode-utf8.md | 0 .../derive-clone-copy.md | 0 .../src/{ => library-features}/derive-eq.md | 0 .../discriminant-value.md | 0 .../src/{ => library-features}/enumset.md | 0 .../{ => library-features}/error-type-id.md | 0 .../exact-size-is-empty.md | 0 .../src/{ => library-features}/fd-read.md | 0 .../src/{ => library-features}/fd.md | 0 .../fixed-size-array.md | 0 .../{ => library-features}/float-bits-conv.md | 0 .../{ => library-features}/float-extras.md | 0 .../src/{ => library-features}/flt2dec.md | 0 .../{ => library-features}/fmt-flags-align.md | 0 .../{ => library-features}/fmt-internals.md | 0 .../src/{ => library-features}/fn-traits.md | 0 .../src/{ => library-features}/fnbox.md | 0 .../from_utf8_error_as_bytes.md | 0 .../src/{ => library-features}/fused.md | 0 .../future-atomic-orderings.md | 0 .../src/{ => library-features}/get-type-id.md | 0 .../src/{ => library-features}/heap-api.md | 0 .../src/{ => library-features}/i128.md | 0 .../{ => library-features}/inclusive-range.md | 0 .../int-error-internals.md | 0 .../{ => library-features}/integer-atomics.md | 0 .../into-boxed-c-str.md | 0 .../into-boxed-os-str.md | 0 .../{ => library-features}/into-boxed-path.md | 0 .../io-error-internals.md | 0 .../src/{ => library-features}/io.md | 0 .../src/{ => library-features}/ip.md | 0 .../src/{ => library-features}/is-unique.md | 0 .../src/{ => library-features}/iter-rfind.md | 0 .../libstd-io-internals.md | 0 .../libstd-sys-internals.md | 0 .../libstd-thread-internals.md | 0 .../linked-list-extras.md | 0 .../src/{ => library-features}/lookup-host.md | 0 .../{ => library-features}/manually-drop.md | 0 .../map-entry-recover-keys.md | 0 .../src/{ => library-features}/mpsc-select.md | 0 .../src/{ => library-features}/n16.md | 0 .../never-type-impls.md | 0 .../src/{ => library-features}/nonzero.md | 0 .../src/{ => library-features}/offset-to.md | 0 .../src/{ => library-features}/once-poison.md | 0 .../src/{ => library-features}/oom.md | 0 .../{ => library-features}/option-entry.md | 0 .../osstring-shrink-to-fit.md | 0 .../src/{ => library-features}/panic-abort.md | 0 .../{ => library-features}/panic-unwind.md | 0 .../src/{ => library-features}/pattern.md | 0 .../src/{ => library-features}/peek.md | 0 .../{ => library-features}/placement-in.md | 0 .../placement-new-protocol.md | 0 .../src/{ => library-features}/print.md | 0 .../proc-macro-internals.md | 0 .../process-try-wait.md | 0 .../question-mark-carrier.md | 0 .../src/{ => library-features}/rand.md | 0 .../{ => library-features}/range-contains.md | 0 .../src/{ => library-features}/raw.md | 0 .../{ => library-features}/rc-would-unwrap.md | 0 .../retain-hash-collection.md | 0 .../{ => library-features}/reverse-cmp-key.md | 0 .../src/{ => library-features}/rt.md | 0 .../{ => library-features}/rustc-private.md | 0 .../sanitizer-runtime-lib.md | 0 .../src/{ => library-features}/set-stdio.md | 0 .../src/{ => library-features}/shared.md | 0 .../src/{ => library-features}/sip-hash-13.md | 0 .../slice-concat-ext.md | 0 .../{ => library-features}/slice-get-slice.md | 0 .../{ => library-features}/slice-rsplit.md | 0 .../{ => library-features}/sort-internals.md | 0 .../{ => library-features}/sort-unstable.md | 0 .../src/{ => library-features}/step-by.md | 0 .../src/{ => library-features}/step-trait.md | 0 .../str-checked-slicing.md | 0 .../src/{ => library-features}/str-escape.md | 0 .../{ => library-features}/str-internals.md | 0 .../{ => library-features}/str-mut-extras.md | 0 .../src/{ => library-features}/test.md | 0 .../src/{ => library-features}/thread-id.md | 0 .../thread-local-internals.md | 0 .../thread-local-state.md | 0 .../toowned-clone-into.md | 0 .../src/{ => library-features}/trusted-len.md | 0 .../src/{ => library-features}/try-from.md | 0 .../src/{ => library-features}/unicode.md | 0 .../src/{ => library-features}/unique.md | 0 .../src/{ => library-features}/unsize.md | 0 .../update-panic-count.md | 0 .../utf8-error-error-len.md | 0 .../{ => library-features}/vec-remove-item.md | 0 .../src/{ => library-features}/windows-c.md | 0 .../{ => library-features}/windows-handle.md | 0 .../src/{ => library-features}/windows-net.md | 0 .../{ => library-features}/windows-stdio.md | 0 .../src/{ => library-features}/zero-one.md | 0 .../unstable-book/src/the-unstable-book.md | 2 +- src/libsyntax/feature_gate.rs | 3 - src/tools/linkchecker/main.rs | 6 + src/tools/tidy/Cargo.toml | 3 - src/tools/tidy/src/main.rs | 2 - src/tools/tidy/src/unstable_book.rs | 133 +++--- 236 files changed, 307 insertions(+), 300 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags.md rename src/doc/unstable-book/src/{ => compiler-flags}/linker-flavor.md (100%) create mode 100644 src/doc/unstable-book/src/language-features.md rename src/doc/unstable-book/src/{ => language-features}/abi-msp430-interrupt.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-ptx.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-sysv64.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-unadjusted.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-vectorcall.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-x86-interrupt.md (100%) rename src/doc/unstable-book/src/{ => language-features}/advanced-slice-patterns.md (100%) rename src/doc/unstable-book/src/{ => language-features}/allocator.md (100%) rename src/doc/unstable-book/src/{ => language-features}/allow-internal-unstable.md (100%) rename src/doc/unstable-book/src/{ => language-features}/asm.md (100%) rename src/doc/unstable-book/src/{ => language-features}/associated-consts.md (100%) rename src/doc/unstable-book/src/{ => language-features}/associated-type-defaults.md (100%) rename src/doc/unstable-book/src/{ => language-features}/attr-literals.md (100%) rename src/doc/unstable-book/src/{ => language-features}/box-patterns.md (100%) rename src/doc/unstable-book/src/{ => language-features}/box-syntax.md (100%) rename src/doc/unstable-book/src/{ => language-features}/catch-expr.md (100%) rename src/doc/unstable-book/src/{ => language-features}/cfg-target-feature.md (100%) rename src/doc/unstable-book/src/{ => language-features}/cfg-target-has-atomic.md (100%) rename src/doc/unstable-book/src/{ => language-features}/cfg-target-thread-local.md (100%) rename src/doc/unstable-book/src/{ => language-features}/cfg-target-vendor.md (100%) rename src/doc/unstable-book/src/{ => language-features}/closure-to-fn-coercion.md (100%) rename src/doc/unstable-book/src/{ => language-features}/compiler-builtins.md (100%) rename src/doc/unstable-book/src/{ => language-features}/concat-idents.md (100%) rename src/doc/unstable-book/src/{ => language-features}/conservative-impl-trait.md (100%) rename src/doc/unstable-book/src/{ => language-features}/const-fn.md (100%) rename src/doc/unstable-book/src/{ => language-features}/const-indexing.md (100%) rename src/doc/unstable-book/src/{ => language-features}/custom-attribute.md (100%) rename src/doc/unstable-book/src/{ => language-features}/custom-derive.md (100%) rename src/doc/unstable-book/src/{ => language-features}/default-type-parameter-fallback.md (100%) rename src/doc/unstable-book/src/{ => language-features}/drop-types-in-const.md (100%) rename src/doc/unstable-book/src/{ => language-features}/dropck-eyepatch.md (100%) rename src/doc/unstable-book/src/{ => language-features}/dropck-parametricity.md (100%) rename src/doc/unstable-book/src/{ => language-features}/exclusive-range-pattern.md (100%) rename src/doc/unstable-book/src/{ => language-features}/fundamental.md (100%) rename src/doc/unstable-book/src/{ => language-features}/generic-param-attrs.md (100%) rename src/doc/unstable-book/src/{ => language-features}/global_asm.md (100%) rename src/doc/unstable-book/src/{ => language-features}/i128-type.md (100%) rename src/doc/unstable-book/src/{ => language-features}/inclusive-range-syntax.md (100%) rename src/doc/unstable-book/src/{ => language-features}/intrinsics.md (100%) rename src/doc/unstable-book/src/{ => language-features}/lang-items.md (100%) rename src/doc/unstable-book/src/{ => language-features}/link-args.md (100%) rename src/doc/unstable-book/src/{ => language-features}/link-cfg.md (100%) rename src/doc/unstable-book/src/{ => language-features}/link-llvm-intrinsics.md (100%) rename src/doc/unstable-book/src/{ => language-features}/linkage.md (100%) rename src/doc/unstable-book/src/{ => language-features}/log-syntax.md (100%) rename src/doc/unstable-book/src/{ => language-features}/loop-break-value.md (100%) rename src/doc/unstable-book/src/{ => language-features}/macro-reexport.md (100%) rename src/doc/unstable-book/src/{ => language-features}/macro-vis-matcher.md (100%) rename src/doc/unstable-book/src/{ => language-features}/main.md (100%) rename src/doc/unstable-book/src/{ => language-features}/naked-functions.md (100%) rename src/doc/unstable-book/src/{ => language-features}/needs-allocator.md (100%) rename src/doc/unstable-book/src/{ => language-features}/needs-panic-runtime.md (100%) rename src/doc/unstable-book/src/{ => language-features}/never-type.md (100%) rename src/doc/unstable-book/src/{ => language-features}/no-core.md (100%) rename src/doc/unstable-book/src/{ => language-features}/no-debug.md (100%) rename src/doc/unstable-book/src/{ => language-features}/non-ascii-idents.md (100%) rename src/doc/unstable-book/src/{ => language-features}/omit-gdb-pretty-printer-section.md (100%) rename src/doc/unstable-book/src/{ => language-features}/on-unimplemented.md (100%) rename src/doc/unstable-book/src/{ => language-features}/optin-builtin-traits.md (100%) rename src/doc/unstable-book/src/{ => language-features}/overlapping-marker-traits.md (100%) rename src/doc/unstable-book/src/{ => language-features}/panic-runtime.md (100%) rename src/doc/unstable-book/src/{ => language-features}/placement-in-syntax.md (100%) rename src/doc/unstable-book/src/{ => language-features}/platform-intrinsics.md (100%) rename src/doc/unstable-book/src/{ => language-features}/plugin-registrar.md (100%) rename src/doc/unstable-book/src/{ => language-features}/plugin.md (100%) rename src/doc/unstable-book/src/{ => language-features}/prelude-import.md (100%) rename src/doc/unstable-book/src/{ => language-features}/proc-macro.md (100%) rename src/doc/unstable-book/src/{ => language-features}/quote.md (100%) rename src/doc/unstable-book/src/{ => language-features}/relaxed-adts.md (100%) rename src/doc/unstable-book/src/{ => language-features}/repr-simd.md (100%) rename src/doc/unstable-book/src/{ => language-features}/rustc-attrs.md (100%) rename src/doc/unstable-book/src/{ => language-features}/rustc-diagnostic-macros.md (100%) rename src/doc/unstable-book/src/{ => language-features}/rvalue-static-promotion.md (100%) rename src/doc/unstable-book/src/{ => language-features}/sanitizer-runtime.md (100%) rename src/doc/unstable-book/src/{ => language-features}/simd-ffi.md (100%) rename src/doc/unstable-book/src/{ => language-features}/simd.md (100%) rename src/doc/unstable-book/src/{ => language-features}/slice-patterns.md (100%) rename src/doc/unstable-book/src/{ => language-features}/specialization.md (100%) rename src/doc/unstable-book/src/{ => language-features}/staged-api.md (100%) rename src/doc/unstable-book/src/{ => language-features}/start.md (100%) rename src/doc/unstable-book/src/{ => language-features}/static-nobundle.md (100%) rename src/doc/unstable-book/src/{ => language-features}/stmt-expr-attributes.md (100%) rename src/doc/unstable-book/src/{ => language-features}/struct-field-attributes.md (100%) rename src/doc/unstable-book/src/{ => language-features}/structural-match.md (100%) rename src/doc/unstable-book/src/{ => language-features}/target-feature.md (100%) rename src/doc/unstable-book/src/{ => language-features}/thread-local.md (100%) rename src/doc/unstable-book/src/{ => language-features}/trace-macros.md (100%) rename src/doc/unstable-book/src/{ => language-features}/type-ascription.md (100%) rename src/doc/unstable-book/src/{ => language-features}/unboxed-closures.md (100%) rename src/doc/unstable-book/src/{ => language-features}/untagged-unions.md (100%) rename src/doc/unstable-book/src/{ => language-features}/unwind-attributes.md (100%) rename src/doc/unstable-book/src/{ => language-features}/use-extern-macros.md (100%) rename src/doc/unstable-book/src/{ => language-features}/used.md (100%) create mode 100644 src/doc/unstable-book/src/library-features.md rename src/doc/unstable-book/src/{ => library-features}/alloc-jemalloc.md (100%) rename src/doc/unstable-book/src/{ => library-features}/alloc-system.md (100%) rename src/doc/unstable-book/src/{ => library-features}/alloc.md (100%) rename src/doc/unstable-book/src/{ => library-features}/as-c-str.md (100%) rename src/doc/unstable-book/src/{ => library-features}/as-unsafe-cell.md (100%) rename src/doc/unstable-book/src/{ => library-features}/ascii-ctype.md (100%) rename src/doc/unstable-book/src/{ => library-features}/binary-heap-extras.md (100%) rename src/doc/unstable-book/src/{ => library-features}/binary-heap-peek-mut-pop.md (100%) rename src/doc/unstable-book/src/{ => library-features}/borrow-state.md (100%) rename src/doc/unstable-book/src/{ => library-features}/box-heap.md (100%) rename src/doc/unstable-book/src/{ => library-features}/c-void-variant.md (100%) rename src/doc/unstable-book/src/{ => library-features}/char-escape-debug.md (100%) rename src/doc/unstable-book/src/{ => library-features}/coerce-unsized.md (100%) rename src/doc/unstable-book/src/{ => library-features}/collection-placement.md (100%) rename src/doc/unstable-book/src/{ => library-features}/collections-range.md (100%) rename src/doc/unstable-book/src/{ => library-features}/collections.md (100%) rename src/doc/unstable-book/src/{ => library-features}/command-envs.md (100%) rename src/doc/unstable-book/src/{ => library-features}/compiler-builtins-lib.md (100%) rename src/doc/unstable-book/src/{ => library-features}/compiler-fences.md (100%) rename src/doc/unstable-book/src/{ => library-features}/concat-idents-macro.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-char-ext.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-float.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-intrinsics.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-panic.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-private-bignum.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-private-diy-float.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-slice-ext.md (100%) rename src/doc/unstable-book/src/{ => library-features}/core-str-ext.md (100%) rename src/doc/unstable-book/src/{ => library-features}/dec2flt.md (100%) rename src/doc/unstable-book/src/{ => library-features}/decode-utf8.md (100%) rename src/doc/unstable-book/src/{ => library-features}/derive-clone-copy.md (100%) rename src/doc/unstable-book/src/{ => library-features}/derive-eq.md (100%) rename src/doc/unstable-book/src/{ => library-features}/discriminant-value.md (100%) rename src/doc/unstable-book/src/{ => library-features}/enumset.md (100%) rename src/doc/unstable-book/src/{ => library-features}/error-type-id.md (100%) rename src/doc/unstable-book/src/{ => library-features}/exact-size-is-empty.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fd-read.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fd.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fixed-size-array.md (100%) rename src/doc/unstable-book/src/{ => library-features}/float-bits-conv.md (100%) rename src/doc/unstable-book/src/{ => library-features}/float-extras.md (100%) rename src/doc/unstable-book/src/{ => library-features}/flt2dec.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fmt-flags-align.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fmt-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fn-traits.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fnbox.md (100%) rename src/doc/unstable-book/src/{ => library-features}/from_utf8_error_as_bytes.md (100%) rename src/doc/unstable-book/src/{ => library-features}/fused.md (100%) rename src/doc/unstable-book/src/{ => library-features}/future-atomic-orderings.md (100%) rename src/doc/unstable-book/src/{ => library-features}/get-type-id.md (100%) rename src/doc/unstable-book/src/{ => library-features}/heap-api.md (100%) rename src/doc/unstable-book/src/{ => library-features}/i128.md (100%) rename src/doc/unstable-book/src/{ => library-features}/inclusive-range.md (100%) rename src/doc/unstable-book/src/{ => library-features}/int-error-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/integer-atomics.md (100%) rename src/doc/unstable-book/src/{ => library-features}/into-boxed-c-str.md (100%) rename src/doc/unstable-book/src/{ => library-features}/into-boxed-os-str.md (100%) rename src/doc/unstable-book/src/{ => library-features}/into-boxed-path.md (100%) rename src/doc/unstable-book/src/{ => library-features}/io-error-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/io.md (100%) rename src/doc/unstable-book/src/{ => library-features}/ip.md (100%) rename src/doc/unstable-book/src/{ => library-features}/is-unique.md (100%) rename src/doc/unstable-book/src/{ => library-features}/iter-rfind.md (100%) rename src/doc/unstable-book/src/{ => library-features}/libstd-io-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/libstd-sys-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/libstd-thread-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/linked-list-extras.md (100%) rename src/doc/unstable-book/src/{ => library-features}/lookup-host.md (100%) rename src/doc/unstable-book/src/{ => library-features}/manually-drop.md (100%) rename src/doc/unstable-book/src/{ => library-features}/map-entry-recover-keys.md (100%) rename src/doc/unstable-book/src/{ => library-features}/mpsc-select.md (100%) rename src/doc/unstable-book/src/{ => library-features}/n16.md (100%) rename src/doc/unstable-book/src/{ => library-features}/never-type-impls.md (100%) rename src/doc/unstable-book/src/{ => library-features}/nonzero.md (100%) rename src/doc/unstable-book/src/{ => library-features}/offset-to.md (100%) rename src/doc/unstable-book/src/{ => library-features}/once-poison.md (100%) rename src/doc/unstable-book/src/{ => library-features}/oom.md (100%) rename src/doc/unstable-book/src/{ => library-features}/option-entry.md (100%) rename src/doc/unstable-book/src/{ => library-features}/osstring-shrink-to-fit.md (100%) rename src/doc/unstable-book/src/{ => library-features}/panic-abort.md (100%) rename src/doc/unstable-book/src/{ => library-features}/panic-unwind.md (100%) rename src/doc/unstable-book/src/{ => library-features}/pattern.md (100%) rename src/doc/unstable-book/src/{ => library-features}/peek.md (100%) rename src/doc/unstable-book/src/{ => library-features}/placement-in.md (100%) rename src/doc/unstable-book/src/{ => library-features}/placement-new-protocol.md (100%) rename src/doc/unstable-book/src/{ => library-features}/print.md (100%) rename src/doc/unstable-book/src/{ => library-features}/proc-macro-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/process-try-wait.md (100%) rename src/doc/unstable-book/src/{ => library-features}/question-mark-carrier.md (100%) rename src/doc/unstable-book/src/{ => library-features}/rand.md (100%) rename src/doc/unstable-book/src/{ => library-features}/range-contains.md (100%) rename src/doc/unstable-book/src/{ => library-features}/raw.md (100%) rename src/doc/unstable-book/src/{ => library-features}/rc-would-unwrap.md (100%) rename src/doc/unstable-book/src/{ => library-features}/retain-hash-collection.md (100%) rename src/doc/unstable-book/src/{ => library-features}/reverse-cmp-key.md (100%) rename src/doc/unstable-book/src/{ => library-features}/rt.md (100%) rename src/doc/unstable-book/src/{ => library-features}/rustc-private.md (100%) rename src/doc/unstable-book/src/{ => library-features}/sanitizer-runtime-lib.md (100%) rename src/doc/unstable-book/src/{ => library-features}/set-stdio.md (100%) rename src/doc/unstable-book/src/{ => library-features}/shared.md (100%) rename src/doc/unstable-book/src/{ => library-features}/sip-hash-13.md (100%) rename src/doc/unstable-book/src/{ => library-features}/slice-concat-ext.md (100%) rename src/doc/unstable-book/src/{ => library-features}/slice-get-slice.md (100%) rename src/doc/unstable-book/src/{ => library-features}/slice-rsplit.md (100%) rename src/doc/unstable-book/src/{ => library-features}/sort-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/sort-unstable.md (100%) rename src/doc/unstable-book/src/{ => library-features}/step-by.md (100%) rename src/doc/unstable-book/src/{ => library-features}/step-trait.md (100%) rename src/doc/unstable-book/src/{ => library-features}/str-checked-slicing.md (100%) rename src/doc/unstable-book/src/{ => library-features}/str-escape.md (100%) rename src/doc/unstable-book/src/{ => library-features}/str-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/str-mut-extras.md (100%) rename src/doc/unstable-book/src/{ => library-features}/test.md (100%) rename src/doc/unstable-book/src/{ => library-features}/thread-id.md (100%) rename src/doc/unstable-book/src/{ => library-features}/thread-local-internals.md (100%) rename src/doc/unstable-book/src/{ => library-features}/thread-local-state.md (100%) rename src/doc/unstable-book/src/{ => library-features}/toowned-clone-into.md (100%) rename src/doc/unstable-book/src/{ => library-features}/trusted-len.md (100%) rename src/doc/unstable-book/src/{ => library-features}/try-from.md (100%) rename src/doc/unstable-book/src/{ => library-features}/unicode.md (100%) rename src/doc/unstable-book/src/{ => library-features}/unique.md (100%) rename src/doc/unstable-book/src/{ => library-features}/unsize.md (100%) rename src/doc/unstable-book/src/{ => library-features}/update-panic-count.md (100%) rename src/doc/unstable-book/src/{ => library-features}/utf8-error-error-len.md (100%) rename src/doc/unstable-book/src/{ => library-features}/vec-remove-item.md (100%) rename src/doc/unstable-book/src/{ => library-features}/windows-c.md (100%) rename src/doc/unstable-book/src/{ => library-features}/windows-handle.md (100%) rename src/doc/unstable-book/src/{ => library-features}/windows-net.md (100%) rename src/doc/unstable-book/src/{ => library-features}/windows-stdio.md (100%) rename src/doc/unstable-book/src/{ => library-features}/zero-one.md (100%) diff --git a/src/Cargo.lock b/src/Cargo.lock index 62b853480394..26c7dc3ce972 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -922,9 +922,6 @@ dependencies = [ [[package]] name = "tidy" version = "0.1.0" -dependencies = [ - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "toml" diff --git a/src/doc/guide-plugins.md b/src/doc/guide-plugins.md index 1ba28c0117db..6c511548789b 100644 --- a/src/doc/guide-plugins.md +++ b/src/doc/guide-plugins.md @@ -1,4 +1,4 @@ % The (old) Rust Compiler Plugins Guide This content has moved into -[the Unstable Book](unstable-book/plugin.html). +[the Unstable Book](unstable-book/language-features/plugin.html). diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 36999eb143ff..3e0415439774 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -1,226 +1,228 @@ [The Unstable Book](the-unstable-book.md) -- [abi_msp430_interrupt](abi-msp430-interrupt.md) -- [abi_ptx](abi-ptx.md) -- [abi_sysv64](abi-sysv64.md) -- [abi_unadjusted](abi-unadjusted.md) -- [abi_vectorcall](abi-vectorcall.md) -- [abi_x86_interrupt](abi-x86-interrupt.md) -- [advanced_slice_patterns](advanced-slice-patterns.md) -- [alloc](alloc.md) -- [alloc_jemalloc](alloc-jemalloc.md) -- [alloc_system](alloc-system.md) -- [allocator](allocator.md) -- [allow_internal_unstable](allow-internal-unstable.md) -- [as_c_str](as-c-str.md) -- [as_unsafe_cell](as-unsafe-cell.md) -- [ascii_ctype](ascii-ctype.md) -- [asm](asm.md) -- [associated_consts](associated-consts.md) -- [associated_type_defaults](associated-type-defaults.md) -- [attr_literals](attr-literals.md) -- [binary_heap_extras](binary-heap-extras.md) -- [binary_heap_peek_mut_pop](binary-heap-peek-mut-pop.md) -- [borrow_state](borrow-state.md) -- [box_heap](box-heap.md) -- [box_patterns](box-patterns.md) -- [box_syntax](box-syntax.md) -- [c_void_variant](c-void-variant.md) -- [catch_expr](catch-expr.md) -- [cfg_target_feature](cfg-target-feature.md) -- [cfg_target_has_atomic](cfg-target-has-atomic.md) -- [cfg_target_thread_local](cfg-target-thread-local.md) -- [cfg_target_vendor](cfg-target-vendor.md) -- [char_escape_debug](char-escape-debug.md) -- [closure_to_fn_coercion](closure-to-fn-coercion.md) -- [coerce_unsized](coerce-unsized.md) -- [collection_placement](collection-placement.md) -- [collections](collections.md) -- [collections_range](collections-range.md) -- [command_envs](command-envs.md) -- [compiler_fences](compiler-fences.md) -- [compiler_builtins](compiler-builtins.md) -- [compiler_builtins_lib](compiler-builtins-lib.md) -- [concat_idents](concat-idents.md) -- [concat_idents_macro](concat-idents-macro.md) -- [conservative_impl_trait](conservative-impl-trait.md) -- [const_fn](const-fn.md) -- [const_indexing](const-indexing.md) -- [core_char_ext](core-char-ext.md) -- [core_float](core-float.md) -- [core_intrinsics](core-intrinsics.md) -- [core_panic](core-panic.md) -- [core_private_bignum](core-private-bignum.md) -- [core_private_diy_float](core-private-diy-float.md) -- [core_slice_ext](core-slice-ext.md) -- [core_str_ext](core-str-ext.md) -- [custom_attribute](custom-attribute.md) -- [custom_derive](custom-derive.md) -- [dec2flt](dec2flt.md) -- [decode_utf8](decode-utf8.md) -- [default_type_parameter_fallback](default-type-parameter-fallback.md) -- [derive_clone_copy](derive-clone-copy.md) -- [derive_eq](derive-eq.md) -- [discriminant_value](discriminant-value.md) -- [drop_types_in_const](drop-types-in-const.md) -- [dropck_eyepatch](dropck-eyepatch.md) -- [dropck_parametricity](dropck-parametricity.md) -- [enumset](enumset.md) -- [error_type_id](error-type-id.md) -- [exact_size_is_empty](exact-size-is-empty.md) -- [exclusive_range_pattern](exclusive-range-pattern.md) -- [fd](fd.md) -- [fd_read](fd-read.md) -- [fixed_size_array](fixed-size-array.md) -- [float_bits_conv](float-bits-conv.md) -- [float_extras](float-extras.md) -- [flt2dec](flt2dec.md) -- [fmt_flags_align](fmt-flags-align.md) -- [fmt_internals](fmt-internals.md) -- [fn_traits](fn-traits.md) -- [fnbox](fnbox.md) -- [from_utf8_error_as_bytes](from_utf8_error_as_bytes.md) -- [fundamental](fundamental.md) -- [fused](fused.md) -- [future_atomic_orderings](future-atomic-orderings.md) -- [generic_param_attrs](generic-param-attrs.md) -- [get_type_id](get-type-id.md) -- [global_asm](global_asm.md) -- [heap_api](heap-api.md) -- [i128](i128.md) -- [i128_type](i128-type.md) -- [inclusive_range](inclusive-range.md) -- [inclusive_range_syntax](inclusive-range-syntax.md) -- [int_error_internals](int-error-internals.md) -- [integer_atomics](integer-atomics.md) -- [into_boxed_c_str](into-boxed-c-str.md) -- [into_boxed_os_str](into-boxed-os-str.md) -- [into_boxed_path](into-boxed-path.md) -- [intrinsics](intrinsics.md) -- [io](io.md) -- [io_error_internals](io-error-internals.md) -- [ip](ip.md) -- [is_unique](is-unique.md) -- [iter_rfind](iter-rfind.md) -- [lang_items](lang-items.md) -- [libstd_io_internals](libstd-io-internals.md) -- [libstd_sys_internals](libstd-sys-internals.md) -- [libstd_thread_internals](libstd-thread-internals.md) -- [link_args](link-args.md) -- [link_cfg](link-cfg.md) -- [link_llvm_intrinsics](link-llvm-intrinsics.md) -- [linkage](linkage.md) -- [linked_list_extras](linked-list-extras.md) -- [linker_flavor](linker-flavor.md) -- [log_syntax](log-syntax.md) -- [lookup_host](lookup-host.md) -- [loop_break_value](loop-break-value.md) -- [macro_reexport](macro-reexport.md) -- [macro_vis_matcher](macro-vis-matcher.md) -- [main](main.md) -- [manually_drop](manually-drop.md) -- [map_entry_recover_keys](map-entry-recover-keys.md) -- [mpsc_select](mpsc-select.md) -- [n16](n16.md) -- [naked_functions](naked-functions.md) -- [needs_allocator](needs-allocator.md) -- [needs_panic_runtime](needs-panic-runtime.md) -- [never_type](never-type.md) -- [never_type_impls](never-type-impls.md) -- [no_core](no-core.md) -- [no_debug](no-debug.md) -- [non_ascii_idents](non-ascii-idents.md) -- [nonzero](nonzero.md) -- [offset_to](offset-to.md) -- [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md) -- [on_unimplemented](on-unimplemented.md) -- [once_poison](once-poison.md) -- [oom](oom.md) -- [optin_builtin_traits](optin-builtin-traits.md) -- [option_entry](option-entry.md) -- [osstring_shrink_to_fit](osstring-shrink-to-fit.md) -- [overlapping_marker_traits](overlapping-marker-traits.md) -- [panic_abort](panic-abort.md) -- [panic_runtime](panic-runtime.md) -- [panic_unwind](panic-unwind.md) -- [pattern](pattern.md) -- [peek](peek.md) -- [placement_in](placement-in.md) -- [placement_in_syntax](placement-in-syntax.md) -- [placement_new_protocol](placement-new-protocol.md) -- [platform_intrinsics](platform-intrinsics.md) -- [plugin](plugin.md) -- [plugin_registrar](plugin-registrar.md) -- [prelude_import](prelude-import.md) -- [print](print.md) -- [proc_macro](proc-macro.md) -- [proc_macro_internals](proc-macro-internals.md) -- [process_try_wait](process-try-wait.md) -- [question_mark_carrier](question-mark-carrier.md) -- [quote](quote.md) -- [rand](rand.md) -- [range_contains](range-contains.md) -- [raw](raw.md) -- [rc_would_unwrap](rc-would-unwrap.md) -- [relaxed_adts](relaxed-adts.md) -- [repr_simd](repr-simd.md) -- [retain_hash_collection](retain-hash-collection.md) -- [reverse_cmp_key](reverse-cmp-key.md) -- [rt](rt.md) -- [rustc_attrs](rustc-attrs.md) -- [rustc_diagnostic_macros](rustc-diagnostic-macros.md) -- [rustc_private](rustc-private.md) -- [rvalue_static_promotion](rvalue-static-promotion.md) -- [sanitizer_runtime](sanitizer-runtime.md) -- [sanitizer_runtime_lib](sanitizer-runtime-lib.md) -- [set_stdio](set-stdio.md) -- [shared](shared.md) -- [simd](simd.md) -- [simd_ffi](simd-ffi.md) -- [sip_hash_13](sip-hash-13.md) -- [slice_concat_ext](slice-concat-ext.md) -- [slice_get_slice](slice-get-slice.md) -- [slice_patterns](slice-patterns.md) -- [slice_rsplit](slice-rsplit.md) -- [sort_internals](sort-internals.md) -- [sort_unstable](sort-unstable.md) -- [specialization](specialization.md) -- [staged_api](staged-api.md) -- [start](start.md) -- [static_nobundle](static-nobundle.md) -- [step_by](step-by.md) -- [step_trait](step-trait.md) -- [stmt_expr_attributes](stmt-expr-attributes.md) -- [str_checked_slicing](str-checked-slicing.md) -- [str_escape](str-escape.md) -- [str_internals](str-internals.md) -- [str_mut_extras](str-mut-extras.md) -- [struct_field_attributes](struct-field-attributes.md) -- [structural_match](structural-match.md) -- [target_feature](target-feature.md) -- [test](test.md) -- [thread_id](thread-id.md) -- [thread_local](thread-local.md) -- [thread_local_internals](thread-local-internals.md) -- [thread_local_state](thread-local-state.md) -- [toowned_clone_into](toowned-clone-into.md) -- [trace_macros](trace-macros.md) -- [trusted_len](trusted-len.md) -- [try_from](try-from.md) -- [type_ascription](type-ascription.md) -- [unboxed_closures](unboxed-closures.md) -- [unicode](unicode.md) -- [unique](unique.md) -- [unsize](unsize.md) -- [untagged_unions](untagged-unions.md) -- [unwind_attributes](unwind-attributes.md) -- [update_panic_count](update-panic-count.md) -- [use_extern_macros](use-extern-macros.md) -- [used](used.md) -- [utf8_error_error_len](utf8-error-error-len.md) -- [vec_remove_item](vec-remove-item.md) -- [windows_c](windows-c.md) -- [windows_handle](windows-handle.md) -- [windows_net](windows-net.md) -- [windows_stdio](windows-stdio.md) -- [zero_one](zero-one.md) +- [Compiler flags](compiler-flags.md) + - [linker_flavor](compiler-flags/linker-flavor.md) +- [Language features](language-features.md) + - [abi_msp430_interrupt](language-features/abi-msp430-interrupt.md) + - [abi_ptx](language-features/abi-ptx.md) + - [abi_sysv64](language-features/abi-sysv64.md) + - [abi_unadjusted](language-features/abi-unadjusted.md) + - [abi_vectorcall](language-features/abi-vectorcall.md) + - [abi_x86_interrupt](language-features/abi-x86-interrupt.md) + - [advanced_slice_patterns](language-features/advanced-slice-patterns.md) + - [allocator](language-features/allocator.md) + - [allow_internal_unstable](language-features/allow-internal-unstable.md) + - [asm](language-features/asm.md) + - [associated_consts](language-features/associated-consts.md) + - [associated_type_defaults](language-features/associated-type-defaults.md) + - [attr_literals](language-features/attr-literals.md) + - [box_patterns](language-features/box-patterns.md) + - [box_syntax](language-features/box-syntax.md) + - [catch_expr](language-features/catch-expr.md) + - [cfg_target_feature](language-features/cfg-target-feature.md) + - [cfg_target_has_atomic](language-features/cfg-target-has-atomic.md) + - [cfg_target_thread_local](language-features/cfg-target-thread-local.md) + - [cfg_target_vendor](language-features/cfg-target-vendor.md) + - [closure_to_fn_coercion](language-features/closure-to-fn-coercion.md) + - [compiler_builtins](language-features/compiler-builtins.md) + - [concat_idents](language-features/concat-idents.md) + - [conservative_impl_trait](language-features/conservative-impl-trait.md) + - [const_fn](language-features/const-fn.md) + - [const_indexing](language-features/const-indexing.md) + - [custom_attribute](language-features/custom-attribute.md) + - [custom_derive](language-features/custom-derive.md) + - [default_type_parameter_fallback](language-features/default-type-parameter-fallback.md) + - [drop_types_in_const](language-features/drop-types-in-const.md) + - [dropck_eyepatch](language-features/dropck-eyepatch.md) + - [dropck_parametricity](language-features/dropck-parametricity.md) + - [exclusive_range_pattern](language-features/exclusive-range-pattern.md) + - [fundamental](language-features/fundamental.md) + - [generic_param_attrs](language-features/generic-param-attrs.md) + - [global_asm](language-features/global_asm.md) + - [i128_type](language-features/i128-type.md) + - [inclusive_range_syntax](language-features/inclusive-range-syntax.md) + - [intrinsics](language-features/intrinsics.md) + - [lang_items](language-features/lang-items.md) + - [link_args](language-features/link-args.md) + - [link_cfg](language-features/link-cfg.md) + - [link_llvm_intrinsics](language-features/link-llvm-intrinsics.md) + - [linkage](language-features/linkage.md) + - [log_syntax](language-features/log-syntax.md) + - [loop_break_value](language-features/loop-break-value.md) + - [macro_reexport](language-features/macro-reexport.md) + - [macro_vis_matcher](language-features/macro-vis-matcher.md) + - [main](language-features/main.md) + - [naked_functions](language-features/naked-functions.md) + - [needs_allocator](language-features/needs-allocator.md) + - [needs_panic_runtime](language-features/needs-panic-runtime.md) + - [never_type](language-features/never-type.md) + - [no_core](language-features/no-core.md) + - [no_debug](language-features/no-debug.md) + - [non_ascii_idents](language-features/non-ascii-idents.md) + - [omit_gdb_pretty_printer_section](language-features/omit-gdb-pretty-printer-section.md) + - [on_unimplemented](language-features/on-unimplemented.md) + - [optin_builtin_traits](language-features/optin-builtin-traits.md) + - [overlapping_marker_traits](language-features/overlapping-marker-traits.md) + - [panic_runtime](language-features/panic-runtime.md) + - [placement_in_syntax](language-features/placement-in-syntax.md) + - [platform_intrinsics](language-features/platform-intrinsics.md) + - [plugin](language-features/plugin.md) + - [plugin_registrar](language-features/plugin-registrar.md) + - [prelude_import](language-features/prelude-import.md) + - [proc_macro](language-features/proc-macro.md) + - [quote](language-features/quote.md) + - [relaxed_adts](language-features/relaxed-adts.md) + - [repr_simd](language-features/repr-simd.md) + - [rustc_attrs](language-features/rustc-attrs.md) + - [rustc_diagnostic_macros](language-features/rustc-diagnostic-macros.md) + - [rvalue_static_promotion](language-features/rvalue-static-promotion.md) + - [sanitizer_runtime](language-features/sanitizer-runtime.md) + - [simd](language-features/simd.md) + - [simd_ffi](language-features/simd-ffi.md) + - [slice_patterns](language-features/slice-patterns.md) + - [specialization](language-features/specialization.md) + - [staged_api](language-features/staged-api.md) + - [start](language-features/start.md) + - [static_nobundle](language-features/static-nobundle.md) + - [stmt_expr_attributes](language-features/stmt-expr-attributes.md) + - [struct_field_attributes](language-features/struct-field-attributes.md) + - [structural_match](language-features/structural-match.md) + - [target_feature](language-features/target-feature.md) + - [thread_local](language-features/thread-local.md) + - [trace_macros](language-features/trace-macros.md) + - [type_ascription](language-features/type-ascription.md) + - [unboxed_closures](language-features/unboxed-closures.md) + - [untagged_unions](language-features/untagged-unions.md) + - [unwind_attributes](language-features/unwind-attributes.md) + - [use_extern_macros](language-features/use-extern-macros.md) + - [used](language-features/used.md) +- [Library Features](library-features.md) + - [alloc_jemalloc](library-features/alloc-jemalloc.md) + - [alloc_system](library-features/alloc-system.md) + - [alloc](library-features/alloc.md) + - [as_c_str](library-features/as-c-str.md) + - [as_unsafe_cell](library-features/as-unsafe-cell.md) + - [ascii_ctype](library-features/ascii-ctype.md) + - [binary_heap_extras](library-features/binary-heap-extras.md) + - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md) + - [borrow_state](library-features/borrow-state.md) + - [box_heap](library-features/box-heap.md) + - [c_void_variant](library-features/c-void-variant.md) + - [char_escape_debug](library-features/char-escape-debug.md) + - [coerce_unsized](library-features/coerce-unsized.md) + - [collection_placement](library-features/collection-placement.md) + - [collections_range](library-features/collections-range.md) + - [collections](library-features/collections.md) + - [command_envs](library-features/command-envs.md) + - [compiler_builtins_lib](library-features/compiler-builtins-lib.md) + - [compiler_fences](library-features/compiler-fences.md) + - [concat_idents_macro](library-features/concat-idents-macro.md) + - [core_char_ext](library-features/core-char-ext.md) + - [core_float](library-features/core-float.md) + - [core_intrinsics](library-features/core-intrinsics.md) + - [core_panic](library-features/core-panic.md) + - [core_private_bignum](library-features/core-private-bignum.md) + - [core_private_diy_float](library-features/core-private-diy-float.md) + - [core_slice_ext](library-features/core-slice-ext.md) + - [core_str_ext](library-features/core-str-ext.md) + - [dec2flt](library-features/dec2flt.md) + - [decode_utf8](library-features/decode-utf8.md) + - [derive_clone_copy](library-features/derive-clone-copy.md) + - [derive_eq](library-features/derive-eq.md) + - [discriminant_value](library-features/discriminant-value.md) + - [enumset](library-features/enumset.md) + - [error_type_id](library-features/error-type-id.md) + - [exact_size_is_empty](library-features/exact-size-is-empty.md) + - [fd](library-features/fd.md) + - [fd_read](library-features/fd-read.md) + - [fixed_size_array](library-features/fixed-size-array.md) + - [float_bits_conv](library-features/float-bits-conv.md) + - [float_extras](library-features/float-extras.md) + - [flt2dec](library-features/flt2dec.md) + - [fmt_flags_align](library-features/fmt-flags-align.md) + - [fmt_internals](library-features/fmt-internals.md) + - [fn_traits](library-features/fn-traits.md) + - [fnbox](library-features/fnbox.md) + - [from_utf8_error_as_bytes](library-features/from_utf8_error_as_bytes.md) + - [fused](library-features/fused.md) + - [future_atomic_orderings](library-features/future-atomic-orderings.md) + - [get_type_id](library-features/get-type-id.md) + - [heap_api](library-features/heap-api.md) + - [i128](library-features/i128.md) + - [inclusive_range](library-features/inclusive-range.md) + - [integer_atomics](library-features/integer-atomics.md) + - [into_boxed_c_str](library-features/into-boxed-c-str.md) + - [into_boxed_os_str](library-features/into-boxed-os-str.md) + - [into_boxed_path](library-features/into-boxed-path.md) + - [io_error_internals](library-features/io-error-internals.md) + - [io](library-features/io.md) + - [ip](library-features/ip.md) + - [is_unique](library-features/is-unique.md) + - [iter_rfind](library-features/iter-rfind.md) + - [libstd_io_internals](library-features/libstd-io-internals.md) + - [libstd_sys_internals](library-features/libstd-sys-internals.md) + - [libstd_thread_internals](library-features/libstd-thread-internals.md) + - [linked_list_extras](library-features/linked-list-extras.md) + - [lookup_host](library-features/lookup-host.md) + - [manually_drop](library-features/manually-drop.md) + - [map_entry_recover_keys](library-features/map-entry-recover-keys.md) + - [mpsc_select](library-features/mpsc-select.md) + - [n16](library-features/n16.md) + - [never_type_impls](library-features/never-type-impls.md) + - [nonzero](library-features/nonzero.md) + - [offset_to](library-features/offset-to.md) + - [once_poison](library-features/once-poison.md) + - [oom](library-features/oom.md) + - [option_entry](library-features/option-entry.md) + - [osstring_shrink_to_fit](library-features/osstring-shrink-to-fit.md) + - [panic_abort](library-features/panic-abort.md) + - [panic_unwind](library-features/panic-unwind.md) + - [pattern](library-features/pattern.md) + - [peek](library-features/peek.md) + - [placement_in](library-features/placement-in.md) + - [placement_new_protocol](library-features/placement-new-protocol.md) + - [print](library-features/print.md) + - [proc_macro_internals](library-features/proc-macro-internals.md) + - [process_try_wait](library-features/process-try-wait.md) + - [question_mark_carrier](library-features/question-mark-carrier.md) + - [rand](library-features/rand.md) + - [range_contains](library-features/range-contains.md) + - [raw](library-features/raw.md) + - [rc_would_unwrap](library-features/rc-would-unwrap.md) + - [retain_hash_collection](library-features/retain-hash-collection.md) + - [reverse_cmp_key](library-features/reverse-cmp-key.md) + - [rt](library-features/rt.md) + - [rustc_private](library-features/rustc-private.md) + - [sanitizer_runtime_lib](library-features/sanitizer-runtime-lib.md) + - [set_stdio](library-features/set-stdio.md) + - [shared](library-features/shared.md) + - [sip_hash_13](library-features/sip-hash-13.md) + - [slice_concat_ext](library-features/slice-concat-ext.md) + - [slice_get_slice](library-features/slice-get-slice.md) + - [slice_rsplit](library-features/slice-rsplit.md) + - [sort_internals](library-features/sort-internals.md) + - [sort_unstable](library-features/sort-unstable.md) + - [step_by](library-features/step-by.md) + - [step_trait](library-features/step-trait.md) + - [str_checked_slicing](library-features/str-checked-slicing.md) + - [str_escape](library-features/str-escape.md) + - [str_internals](library-features/str-internals.md) + - [str_mut_extras](library-features/str-mut-extras.md) + - [test](library-features/test.md) + - [thread_id](library-features/thread-id.md) + - [thread_local_internals](library-features/thread-local-internals.md) + - [thread_local_state](library-features/thread-local-state.md) + - [toowned_clone_into](library-features/toowned-clone-into.md) + - [trusted_len](library-features/trusted-len.md) + - [try_from](library-features/try-from.md) + - [unicode](library-features/unicode.md) + - [unique](library-features/unique.md) + - [unsize](library-features/unsize.md) + - [utf8_error_error_len](library-features/utf8-error-error-len.md) + - [vec_remove_item](library-features/vec-remove-item.md) + - [windows_c](library-features/windows-c.md) + - [windows_handle](library-features/windows-handle.md) + - [windows_net](library-features/windows-net.md) + - [windows_stdio](library-features/windows-stdio.md) + - [zero_one](library-features/zero-one.md) +>>>>>> Add top level sections to the Unstable Book. diff --git a/src/doc/unstable-book/src/compiler-flags.md b/src/doc/unstable-book/src/compiler-flags.md new file mode 100644 index 000000000000..43eadb351016 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags.md @@ -0,0 +1 @@ +# Compiler flags diff --git a/src/doc/unstable-book/src/linker-flavor.md b/src/doc/unstable-book/src/compiler-flags/linker-flavor.md similarity index 100% rename from src/doc/unstable-book/src/linker-flavor.md rename to src/doc/unstable-book/src/compiler-flags/linker-flavor.md diff --git a/src/doc/unstable-book/src/language-features.md b/src/doc/unstable-book/src/language-features.md new file mode 100644 index 000000000000..a27514df97d6 --- /dev/null +++ b/src/doc/unstable-book/src/language-features.md @@ -0,0 +1 @@ +# Language features diff --git a/src/doc/unstable-book/src/abi-msp430-interrupt.md b/src/doc/unstable-book/src/language-features/abi-msp430-interrupt.md similarity index 100% rename from src/doc/unstable-book/src/abi-msp430-interrupt.md rename to src/doc/unstable-book/src/language-features/abi-msp430-interrupt.md diff --git a/src/doc/unstable-book/src/abi-ptx.md b/src/doc/unstable-book/src/language-features/abi-ptx.md similarity index 100% rename from src/doc/unstable-book/src/abi-ptx.md rename to src/doc/unstable-book/src/language-features/abi-ptx.md diff --git a/src/doc/unstable-book/src/abi-sysv64.md b/src/doc/unstable-book/src/language-features/abi-sysv64.md similarity index 100% rename from src/doc/unstable-book/src/abi-sysv64.md rename to src/doc/unstable-book/src/language-features/abi-sysv64.md diff --git a/src/doc/unstable-book/src/abi-unadjusted.md b/src/doc/unstable-book/src/language-features/abi-unadjusted.md similarity index 100% rename from src/doc/unstable-book/src/abi-unadjusted.md rename to src/doc/unstable-book/src/language-features/abi-unadjusted.md diff --git a/src/doc/unstable-book/src/abi-vectorcall.md b/src/doc/unstable-book/src/language-features/abi-vectorcall.md similarity index 100% rename from src/doc/unstable-book/src/abi-vectorcall.md rename to src/doc/unstable-book/src/language-features/abi-vectorcall.md diff --git a/src/doc/unstable-book/src/abi-x86-interrupt.md b/src/doc/unstable-book/src/language-features/abi-x86-interrupt.md similarity index 100% rename from src/doc/unstable-book/src/abi-x86-interrupt.md rename to src/doc/unstable-book/src/language-features/abi-x86-interrupt.md diff --git a/src/doc/unstable-book/src/advanced-slice-patterns.md b/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md similarity index 100% rename from src/doc/unstable-book/src/advanced-slice-patterns.md rename to src/doc/unstable-book/src/language-features/advanced-slice-patterns.md diff --git a/src/doc/unstable-book/src/allocator.md b/src/doc/unstable-book/src/language-features/allocator.md similarity index 100% rename from src/doc/unstable-book/src/allocator.md rename to src/doc/unstable-book/src/language-features/allocator.md diff --git a/src/doc/unstable-book/src/allow-internal-unstable.md b/src/doc/unstable-book/src/language-features/allow-internal-unstable.md similarity index 100% rename from src/doc/unstable-book/src/allow-internal-unstable.md rename to src/doc/unstable-book/src/language-features/allow-internal-unstable.md diff --git a/src/doc/unstable-book/src/asm.md b/src/doc/unstable-book/src/language-features/asm.md similarity index 100% rename from src/doc/unstable-book/src/asm.md rename to src/doc/unstable-book/src/language-features/asm.md diff --git a/src/doc/unstable-book/src/associated-consts.md b/src/doc/unstable-book/src/language-features/associated-consts.md similarity index 100% rename from src/doc/unstable-book/src/associated-consts.md rename to src/doc/unstable-book/src/language-features/associated-consts.md diff --git a/src/doc/unstable-book/src/associated-type-defaults.md b/src/doc/unstable-book/src/language-features/associated-type-defaults.md similarity index 100% rename from src/doc/unstable-book/src/associated-type-defaults.md rename to src/doc/unstable-book/src/language-features/associated-type-defaults.md diff --git a/src/doc/unstable-book/src/attr-literals.md b/src/doc/unstable-book/src/language-features/attr-literals.md similarity index 100% rename from src/doc/unstable-book/src/attr-literals.md rename to src/doc/unstable-book/src/language-features/attr-literals.md diff --git a/src/doc/unstable-book/src/box-patterns.md b/src/doc/unstable-book/src/language-features/box-patterns.md similarity index 100% rename from src/doc/unstable-book/src/box-patterns.md rename to src/doc/unstable-book/src/language-features/box-patterns.md diff --git a/src/doc/unstable-book/src/box-syntax.md b/src/doc/unstable-book/src/language-features/box-syntax.md similarity index 100% rename from src/doc/unstable-book/src/box-syntax.md rename to src/doc/unstable-book/src/language-features/box-syntax.md diff --git a/src/doc/unstable-book/src/catch-expr.md b/src/doc/unstable-book/src/language-features/catch-expr.md similarity index 100% rename from src/doc/unstable-book/src/catch-expr.md rename to src/doc/unstable-book/src/language-features/catch-expr.md diff --git a/src/doc/unstable-book/src/cfg-target-feature.md b/src/doc/unstable-book/src/language-features/cfg-target-feature.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-feature.md rename to src/doc/unstable-book/src/language-features/cfg-target-feature.md diff --git a/src/doc/unstable-book/src/cfg-target-has-atomic.md b/src/doc/unstable-book/src/language-features/cfg-target-has-atomic.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-has-atomic.md rename to src/doc/unstable-book/src/language-features/cfg-target-has-atomic.md diff --git a/src/doc/unstable-book/src/cfg-target-thread-local.md b/src/doc/unstable-book/src/language-features/cfg-target-thread-local.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-thread-local.md rename to src/doc/unstable-book/src/language-features/cfg-target-thread-local.md diff --git a/src/doc/unstable-book/src/cfg-target-vendor.md b/src/doc/unstable-book/src/language-features/cfg-target-vendor.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-vendor.md rename to src/doc/unstable-book/src/language-features/cfg-target-vendor.md diff --git a/src/doc/unstable-book/src/closure-to-fn-coercion.md b/src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md similarity index 100% rename from src/doc/unstable-book/src/closure-to-fn-coercion.md rename to src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md diff --git a/src/doc/unstable-book/src/compiler-builtins.md b/src/doc/unstable-book/src/language-features/compiler-builtins.md similarity index 100% rename from src/doc/unstable-book/src/compiler-builtins.md rename to src/doc/unstable-book/src/language-features/compiler-builtins.md diff --git a/src/doc/unstable-book/src/concat-idents.md b/src/doc/unstable-book/src/language-features/concat-idents.md similarity index 100% rename from src/doc/unstable-book/src/concat-idents.md rename to src/doc/unstable-book/src/language-features/concat-idents.md diff --git a/src/doc/unstable-book/src/conservative-impl-trait.md b/src/doc/unstable-book/src/language-features/conservative-impl-trait.md similarity index 100% rename from src/doc/unstable-book/src/conservative-impl-trait.md rename to src/doc/unstable-book/src/language-features/conservative-impl-trait.md diff --git a/src/doc/unstable-book/src/const-fn.md b/src/doc/unstable-book/src/language-features/const-fn.md similarity index 100% rename from src/doc/unstable-book/src/const-fn.md rename to src/doc/unstable-book/src/language-features/const-fn.md diff --git a/src/doc/unstable-book/src/const-indexing.md b/src/doc/unstable-book/src/language-features/const-indexing.md similarity index 100% rename from src/doc/unstable-book/src/const-indexing.md rename to src/doc/unstable-book/src/language-features/const-indexing.md diff --git a/src/doc/unstable-book/src/custom-attribute.md b/src/doc/unstable-book/src/language-features/custom-attribute.md similarity index 100% rename from src/doc/unstable-book/src/custom-attribute.md rename to src/doc/unstable-book/src/language-features/custom-attribute.md diff --git a/src/doc/unstable-book/src/custom-derive.md b/src/doc/unstable-book/src/language-features/custom-derive.md similarity index 100% rename from src/doc/unstable-book/src/custom-derive.md rename to src/doc/unstable-book/src/language-features/custom-derive.md diff --git a/src/doc/unstable-book/src/default-type-parameter-fallback.md b/src/doc/unstable-book/src/language-features/default-type-parameter-fallback.md similarity index 100% rename from src/doc/unstable-book/src/default-type-parameter-fallback.md rename to src/doc/unstable-book/src/language-features/default-type-parameter-fallback.md diff --git a/src/doc/unstable-book/src/drop-types-in-const.md b/src/doc/unstable-book/src/language-features/drop-types-in-const.md similarity index 100% rename from src/doc/unstable-book/src/drop-types-in-const.md rename to src/doc/unstable-book/src/language-features/drop-types-in-const.md diff --git a/src/doc/unstable-book/src/dropck-eyepatch.md b/src/doc/unstable-book/src/language-features/dropck-eyepatch.md similarity index 100% rename from src/doc/unstable-book/src/dropck-eyepatch.md rename to src/doc/unstable-book/src/language-features/dropck-eyepatch.md diff --git a/src/doc/unstable-book/src/dropck-parametricity.md b/src/doc/unstable-book/src/language-features/dropck-parametricity.md similarity index 100% rename from src/doc/unstable-book/src/dropck-parametricity.md rename to src/doc/unstable-book/src/language-features/dropck-parametricity.md diff --git a/src/doc/unstable-book/src/exclusive-range-pattern.md b/src/doc/unstable-book/src/language-features/exclusive-range-pattern.md similarity index 100% rename from src/doc/unstable-book/src/exclusive-range-pattern.md rename to src/doc/unstable-book/src/language-features/exclusive-range-pattern.md diff --git a/src/doc/unstable-book/src/fundamental.md b/src/doc/unstable-book/src/language-features/fundamental.md similarity index 100% rename from src/doc/unstable-book/src/fundamental.md rename to src/doc/unstable-book/src/language-features/fundamental.md diff --git a/src/doc/unstable-book/src/generic-param-attrs.md b/src/doc/unstable-book/src/language-features/generic-param-attrs.md similarity index 100% rename from src/doc/unstable-book/src/generic-param-attrs.md rename to src/doc/unstable-book/src/language-features/generic-param-attrs.md diff --git a/src/doc/unstable-book/src/global_asm.md b/src/doc/unstable-book/src/language-features/global_asm.md similarity index 100% rename from src/doc/unstable-book/src/global_asm.md rename to src/doc/unstable-book/src/language-features/global_asm.md diff --git a/src/doc/unstable-book/src/i128-type.md b/src/doc/unstable-book/src/language-features/i128-type.md similarity index 100% rename from src/doc/unstable-book/src/i128-type.md rename to src/doc/unstable-book/src/language-features/i128-type.md diff --git a/src/doc/unstable-book/src/inclusive-range-syntax.md b/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md similarity index 100% rename from src/doc/unstable-book/src/inclusive-range-syntax.md rename to src/doc/unstable-book/src/language-features/inclusive-range-syntax.md diff --git a/src/doc/unstable-book/src/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md similarity index 100% rename from src/doc/unstable-book/src/intrinsics.md rename to src/doc/unstable-book/src/language-features/intrinsics.md diff --git a/src/doc/unstable-book/src/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md similarity index 100% rename from src/doc/unstable-book/src/lang-items.md rename to src/doc/unstable-book/src/language-features/lang-items.md diff --git a/src/doc/unstable-book/src/link-args.md b/src/doc/unstable-book/src/language-features/link-args.md similarity index 100% rename from src/doc/unstable-book/src/link-args.md rename to src/doc/unstable-book/src/language-features/link-args.md diff --git a/src/doc/unstable-book/src/link-cfg.md b/src/doc/unstable-book/src/language-features/link-cfg.md similarity index 100% rename from src/doc/unstable-book/src/link-cfg.md rename to src/doc/unstable-book/src/language-features/link-cfg.md diff --git a/src/doc/unstable-book/src/link-llvm-intrinsics.md b/src/doc/unstable-book/src/language-features/link-llvm-intrinsics.md similarity index 100% rename from src/doc/unstable-book/src/link-llvm-intrinsics.md rename to src/doc/unstable-book/src/language-features/link-llvm-intrinsics.md diff --git a/src/doc/unstable-book/src/linkage.md b/src/doc/unstable-book/src/language-features/linkage.md similarity index 100% rename from src/doc/unstable-book/src/linkage.md rename to src/doc/unstable-book/src/language-features/linkage.md diff --git a/src/doc/unstable-book/src/log-syntax.md b/src/doc/unstable-book/src/language-features/log-syntax.md similarity index 100% rename from src/doc/unstable-book/src/log-syntax.md rename to src/doc/unstable-book/src/language-features/log-syntax.md diff --git a/src/doc/unstable-book/src/loop-break-value.md b/src/doc/unstable-book/src/language-features/loop-break-value.md similarity index 100% rename from src/doc/unstable-book/src/loop-break-value.md rename to src/doc/unstable-book/src/language-features/loop-break-value.md diff --git a/src/doc/unstable-book/src/macro-reexport.md b/src/doc/unstable-book/src/language-features/macro-reexport.md similarity index 100% rename from src/doc/unstable-book/src/macro-reexport.md rename to src/doc/unstable-book/src/language-features/macro-reexport.md diff --git a/src/doc/unstable-book/src/macro-vis-matcher.md b/src/doc/unstable-book/src/language-features/macro-vis-matcher.md similarity index 100% rename from src/doc/unstable-book/src/macro-vis-matcher.md rename to src/doc/unstable-book/src/language-features/macro-vis-matcher.md diff --git a/src/doc/unstable-book/src/main.md b/src/doc/unstable-book/src/language-features/main.md similarity index 100% rename from src/doc/unstable-book/src/main.md rename to src/doc/unstable-book/src/language-features/main.md diff --git a/src/doc/unstable-book/src/naked-functions.md b/src/doc/unstable-book/src/language-features/naked-functions.md similarity index 100% rename from src/doc/unstable-book/src/naked-functions.md rename to src/doc/unstable-book/src/language-features/naked-functions.md diff --git a/src/doc/unstable-book/src/needs-allocator.md b/src/doc/unstable-book/src/language-features/needs-allocator.md similarity index 100% rename from src/doc/unstable-book/src/needs-allocator.md rename to src/doc/unstable-book/src/language-features/needs-allocator.md diff --git a/src/doc/unstable-book/src/needs-panic-runtime.md b/src/doc/unstable-book/src/language-features/needs-panic-runtime.md similarity index 100% rename from src/doc/unstable-book/src/needs-panic-runtime.md rename to src/doc/unstable-book/src/language-features/needs-panic-runtime.md diff --git a/src/doc/unstable-book/src/never-type.md b/src/doc/unstable-book/src/language-features/never-type.md similarity index 100% rename from src/doc/unstable-book/src/never-type.md rename to src/doc/unstable-book/src/language-features/never-type.md diff --git a/src/doc/unstable-book/src/no-core.md b/src/doc/unstable-book/src/language-features/no-core.md similarity index 100% rename from src/doc/unstable-book/src/no-core.md rename to src/doc/unstable-book/src/language-features/no-core.md diff --git a/src/doc/unstable-book/src/no-debug.md b/src/doc/unstable-book/src/language-features/no-debug.md similarity index 100% rename from src/doc/unstable-book/src/no-debug.md rename to src/doc/unstable-book/src/language-features/no-debug.md diff --git a/src/doc/unstable-book/src/non-ascii-idents.md b/src/doc/unstable-book/src/language-features/non-ascii-idents.md similarity index 100% rename from src/doc/unstable-book/src/non-ascii-idents.md rename to src/doc/unstable-book/src/language-features/non-ascii-idents.md diff --git a/src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md b/src/doc/unstable-book/src/language-features/omit-gdb-pretty-printer-section.md similarity index 100% rename from src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md rename to src/doc/unstable-book/src/language-features/omit-gdb-pretty-printer-section.md diff --git a/src/doc/unstable-book/src/on-unimplemented.md b/src/doc/unstable-book/src/language-features/on-unimplemented.md similarity index 100% rename from src/doc/unstable-book/src/on-unimplemented.md rename to src/doc/unstable-book/src/language-features/on-unimplemented.md diff --git a/src/doc/unstable-book/src/optin-builtin-traits.md b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md similarity index 100% rename from src/doc/unstable-book/src/optin-builtin-traits.md rename to src/doc/unstable-book/src/language-features/optin-builtin-traits.md diff --git a/src/doc/unstable-book/src/overlapping-marker-traits.md b/src/doc/unstable-book/src/language-features/overlapping-marker-traits.md similarity index 100% rename from src/doc/unstable-book/src/overlapping-marker-traits.md rename to src/doc/unstable-book/src/language-features/overlapping-marker-traits.md diff --git a/src/doc/unstable-book/src/panic-runtime.md b/src/doc/unstable-book/src/language-features/panic-runtime.md similarity index 100% rename from src/doc/unstable-book/src/panic-runtime.md rename to src/doc/unstable-book/src/language-features/panic-runtime.md diff --git a/src/doc/unstable-book/src/placement-in-syntax.md b/src/doc/unstable-book/src/language-features/placement-in-syntax.md similarity index 100% rename from src/doc/unstable-book/src/placement-in-syntax.md rename to src/doc/unstable-book/src/language-features/placement-in-syntax.md diff --git a/src/doc/unstable-book/src/platform-intrinsics.md b/src/doc/unstable-book/src/language-features/platform-intrinsics.md similarity index 100% rename from src/doc/unstable-book/src/platform-intrinsics.md rename to src/doc/unstable-book/src/language-features/platform-intrinsics.md diff --git a/src/doc/unstable-book/src/plugin-registrar.md b/src/doc/unstable-book/src/language-features/plugin-registrar.md similarity index 100% rename from src/doc/unstable-book/src/plugin-registrar.md rename to src/doc/unstable-book/src/language-features/plugin-registrar.md diff --git a/src/doc/unstable-book/src/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md similarity index 100% rename from src/doc/unstable-book/src/plugin.md rename to src/doc/unstable-book/src/language-features/plugin.md diff --git a/src/doc/unstable-book/src/prelude-import.md b/src/doc/unstable-book/src/language-features/prelude-import.md similarity index 100% rename from src/doc/unstable-book/src/prelude-import.md rename to src/doc/unstable-book/src/language-features/prelude-import.md diff --git a/src/doc/unstable-book/src/proc-macro.md b/src/doc/unstable-book/src/language-features/proc-macro.md similarity index 100% rename from src/doc/unstable-book/src/proc-macro.md rename to src/doc/unstable-book/src/language-features/proc-macro.md diff --git a/src/doc/unstable-book/src/quote.md b/src/doc/unstable-book/src/language-features/quote.md similarity index 100% rename from src/doc/unstable-book/src/quote.md rename to src/doc/unstable-book/src/language-features/quote.md diff --git a/src/doc/unstable-book/src/relaxed-adts.md b/src/doc/unstable-book/src/language-features/relaxed-adts.md similarity index 100% rename from src/doc/unstable-book/src/relaxed-adts.md rename to src/doc/unstable-book/src/language-features/relaxed-adts.md diff --git a/src/doc/unstable-book/src/repr-simd.md b/src/doc/unstable-book/src/language-features/repr-simd.md similarity index 100% rename from src/doc/unstable-book/src/repr-simd.md rename to src/doc/unstable-book/src/language-features/repr-simd.md diff --git a/src/doc/unstable-book/src/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md similarity index 100% rename from src/doc/unstable-book/src/rustc-attrs.md rename to src/doc/unstable-book/src/language-features/rustc-attrs.md diff --git a/src/doc/unstable-book/src/rustc-diagnostic-macros.md b/src/doc/unstable-book/src/language-features/rustc-diagnostic-macros.md similarity index 100% rename from src/doc/unstable-book/src/rustc-diagnostic-macros.md rename to src/doc/unstable-book/src/language-features/rustc-diagnostic-macros.md diff --git a/src/doc/unstable-book/src/rvalue-static-promotion.md b/src/doc/unstable-book/src/language-features/rvalue-static-promotion.md similarity index 100% rename from src/doc/unstable-book/src/rvalue-static-promotion.md rename to src/doc/unstable-book/src/language-features/rvalue-static-promotion.md diff --git a/src/doc/unstable-book/src/sanitizer-runtime.md b/src/doc/unstable-book/src/language-features/sanitizer-runtime.md similarity index 100% rename from src/doc/unstable-book/src/sanitizer-runtime.md rename to src/doc/unstable-book/src/language-features/sanitizer-runtime.md diff --git a/src/doc/unstable-book/src/simd-ffi.md b/src/doc/unstable-book/src/language-features/simd-ffi.md similarity index 100% rename from src/doc/unstable-book/src/simd-ffi.md rename to src/doc/unstable-book/src/language-features/simd-ffi.md diff --git a/src/doc/unstable-book/src/simd.md b/src/doc/unstable-book/src/language-features/simd.md similarity index 100% rename from src/doc/unstable-book/src/simd.md rename to src/doc/unstable-book/src/language-features/simd.md diff --git a/src/doc/unstable-book/src/slice-patterns.md b/src/doc/unstable-book/src/language-features/slice-patterns.md similarity index 100% rename from src/doc/unstable-book/src/slice-patterns.md rename to src/doc/unstable-book/src/language-features/slice-patterns.md diff --git a/src/doc/unstable-book/src/specialization.md b/src/doc/unstable-book/src/language-features/specialization.md similarity index 100% rename from src/doc/unstable-book/src/specialization.md rename to src/doc/unstable-book/src/language-features/specialization.md diff --git a/src/doc/unstable-book/src/staged-api.md b/src/doc/unstable-book/src/language-features/staged-api.md similarity index 100% rename from src/doc/unstable-book/src/staged-api.md rename to src/doc/unstable-book/src/language-features/staged-api.md diff --git a/src/doc/unstable-book/src/start.md b/src/doc/unstable-book/src/language-features/start.md similarity index 100% rename from src/doc/unstable-book/src/start.md rename to src/doc/unstable-book/src/language-features/start.md diff --git a/src/doc/unstable-book/src/static-nobundle.md b/src/doc/unstable-book/src/language-features/static-nobundle.md similarity index 100% rename from src/doc/unstable-book/src/static-nobundle.md rename to src/doc/unstable-book/src/language-features/static-nobundle.md diff --git a/src/doc/unstable-book/src/stmt-expr-attributes.md b/src/doc/unstable-book/src/language-features/stmt-expr-attributes.md similarity index 100% rename from src/doc/unstable-book/src/stmt-expr-attributes.md rename to src/doc/unstable-book/src/language-features/stmt-expr-attributes.md diff --git a/src/doc/unstable-book/src/struct-field-attributes.md b/src/doc/unstable-book/src/language-features/struct-field-attributes.md similarity index 100% rename from src/doc/unstable-book/src/struct-field-attributes.md rename to src/doc/unstable-book/src/language-features/struct-field-attributes.md diff --git a/src/doc/unstable-book/src/structural-match.md b/src/doc/unstable-book/src/language-features/structural-match.md similarity index 100% rename from src/doc/unstable-book/src/structural-match.md rename to src/doc/unstable-book/src/language-features/structural-match.md diff --git a/src/doc/unstable-book/src/target-feature.md b/src/doc/unstable-book/src/language-features/target-feature.md similarity index 100% rename from src/doc/unstable-book/src/target-feature.md rename to src/doc/unstable-book/src/language-features/target-feature.md diff --git a/src/doc/unstable-book/src/thread-local.md b/src/doc/unstable-book/src/language-features/thread-local.md similarity index 100% rename from src/doc/unstable-book/src/thread-local.md rename to src/doc/unstable-book/src/language-features/thread-local.md diff --git a/src/doc/unstable-book/src/trace-macros.md b/src/doc/unstable-book/src/language-features/trace-macros.md similarity index 100% rename from src/doc/unstable-book/src/trace-macros.md rename to src/doc/unstable-book/src/language-features/trace-macros.md diff --git a/src/doc/unstable-book/src/type-ascription.md b/src/doc/unstable-book/src/language-features/type-ascription.md similarity index 100% rename from src/doc/unstable-book/src/type-ascription.md rename to src/doc/unstable-book/src/language-features/type-ascription.md diff --git a/src/doc/unstable-book/src/unboxed-closures.md b/src/doc/unstable-book/src/language-features/unboxed-closures.md similarity index 100% rename from src/doc/unstable-book/src/unboxed-closures.md rename to src/doc/unstable-book/src/language-features/unboxed-closures.md diff --git a/src/doc/unstable-book/src/untagged-unions.md b/src/doc/unstable-book/src/language-features/untagged-unions.md similarity index 100% rename from src/doc/unstable-book/src/untagged-unions.md rename to src/doc/unstable-book/src/language-features/untagged-unions.md diff --git a/src/doc/unstable-book/src/unwind-attributes.md b/src/doc/unstable-book/src/language-features/unwind-attributes.md similarity index 100% rename from src/doc/unstable-book/src/unwind-attributes.md rename to src/doc/unstable-book/src/language-features/unwind-attributes.md diff --git a/src/doc/unstable-book/src/use-extern-macros.md b/src/doc/unstable-book/src/language-features/use-extern-macros.md similarity index 100% rename from src/doc/unstable-book/src/use-extern-macros.md rename to src/doc/unstable-book/src/language-features/use-extern-macros.md diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/language-features/used.md similarity index 100% rename from src/doc/unstable-book/src/used.md rename to src/doc/unstable-book/src/language-features/used.md diff --git a/src/doc/unstable-book/src/library-features.md b/src/doc/unstable-book/src/library-features.md new file mode 100644 index 000000000000..9f537e26132b --- /dev/null +++ b/src/doc/unstable-book/src/library-features.md @@ -0,0 +1 @@ +# Library Features diff --git a/src/doc/unstable-book/src/alloc-jemalloc.md b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md similarity index 100% rename from src/doc/unstable-book/src/alloc-jemalloc.md rename to src/doc/unstable-book/src/library-features/alloc-jemalloc.md diff --git a/src/doc/unstable-book/src/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md similarity index 100% rename from src/doc/unstable-book/src/alloc-system.md rename to src/doc/unstable-book/src/library-features/alloc-system.md diff --git a/src/doc/unstable-book/src/alloc.md b/src/doc/unstable-book/src/library-features/alloc.md similarity index 100% rename from src/doc/unstable-book/src/alloc.md rename to src/doc/unstable-book/src/library-features/alloc.md diff --git a/src/doc/unstable-book/src/as-c-str.md b/src/doc/unstable-book/src/library-features/as-c-str.md similarity index 100% rename from src/doc/unstable-book/src/as-c-str.md rename to src/doc/unstable-book/src/library-features/as-c-str.md diff --git a/src/doc/unstable-book/src/as-unsafe-cell.md b/src/doc/unstable-book/src/library-features/as-unsafe-cell.md similarity index 100% rename from src/doc/unstable-book/src/as-unsafe-cell.md rename to src/doc/unstable-book/src/library-features/as-unsafe-cell.md diff --git a/src/doc/unstable-book/src/ascii-ctype.md b/src/doc/unstable-book/src/library-features/ascii-ctype.md similarity index 100% rename from src/doc/unstable-book/src/ascii-ctype.md rename to src/doc/unstable-book/src/library-features/ascii-ctype.md diff --git a/src/doc/unstable-book/src/binary-heap-extras.md b/src/doc/unstable-book/src/library-features/binary-heap-extras.md similarity index 100% rename from src/doc/unstable-book/src/binary-heap-extras.md rename to src/doc/unstable-book/src/library-features/binary-heap-extras.md diff --git a/src/doc/unstable-book/src/binary-heap-peek-mut-pop.md b/src/doc/unstable-book/src/library-features/binary-heap-peek-mut-pop.md similarity index 100% rename from src/doc/unstable-book/src/binary-heap-peek-mut-pop.md rename to src/doc/unstable-book/src/library-features/binary-heap-peek-mut-pop.md diff --git a/src/doc/unstable-book/src/borrow-state.md b/src/doc/unstable-book/src/library-features/borrow-state.md similarity index 100% rename from src/doc/unstable-book/src/borrow-state.md rename to src/doc/unstable-book/src/library-features/borrow-state.md diff --git a/src/doc/unstable-book/src/box-heap.md b/src/doc/unstable-book/src/library-features/box-heap.md similarity index 100% rename from src/doc/unstable-book/src/box-heap.md rename to src/doc/unstable-book/src/library-features/box-heap.md diff --git a/src/doc/unstable-book/src/c-void-variant.md b/src/doc/unstable-book/src/library-features/c-void-variant.md similarity index 100% rename from src/doc/unstable-book/src/c-void-variant.md rename to src/doc/unstable-book/src/library-features/c-void-variant.md diff --git a/src/doc/unstable-book/src/char-escape-debug.md b/src/doc/unstable-book/src/library-features/char-escape-debug.md similarity index 100% rename from src/doc/unstable-book/src/char-escape-debug.md rename to src/doc/unstable-book/src/library-features/char-escape-debug.md diff --git a/src/doc/unstable-book/src/coerce-unsized.md b/src/doc/unstable-book/src/library-features/coerce-unsized.md similarity index 100% rename from src/doc/unstable-book/src/coerce-unsized.md rename to src/doc/unstable-book/src/library-features/coerce-unsized.md diff --git a/src/doc/unstable-book/src/collection-placement.md b/src/doc/unstable-book/src/library-features/collection-placement.md similarity index 100% rename from src/doc/unstable-book/src/collection-placement.md rename to src/doc/unstable-book/src/library-features/collection-placement.md diff --git a/src/doc/unstable-book/src/collections-range.md b/src/doc/unstable-book/src/library-features/collections-range.md similarity index 100% rename from src/doc/unstable-book/src/collections-range.md rename to src/doc/unstable-book/src/library-features/collections-range.md diff --git a/src/doc/unstable-book/src/collections.md b/src/doc/unstable-book/src/library-features/collections.md similarity index 100% rename from src/doc/unstable-book/src/collections.md rename to src/doc/unstable-book/src/library-features/collections.md diff --git a/src/doc/unstable-book/src/command-envs.md b/src/doc/unstable-book/src/library-features/command-envs.md similarity index 100% rename from src/doc/unstable-book/src/command-envs.md rename to src/doc/unstable-book/src/library-features/command-envs.md diff --git a/src/doc/unstable-book/src/compiler-builtins-lib.md b/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md similarity index 100% rename from src/doc/unstable-book/src/compiler-builtins-lib.md rename to src/doc/unstable-book/src/library-features/compiler-builtins-lib.md diff --git a/src/doc/unstable-book/src/compiler-fences.md b/src/doc/unstable-book/src/library-features/compiler-fences.md similarity index 100% rename from src/doc/unstable-book/src/compiler-fences.md rename to src/doc/unstable-book/src/library-features/compiler-fences.md diff --git a/src/doc/unstable-book/src/concat-idents-macro.md b/src/doc/unstable-book/src/library-features/concat-idents-macro.md similarity index 100% rename from src/doc/unstable-book/src/concat-idents-macro.md rename to src/doc/unstable-book/src/library-features/concat-idents-macro.md diff --git a/src/doc/unstable-book/src/core-char-ext.md b/src/doc/unstable-book/src/library-features/core-char-ext.md similarity index 100% rename from src/doc/unstable-book/src/core-char-ext.md rename to src/doc/unstable-book/src/library-features/core-char-ext.md diff --git a/src/doc/unstable-book/src/core-float.md b/src/doc/unstable-book/src/library-features/core-float.md similarity index 100% rename from src/doc/unstable-book/src/core-float.md rename to src/doc/unstable-book/src/library-features/core-float.md diff --git a/src/doc/unstable-book/src/core-intrinsics.md b/src/doc/unstable-book/src/library-features/core-intrinsics.md similarity index 100% rename from src/doc/unstable-book/src/core-intrinsics.md rename to src/doc/unstable-book/src/library-features/core-intrinsics.md diff --git a/src/doc/unstable-book/src/core-panic.md b/src/doc/unstable-book/src/library-features/core-panic.md similarity index 100% rename from src/doc/unstable-book/src/core-panic.md rename to src/doc/unstable-book/src/library-features/core-panic.md diff --git a/src/doc/unstable-book/src/core-private-bignum.md b/src/doc/unstable-book/src/library-features/core-private-bignum.md similarity index 100% rename from src/doc/unstable-book/src/core-private-bignum.md rename to src/doc/unstable-book/src/library-features/core-private-bignum.md diff --git a/src/doc/unstable-book/src/core-private-diy-float.md b/src/doc/unstable-book/src/library-features/core-private-diy-float.md similarity index 100% rename from src/doc/unstable-book/src/core-private-diy-float.md rename to src/doc/unstable-book/src/library-features/core-private-diy-float.md diff --git a/src/doc/unstable-book/src/core-slice-ext.md b/src/doc/unstable-book/src/library-features/core-slice-ext.md similarity index 100% rename from src/doc/unstable-book/src/core-slice-ext.md rename to src/doc/unstable-book/src/library-features/core-slice-ext.md diff --git a/src/doc/unstable-book/src/core-str-ext.md b/src/doc/unstable-book/src/library-features/core-str-ext.md similarity index 100% rename from src/doc/unstable-book/src/core-str-ext.md rename to src/doc/unstable-book/src/library-features/core-str-ext.md diff --git a/src/doc/unstable-book/src/dec2flt.md b/src/doc/unstable-book/src/library-features/dec2flt.md similarity index 100% rename from src/doc/unstable-book/src/dec2flt.md rename to src/doc/unstable-book/src/library-features/dec2flt.md diff --git a/src/doc/unstable-book/src/decode-utf8.md b/src/doc/unstable-book/src/library-features/decode-utf8.md similarity index 100% rename from src/doc/unstable-book/src/decode-utf8.md rename to src/doc/unstable-book/src/library-features/decode-utf8.md diff --git a/src/doc/unstable-book/src/derive-clone-copy.md b/src/doc/unstable-book/src/library-features/derive-clone-copy.md similarity index 100% rename from src/doc/unstable-book/src/derive-clone-copy.md rename to src/doc/unstable-book/src/library-features/derive-clone-copy.md diff --git a/src/doc/unstable-book/src/derive-eq.md b/src/doc/unstable-book/src/library-features/derive-eq.md similarity index 100% rename from src/doc/unstable-book/src/derive-eq.md rename to src/doc/unstable-book/src/library-features/derive-eq.md diff --git a/src/doc/unstable-book/src/discriminant-value.md b/src/doc/unstable-book/src/library-features/discriminant-value.md similarity index 100% rename from src/doc/unstable-book/src/discriminant-value.md rename to src/doc/unstable-book/src/library-features/discriminant-value.md diff --git a/src/doc/unstable-book/src/enumset.md b/src/doc/unstable-book/src/library-features/enumset.md similarity index 100% rename from src/doc/unstable-book/src/enumset.md rename to src/doc/unstable-book/src/library-features/enumset.md diff --git a/src/doc/unstable-book/src/error-type-id.md b/src/doc/unstable-book/src/library-features/error-type-id.md similarity index 100% rename from src/doc/unstable-book/src/error-type-id.md rename to src/doc/unstable-book/src/library-features/error-type-id.md diff --git a/src/doc/unstable-book/src/exact-size-is-empty.md b/src/doc/unstable-book/src/library-features/exact-size-is-empty.md similarity index 100% rename from src/doc/unstable-book/src/exact-size-is-empty.md rename to src/doc/unstable-book/src/library-features/exact-size-is-empty.md diff --git a/src/doc/unstable-book/src/fd-read.md b/src/doc/unstable-book/src/library-features/fd-read.md similarity index 100% rename from src/doc/unstable-book/src/fd-read.md rename to src/doc/unstable-book/src/library-features/fd-read.md diff --git a/src/doc/unstable-book/src/fd.md b/src/doc/unstable-book/src/library-features/fd.md similarity index 100% rename from src/doc/unstable-book/src/fd.md rename to src/doc/unstable-book/src/library-features/fd.md diff --git a/src/doc/unstable-book/src/fixed-size-array.md b/src/doc/unstable-book/src/library-features/fixed-size-array.md similarity index 100% rename from src/doc/unstable-book/src/fixed-size-array.md rename to src/doc/unstable-book/src/library-features/fixed-size-array.md diff --git a/src/doc/unstable-book/src/float-bits-conv.md b/src/doc/unstable-book/src/library-features/float-bits-conv.md similarity index 100% rename from src/doc/unstable-book/src/float-bits-conv.md rename to src/doc/unstable-book/src/library-features/float-bits-conv.md diff --git a/src/doc/unstable-book/src/float-extras.md b/src/doc/unstable-book/src/library-features/float-extras.md similarity index 100% rename from src/doc/unstable-book/src/float-extras.md rename to src/doc/unstable-book/src/library-features/float-extras.md diff --git a/src/doc/unstable-book/src/flt2dec.md b/src/doc/unstable-book/src/library-features/flt2dec.md similarity index 100% rename from src/doc/unstable-book/src/flt2dec.md rename to src/doc/unstable-book/src/library-features/flt2dec.md diff --git a/src/doc/unstable-book/src/fmt-flags-align.md b/src/doc/unstable-book/src/library-features/fmt-flags-align.md similarity index 100% rename from src/doc/unstable-book/src/fmt-flags-align.md rename to src/doc/unstable-book/src/library-features/fmt-flags-align.md diff --git a/src/doc/unstable-book/src/fmt-internals.md b/src/doc/unstable-book/src/library-features/fmt-internals.md similarity index 100% rename from src/doc/unstable-book/src/fmt-internals.md rename to src/doc/unstable-book/src/library-features/fmt-internals.md diff --git a/src/doc/unstable-book/src/fn-traits.md b/src/doc/unstable-book/src/library-features/fn-traits.md similarity index 100% rename from src/doc/unstable-book/src/fn-traits.md rename to src/doc/unstable-book/src/library-features/fn-traits.md diff --git a/src/doc/unstable-book/src/fnbox.md b/src/doc/unstable-book/src/library-features/fnbox.md similarity index 100% rename from src/doc/unstable-book/src/fnbox.md rename to src/doc/unstable-book/src/library-features/fnbox.md diff --git a/src/doc/unstable-book/src/from_utf8_error_as_bytes.md b/src/doc/unstable-book/src/library-features/from_utf8_error_as_bytes.md similarity index 100% rename from src/doc/unstable-book/src/from_utf8_error_as_bytes.md rename to src/doc/unstable-book/src/library-features/from_utf8_error_as_bytes.md diff --git a/src/doc/unstable-book/src/fused.md b/src/doc/unstable-book/src/library-features/fused.md similarity index 100% rename from src/doc/unstable-book/src/fused.md rename to src/doc/unstable-book/src/library-features/fused.md diff --git a/src/doc/unstable-book/src/future-atomic-orderings.md b/src/doc/unstable-book/src/library-features/future-atomic-orderings.md similarity index 100% rename from src/doc/unstable-book/src/future-atomic-orderings.md rename to src/doc/unstable-book/src/library-features/future-atomic-orderings.md diff --git a/src/doc/unstable-book/src/get-type-id.md b/src/doc/unstable-book/src/library-features/get-type-id.md similarity index 100% rename from src/doc/unstable-book/src/get-type-id.md rename to src/doc/unstable-book/src/library-features/get-type-id.md diff --git a/src/doc/unstable-book/src/heap-api.md b/src/doc/unstable-book/src/library-features/heap-api.md similarity index 100% rename from src/doc/unstable-book/src/heap-api.md rename to src/doc/unstable-book/src/library-features/heap-api.md diff --git a/src/doc/unstable-book/src/i128.md b/src/doc/unstable-book/src/library-features/i128.md similarity index 100% rename from src/doc/unstable-book/src/i128.md rename to src/doc/unstable-book/src/library-features/i128.md diff --git a/src/doc/unstable-book/src/inclusive-range.md b/src/doc/unstable-book/src/library-features/inclusive-range.md similarity index 100% rename from src/doc/unstable-book/src/inclusive-range.md rename to src/doc/unstable-book/src/library-features/inclusive-range.md diff --git a/src/doc/unstable-book/src/int-error-internals.md b/src/doc/unstable-book/src/library-features/int-error-internals.md similarity index 100% rename from src/doc/unstable-book/src/int-error-internals.md rename to src/doc/unstable-book/src/library-features/int-error-internals.md diff --git a/src/doc/unstable-book/src/integer-atomics.md b/src/doc/unstable-book/src/library-features/integer-atomics.md similarity index 100% rename from src/doc/unstable-book/src/integer-atomics.md rename to src/doc/unstable-book/src/library-features/integer-atomics.md diff --git a/src/doc/unstable-book/src/into-boxed-c-str.md b/src/doc/unstable-book/src/library-features/into-boxed-c-str.md similarity index 100% rename from src/doc/unstable-book/src/into-boxed-c-str.md rename to src/doc/unstable-book/src/library-features/into-boxed-c-str.md diff --git a/src/doc/unstable-book/src/into-boxed-os-str.md b/src/doc/unstable-book/src/library-features/into-boxed-os-str.md similarity index 100% rename from src/doc/unstable-book/src/into-boxed-os-str.md rename to src/doc/unstable-book/src/library-features/into-boxed-os-str.md diff --git a/src/doc/unstable-book/src/into-boxed-path.md b/src/doc/unstable-book/src/library-features/into-boxed-path.md similarity index 100% rename from src/doc/unstable-book/src/into-boxed-path.md rename to src/doc/unstable-book/src/library-features/into-boxed-path.md diff --git a/src/doc/unstable-book/src/io-error-internals.md b/src/doc/unstable-book/src/library-features/io-error-internals.md similarity index 100% rename from src/doc/unstable-book/src/io-error-internals.md rename to src/doc/unstable-book/src/library-features/io-error-internals.md diff --git a/src/doc/unstable-book/src/io.md b/src/doc/unstable-book/src/library-features/io.md similarity index 100% rename from src/doc/unstable-book/src/io.md rename to src/doc/unstable-book/src/library-features/io.md diff --git a/src/doc/unstable-book/src/ip.md b/src/doc/unstable-book/src/library-features/ip.md similarity index 100% rename from src/doc/unstable-book/src/ip.md rename to src/doc/unstable-book/src/library-features/ip.md diff --git a/src/doc/unstable-book/src/is-unique.md b/src/doc/unstable-book/src/library-features/is-unique.md similarity index 100% rename from src/doc/unstable-book/src/is-unique.md rename to src/doc/unstable-book/src/library-features/is-unique.md diff --git a/src/doc/unstable-book/src/iter-rfind.md b/src/doc/unstable-book/src/library-features/iter-rfind.md similarity index 100% rename from src/doc/unstable-book/src/iter-rfind.md rename to src/doc/unstable-book/src/library-features/iter-rfind.md diff --git a/src/doc/unstable-book/src/libstd-io-internals.md b/src/doc/unstable-book/src/library-features/libstd-io-internals.md similarity index 100% rename from src/doc/unstable-book/src/libstd-io-internals.md rename to src/doc/unstable-book/src/library-features/libstd-io-internals.md diff --git a/src/doc/unstable-book/src/libstd-sys-internals.md b/src/doc/unstable-book/src/library-features/libstd-sys-internals.md similarity index 100% rename from src/doc/unstable-book/src/libstd-sys-internals.md rename to src/doc/unstable-book/src/library-features/libstd-sys-internals.md diff --git a/src/doc/unstable-book/src/libstd-thread-internals.md b/src/doc/unstable-book/src/library-features/libstd-thread-internals.md similarity index 100% rename from src/doc/unstable-book/src/libstd-thread-internals.md rename to src/doc/unstable-book/src/library-features/libstd-thread-internals.md diff --git a/src/doc/unstable-book/src/linked-list-extras.md b/src/doc/unstable-book/src/library-features/linked-list-extras.md similarity index 100% rename from src/doc/unstable-book/src/linked-list-extras.md rename to src/doc/unstable-book/src/library-features/linked-list-extras.md diff --git a/src/doc/unstable-book/src/lookup-host.md b/src/doc/unstable-book/src/library-features/lookup-host.md similarity index 100% rename from src/doc/unstable-book/src/lookup-host.md rename to src/doc/unstable-book/src/library-features/lookup-host.md diff --git a/src/doc/unstable-book/src/manually-drop.md b/src/doc/unstable-book/src/library-features/manually-drop.md similarity index 100% rename from src/doc/unstable-book/src/manually-drop.md rename to src/doc/unstable-book/src/library-features/manually-drop.md diff --git a/src/doc/unstable-book/src/map-entry-recover-keys.md b/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md similarity index 100% rename from src/doc/unstable-book/src/map-entry-recover-keys.md rename to src/doc/unstable-book/src/library-features/map-entry-recover-keys.md diff --git a/src/doc/unstable-book/src/mpsc-select.md b/src/doc/unstable-book/src/library-features/mpsc-select.md similarity index 100% rename from src/doc/unstable-book/src/mpsc-select.md rename to src/doc/unstable-book/src/library-features/mpsc-select.md diff --git a/src/doc/unstable-book/src/n16.md b/src/doc/unstable-book/src/library-features/n16.md similarity index 100% rename from src/doc/unstable-book/src/n16.md rename to src/doc/unstable-book/src/library-features/n16.md diff --git a/src/doc/unstable-book/src/never-type-impls.md b/src/doc/unstable-book/src/library-features/never-type-impls.md similarity index 100% rename from src/doc/unstable-book/src/never-type-impls.md rename to src/doc/unstable-book/src/library-features/never-type-impls.md diff --git a/src/doc/unstable-book/src/nonzero.md b/src/doc/unstable-book/src/library-features/nonzero.md similarity index 100% rename from src/doc/unstable-book/src/nonzero.md rename to src/doc/unstable-book/src/library-features/nonzero.md diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/library-features/offset-to.md similarity index 100% rename from src/doc/unstable-book/src/offset-to.md rename to src/doc/unstable-book/src/library-features/offset-to.md diff --git a/src/doc/unstable-book/src/once-poison.md b/src/doc/unstable-book/src/library-features/once-poison.md similarity index 100% rename from src/doc/unstable-book/src/once-poison.md rename to src/doc/unstable-book/src/library-features/once-poison.md diff --git a/src/doc/unstable-book/src/oom.md b/src/doc/unstable-book/src/library-features/oom.md similarity index 100% rename from src/doc/unstable-book/src/oom.md rename to src/doc/unstable-book/src/library-features/oom.md diff --git a/src/doc/unstable-book/src/option-entry.md b/src/doc/unstable-book/src/library-features/option-entry.md similarity index 100% rename from src/doc/unstable-book/src/option-entry.md rename to src/doc/unstable-book/src/library-features/option-entry.md diff --git a/src/doc/unstable-book/src/osstring-shrink-to-fit.md b/src/doc/unstable-book/src/library-features/osstring-shrink-to-fit.md similarity index 100% rename from src/doc/unstable-book/src/osstring-shrink-to-fit.md rename to src/doc/unstable-book/src/library-features/osstring-shrink-to-fit.md diff --git a/src/doc/unstable-book/src/panic-abort.md b/src/doc/unstable-book/src/library-features/panic-abort.md similarity index 100% rename from src/doc/unstable-book/src/panic-abort.md rename to src/doc/unstable-book/src/library-features/panic-abort.md diff --git a/src/doc/unstable-book/src/panic-unwind.md b/src/doc/unstable-book/src/library-features/panic-unwind.md similarity index 100% rename from src/doc/unstable-book/src/panic-unwind.md rename to src/doc/unstable-book/src/library-features/panic-unwind.md diff --git a/src/doc/unstable-book/src/pattern.md b/src/doc/unstable-book/src/library-features/pattern.md similarity index 100% rename from src/doc/unstable-book/src/pattern.md rename to src/doc/unstable-book/src/library-features/pattern.md diff --git a/src/doc/unstable-book/src/peek.md b/src/doc/unstable-book/src/library-features/peek.md similarity index 100% rename from src/doc/unstable-book/src/peek.md rename to src/doc/unstable-book/src/library-features/peek.md diff --git a/src/doc/unstable-book/src/placement-in.md b/src/doc/unstable-book/src/library-features/placement-in.md similarity index 100% rename from src/doc/unstable-book/src/placement-in.md rename to src/doc/unstable-book/src/library-features/placement-in.md diff --git a/src/doc/unstable-book/src/placement-new-protocol.md b/src/doc/unstable-book/src/library-features/placement-new-protocol.md similarity index 100% rename from src/doc/unstable-book/src/placement-new-protocol.md rename to src/doc/unstable-book/src/library-features/placement-new-protocol.md diff --git a/src/doc/unstable-book/src/print.md b/src/doc/unstable-book/src/library-features/print.md similarity index 100% rename from src/doc/unstable-book/src/print.md rename to src/doc/unstable-book/src/library-features/print.md diff --git a/src/doc/unstable-book/src/proc-macro-internals.md b/src/doc/unstable-book/src/library-features/proc-macro-internals.md similarity index 100% rename from src/doc/unstable-book/src/proc-macro-internals.md rename to src/doc/unstable-book/src/library-features/proc-macro-internals.md diff --git a/src/doc/unstable-book/src/process-try-wait.md b/src/doc/unstable-book/src/library-features/process-try-wait.md similarity index 100% rename from src/doc/unstable-book/src/process-try-wait.md rename to src/doc/unstable-book/src/library-features/process-try-wait.md diff --git a/src/doc/unstable-book/src/question-mark-carrier.md b/src/doc/unstable-book/src/library-features/question-mark-carrier.md similarity index 100% rename from src/doc/unstable-book/src/question-mark-carrier.md rename to src/doc/unstable-book/src/library-features/question-mark-carrier.md diff --git a/src/doc/unstable-book/src/rand.md b/src/doc/unstable-book/src/library-features/rand.md similarity index 100% rename from src/doc/unstable-book/src/rand.md rename to src/doc/unstable-book/src/library-features/rand.md diff --git a/src/doc/unstable-book/src/range-contains.md b/src/doc/unstable-book/src/library-features/range-contains.md similarity index 100% rename from src/doc/unstable-book/src/range-contains.md rename to src/doc/unstable-book/src/library-features/range-contains.md diff --git a/src/doc/unstable-book/src/raw.md b/src/doc/unstable-book/src/library-features/raw.md similarity index 100% rename from src/doc/unstable-book/src/raw.md rename to src/doc/unstable-book/src/library-features/raw.md diff --git a/src/doc/unstable-book/src/rc-would-unwrap.md b/src/doc/unstable-book/src/library-features/rc-would-unwrap.md similarity index 100% rename from src/doc/unstable-book/src/rc-would-unwrap.md rename to src/doc/unstable-book/src/library-features/rc-would-unwrap.md diff --git a/src/doc/unstable-book/src/retain-hash-collection.md b/src/doc/unstable-book/src/library-features/retain-hash-collection.md similarity index 100% rename from src/doc/unstable-book/src/retain-hash-collection.md rename to src/doc/unstable-book/src/library-features/retain-hash-collection.md diff --git a/src/doc/unstable-book/src/reverse-cmp-key.md b/src/doc/unstable-book/src/library-features/reverse-cmp-key.md similarity index 100% rename from src/doc/unstable-book/src/reverse-cmp-key.md rename to src/doc/unstable-book/src/library-features/reverse-cmp-key.md diff --git a/src/doc/unstable-book/src/rt.md b/src/doc/unstable-book/src/library-features/rt.md similarity index 100% rename from src/doc/unstable-book/src/rt.md rename to src/doc/unstable-book/src/library-features/rt.md diff --git a/src/doc/unstable-book/src/rustc-private.md b/src/doc/unstable-book/src/library-features/rustc-private.md similarity index 100% rename from src/doc/unstable-book/src/rustc-private.md rename to src/doc/unstable-book/src/library-features/rustc-private.md diff --git a/src/doc/unstable-book/src/sanitizer-runtime-lib.md b/src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md similarity index 100% rename from src/doc/unstable-book/src/sanitizer-runtime-lib.md rename to src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md diff --git a/src/doc/unstable-book/src/set-stdio.md b/src/doc/unstable-book/src/library-features/set-stdio.md similarity index 100% rename from src/doc/unstable-book/src/set-stdio.md rename to src/doc/unstable-book/src/library-features/set-stdio.md diff --git a/src/doc/unstable-book/src/shared.md b/src/doc/unstable-book/src/library-features/shared.md similarity index 100% rename from src/doc/unstable-book/src/shared.md rename to src/doc/unstable-book/src/library-features/shared.md diff --git a/src/doc/unstable-book/src/sip-hash-13.md b/src/doc/unstable-book/src/library-features/sip-hash-13.md similarity index 100% rename from src/doc/unstable-book/src/sip-hash-13.md rename to src/doc/unstable-book/src/library-features/sip-hash-13.md diff --git a/src/doc/unstable-book/src/slice-concat-ext.md b/src/doc/unstable-book/src/library-features/slice-concat-ext.md similarity index 100% rename from src/doc/unstable-book/src/slice-concat-ext.md rename to src/doc/unstable-book/src/library-features/slice-concat-ext.md diff --git a/src/doc/unstable-book/src/slice-get-slice.md b/src/doc/unstable-book/src/library-features/slice-get-slice.md similarity index 100% rename from src/doc/unstable-book/src/slice-get-slice.md rename to src/doc/unstable-book/src/library-features/slice-get-slice.md diff --git a/src/doc/unstable-book/src/slice-rsplit.md b/src/doc/unstable-book/src/library-features/slice-rsplit.md similarity index 100% rename from src/doc/unstable-book/src/slice-rsplit.md rename to src/doc/unstable-book/src/library-features/slice-rsplit.md diff --git a/src/doc/unstable-book/src/sort-internals.md b/src/doc/unstable-book/src/library-features/sort-internals.md similarity index 100% rename from src/doc/unstable-book/src/sort-internals.md rename to src/doc/unstable-book/src/library-features/sort-internals.md diff --git a/src/doc/unstable-book/src/sort-unstable.md b/src/doc/unstable-book/src/library-features/sort-unstable.md similarity index 100% rename from src/doc/unstable-book/src/sort-unstable.md rename to src/doc/unstable-book/src/library-features/sort-unstable.md diff --git a/src/doc/unstable-book/src/step-by.md b/src/doc/unstable-book/src/library-features/step-by.md similarity index 100% rename from src/doc/unstable-book/src/step-by.md rename to src/doc/unstable-book/src/library-features/step-by.md diff --git a/src/doc/unstable-book/src/step-trait.md b/src/doc/unstable-book/src/library-features/step-trait.md similarity index 100% rename from src/doc/unstable-book/src/step-trait.md rename to src/doc/unstable-book/src/library-features/step-trait.md diff --git a/src/doc/unstable-book/src/str-checked-slicing.md b/src/doc/unstable-book/src/library-features/str-checked-slicing.md similarity index 100% rename from src/doc/unstable-book/src/str-checked-slicing.md rename to src/doc/unstable-book/src/library-features/str-checked-slicing.md diff --git a/src/doc/unstable-book/src/str-escape.md b/src/doc/unstable-book/src/library-features/str-escape.md similarity index 100% rename from src/doc/unstable-book/src/str-escape.md rename to src/doc/unstable-book/src/library-features/str-escape.md diff --git a/src/doc/unstable-book/src/str-internals.md b/src/doc/unstable-book/src/library-features/str-internals.md similarity index 100% rename from src/doc/unstable-book/src/str-internals.md rename to src/doc/unstable-book/src/library-features/str-internals.md diff --git a/src/doc/unstable-book/src/str-mut-extras.md b/src/doc/unstable-book/src/library-features/str-mut-extras.md similarity index 100% rename from src/doc/unstable-book/src/str-mut-extras.md rename to src/doc/unstable-book/src/library-features/str-mut-extras.md diff --git a/src/doc/unstable-book/src/test.md b/src/doc/unstable-book/src/library-features/test.md similarity index 100% rename from src/doc/unstable-book/src/test.md rename to src/doc/unstable-book/src/library-features/test.md diff --git a/src/doc/unstable-book/src/thread-id.md b/src/doc/unstable-book/src/library-features/thread-id.md similarity index 100% rename from src/doc/unstable-book/src/thread-id.md rename to src/doc/unstable-book/src/library-features/thread-id.md diff --git a/src/doc/unstable-book/src/thread-local-internals.md b/src/doc/unstable-book/src/library-features/thread-local-internals.md similarity index 100% rename from src/doc/unstable-book/src/thread-local-internals.md rename to src/doc/unstable-book/src/library-features/thread-local-internals.md diff --git a/src/doc/unstable-book/src/thread-local-state.md b/src/doc/unstable-book/src/library-features/thread-local-state.md similarity index 100% rename from src/doc/unstable-book/src/thread-local-state.md rename to src/doc/unstable-book/src/library-features/thread-local-state.md diff --git a/src/doc/unstable-book/src/toowned-clone-into.md b/src/doc/unstable-book/src/library-features/toowned-clone-into.md similarity index 100% rename from src/doc/unstable-book/src/toowned-clone-into.md rename to src/doc/unstable-book/src/library-features/toowned-clone-into.md diff --git a/src/doc/unstable-book/src/trusted-len.md b/src/doc/unstable-book/src/library-features/trusted-len.md similarity index 100% rename from src/doc/unstable-book/src/trusted-len.md rename to src/doc/unstable-book/src/library-features/trusted-len.md diff --git a/src/doc/unstable-book/src/try-from.md b/src/doc/unstable-book/src/library-features/try-from.md similarity index 100% rename from src/doc/unstable-book/src/try-from.md rename to src/doc/unstable-book/src/library-features/try-from.md diff --git a/src/doc/unstable-book/src/unicode.md b/src/doc/unstable-book/src/library-features/unicode.md similarity index 100% rename from src/doc/unstable-book/src/unicode.md rename to src/doc/unstable-book/src/library-features/unicode.md diff --git a/src/doc/unstable-book/src/unique.md b/src/doc/unstable-book/src/library-features/unique.md similarity index 100% rename from src/doc/unstable-book/src/unique.md rename to src/doc/unstable-book/src/library-features/unique.md diff --git a/src/doc/unstable-book/src/unsize.md b/src/doc/unstable-book/src/library-features/unsize.md similarity index 100% rename from src/doc/unstable-book/src/unsize.md rename to src/doc/unstable-book/src/library-features/unsize.md diff --git a/src/doc/unstable-book/src/update-panic-count.md b/src/doc/unstable-book/src/library-features/update-panic-count.md similarity index 100% rename from src/doc/unstable-book/src/update-panic-count.md rename to src/doc/unstable-book/src/library-features/update-panic-count.md diff --git a/src/doc/unstable-book/src/utf8-error-error-len.md b/src/doc/unstable-book/src/library-features/utf8-error-error-len.md similarity index 100% rename from src/doc/unstable-book/src/utf8-error-error-len.md rename to src/doc/unstable-book/src/library-features/utf8-error-error-len.md diff --git a/src/doc/unstable-book/src/vec-remove-item.md b/src/doc/unstable-book/src/library-features/vec-remove-item.md similarity index 100% rename from src/doc/unstable-book/src/vec-remove-item.md rename to src/doc/unstable-book/src/library-features/vec-remove-item.md diff --git a/src/doc/unstable-book/src/windows-c.md b/src/doc/unstable-book/src/library-features/windows-c.md similarity index 100% rename from src/doc/unstable-book/src/windows-c.md rename to src/doc/unstable-book/src/library-features/windows-c.md diff --git a/src/doc/unstable-book/src/windows-handle.md b/src/doc/unstable-book/src/library-features/windows-handle.md similarity index 100% rename from src/doc/unstable-book/src/windows-handle.md rename to src/doc/unstable-book/src/library-features/windows-handle.md diff --git a/src/doc/unstable-book/src/windows-net.md b/src/doc/unstable-book/src/library-features/windows-net.md similarity index 100% rename from src/doc/unstable-book/src/windows-net.md rename to src/doc/unstable-book/src/library-features/windows-net.md diff --git a/src/doc/unstable-book/src/windows-stdio.md b/src/doc/unstable-book/src/library-features/windows-stdio.md similarity index 100% rename from src/doc/unstable-book/src/windows-stdio.md rename to src/doc/unstable-book/src/library-features/windows-stdio.md diff --git a/src/doc/unstable-book/src/zero-one.md b/src/doc/unstable-book/src/library-features/zero-one.md similarity index 100% rename from src/doc/unstable-book/src/zero-one.md rename to src/doc/unstable-book/src/library-features/zero-one.md diff --git a/src/doc/unstable-book/src/the-unstable-book.md b/src/doc/unstable-book/src/the-unstable-book.md index dfbfe4cab973..604b449f1637 100644 --- a/src/doc/unstable-book/src/the-unstable-book.md +++ b/src/doc/unstable-book/src/the-unstable-book.md @@ -14,7 +14,7 @@ fn main() { The `box_syntax` feature [has a chapter][box] describing how to use it. -[box]: box-syntax.html +[box]: language-features/box-syntax.html Because this documentation relates to unstable features, we make no guarantees that what is contained here is accurate or up to date. It's developed on a diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 129674b74769..175447e11127 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -344,9 +344,6 @@ declare_features! ( // Used to preserve symbols (see llvm.used) (active, used, "1.18.0", Some(40289)), - // Hack to document `-Z linker-flavor` in The Unstable Book - (active, linker_flavor, "1.18.0", Some(41142)), - // Allows module-level inline assembly by way of global_asm!() (active, global_asm, "1.18.0", Some(35119)), diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 137de561c76c..531c148de261 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -147,6 +147,12 @@ fn check(cache: &mut Cache, return None; } + // mdbook uses the HTML tag to handle links for subdirectories, which + // linkchecker doesn't support + if file.to_str().unwrap().contains("unstable-book/") { + return None; + } + let res = load_file(cache, root, PathBuf::from(file), SkipRedirect); let (pretty_file, contents) = match res { Ok(res) => res, diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 371922c9e6bb..664aecfcbdb9 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -2,6 +2,3 @@ name = "tidy" version = "0.1.0" authors = ["Alex Crichton "] - -[dependencies] -regex = "0.2" \ No newline at end of file diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 44063e627a36..3e7046d05f49 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -14,8 +14,6 @@ //! etc. This is run by default on `make check` and as part of the auto //! builders. -extern crate regex; - use std::env; use std::fs; use std::io::{self, Write}; diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index 2d3d9e80257f..5a6524b3e88e 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -10,35 +10,36 @@ use std::collections::HashSet; use std::fs; -use std::io::{self, BufRead}; use std::path; use features::{collect_lang_features, collect_lib_features, Status}; const PATH_STR: &'static str = "doc/unstable-book/src"; -const SUMMARY_FILE_NAME: &'static str = "SUMMARY.md"; +const LANG_FEATURES_DIR: &'static str = "language-features"; -static EXCLUDE: &'static [&'static str; 2] = &[SUMMARY_FILE_NAME, "the-unstable-book.md"]; +const LIB_FEATURES_DIR: &'static str = "library-features"; /// Build the path to the Unstable Book source directory from the Rust 'src' directory fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf { base_src_path.join(PATH_STR) } -/// Build the path to the Unstable Book SUMMARY file from the Rust 'src' directory -fn unstable_book_summary_path(base_src_path: &path::Path) -> path::PathBuf { - unstable_book_path(base_src_path).join(SUMMARY_FILE_NAME) +/// Directory where the features are documented within the Unstable Book source directory +fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf { + unstable_book_path(base_src_path).join(LANG_FEATURES_DIR) } -/// Open the Unstable Book SUMMARY file -fn open_unstable_book_summary_file(base_src_path: &path::Path) -> fs::File { - fs::File::open(unstable_book_summary_path(base_src_path)) - .expect("could not open Unstable Book SUMMARY.md") +/// Directory where the features are documented within the Unstable Book source directory +fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf { + unstable_book_path(base_src_path).join(LIB_FEATURES_DIR) } /// Test to determine if DirEntry is a file fn dir_entry_is_file(dir_entry: &fs::DirEntry) -> bool { - dir_entry.file_type().expect("could not determine file type of directory entry").is_file() + dir_entry + .file_type() + .expect("could not determine file type of directory entry") + .is_file() } /// Retrieve names of all lang-related unstable features @@ -61,75 +62,81 @@ fn collect_unstable_lib_feature_names(base_src_path: &path::Path) -> HashSet HashSet { - collect_unstable_lib_feature_names(base_src_path) - .union(&collect_unstable_lang_feature_names(base_src_path)) - .map(|n| n.to_owned()) - .collect::>() -} - -/// Retrieve file names of all sections in the Unstable Book with: -/// -/// * hyphens replaced by underscores -/// * the markdown suffix ('.md') removed -fn collect_unstable_book_section_file_names(base_src_path: &path::Path) -> HashSet { - fs::read_dir(unstable_book_path(base_src_path)) +fn collect_unstable_book_section_file_names(dir: &path::Path) -> HashSet { + fs::read_dir(dir) .expect("could not read directory") .into_iter() .map(|entry| entry.expect("could not read directory entry")) .filter(dir_entry_is_file) .map(|entry| entry.file_name().into_string().unwrap()) - .filter(|n| EXCLUDE.iter().all(|e| n != e)) .map(|n| n.trim_right_matches(".md").replace('-', "_")) .collect() } -/// Retrieve unstable feature names that are in the Unstable Book SUMMARY file -fn collect_unstable_book_summary_links(base_src_path: &path::Path) -> HashSet { - let summary_link_regex = - ::regex::Regex::new(r"^- \[(\S+)\]\(\S+\.md\)").expect("invalid regex"); - io::BufReader::new(open_unstable_book_summary_file(base_src_path)) - .lines() - .map(|l| l.expect("could not read line from file")) - .filter_map(|line| { - summary_link_regex.captures(&line).map(|c| { - c.get(1) - .unwrap() - .as_str() - .to_owned() - }) - }) - .collect() +/// Retrieve file names of all library feature sections in the Unstable Book with: +/// +/// * hyphens replaced by underscores +/// * the markdown suffix ('.md') removed +fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path::Path) + -> HashSet { + collect_unstable_book_section_file_names(&unstable_book_lang_features_path(base_src_path)) +} + +/// Retrieve file names of all language feature sections in the Unstable Book with: +/// +/// * hyphens replaced by underscores +/// * the markdown suffix ('.md') removed +fn collect_unstable_book_lib_features_section_file_names(base_src_path: &path::Path) + -> HashSet { + collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path)) } pub fn check(path: &path::Path, bad: &mut bool) { - let unstable_feature_names = collect_unstable_feature_names(path); - let unstable_book_section_file_names = collect_unstable_book_section_file_names(path); - let unstable_book_links = collect_unstable_book_summary_links(path); - // Check for Unstable Book section names with no corresponding SUMMARY.md link - for feature_name in &unstable_book_section_file_names - &unstable_book_links { - tidy_error!( - bad, - "The Unstable Book section '{}' needs to have a link in SUMMARY.md", - feature_name); - } + // Library features + + let unstable_lib_feature_names = collect_unstable_lib_feature_names(path); + let unstable_book_lib_features_section_file_names = + collect_unstable_book_lib_features_section_file_names(path); // Check for unstable features that don't have Unstable Book sections - for feature_name in &unstable_feature_names - &unstable_book_section_file_names { - tidy_error!( - bad, - "Unstable feature '{}' needs to have a section in The Unstable Book", - feature_name); + for feature_name in &unstable_lib_feature_names - + &unstable_book_lib_features_section_file_names { + tidy_error!(bad, + "Unstable library feature '{}' needs to have a section within the \ + 'library features' section of The Unstable Book", + feature_name); } // Check for Unstable Book sections that don't have a corresponding unstable feature - for feature_name in &unstable_book_section_file_names - &unstable_feature_names { - tidy_error!( - bad, - "The Unstable Book has a section '{}' which doesn't correspond \ - to an unstable feature", - feature_name) + for feature_name in &unstable_book_lib_features_section_file_names - + &unstable_lib_feature_names { + tidy_error!(bad, + "The Unstable Book has a 'library feature' section '{}' which doesn't \ + correspond to an unstable library feature", + feature_name) + } + + // Language features + + let unstable_lang_feature_names = collect_unstable_lang_feature_names(path); + let unstable_book_lang_features_section_file_names = + collect_unstable_book_lang_features_section_file_names(path); + + for feature_name in &unstable_lang_feature_names - + &unstable_book_lang_features_section_file_names { + tidy_error!(bad, + "Unstable language feature '{}' needs to have a section within the \ + 'language features' section of The Unstable Book", + feature_name); + } + + // Check for Unstable Book sections that don't have a corresponding unstable feature + for feature_name in &unstable_book_lang_features_section_file_names - + &unstable_lang_feature_names { + tidy_error!(bad, + "The Unstable Book has a 'language feature' section '{}' which doesn't \ + correspond to an unstable language feature", + feature_name) } } From bf202c880c7028a12a70bf119c359563413988d2 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 17 Apr 2017 16:55:43 -0400 Subject: [PATCH 582/905] Bump book and reference. --- src/doc/book | 2 +- src/doc/reference | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book b/src/doc/book index beea82b9230c..ad7de198561b 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 +Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 diff --git a/src/doc/reference b/src/doc/reference index b060f732145f..6b0de90d87dd 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d +Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 From 295bcdb715871ef3ba0258c75dad885b7315a162 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 13 Apr 2017 02:48:46 -0700 Subject: [PATCH 583/905] Override ToOwned::clone_into for Path and OsStr The only non-overridden one remaining is the CStr impl, which cannot be optimized as doing so would break CString's second invariant. --- src/libstd/ffi/os_str.rs | 18 +++++++++++++++++- src/libstd/lib.rs | 1 + src/libstd/path.rs | 12 ++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index bf3f41b13c18..b90192dd8af2 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -677,7 +677,13 @@ impl Borrow for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for OsStr { type Owned = OsString; - fn to_owned(&self) -> OsString { self.to_os_string() } + fn to_owned(&self) -> OsString { + self.to_os_string() + } + fn clone_into(&self, target: &mut OsString) { + target.clear(); + target.push(self); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -863,4 +869,14 @@ mod tests { let boxed = >::default(); assert!(boxed.is_empty()); } + + #[test] + fn test_os_str_clone_into() { + let mut os_string = OsString::with_capacity(123); + os_string.push("hello"); + let os_str = OsStr::new("bonjour"); + os_str.clone_into(&mut os_string); + assert_eq!(os_str, os_string); + assert!(os_string.capacity() >= 123); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 8de6e1a24f1f..367779bb701c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -311,6 +311,7 @@ #![feature(str_utf16)] #![feature(test, rustc_private)] #![feature(thread_local)] +#![feature(toowned_clone_into)] #![feature(try_from)] #![feature(unboxed_closures)] #![feature(unicode)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index db446d88900c..fcbd3705e881 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1322,6 +1322,9 @@ impl ToOwned for Path { fn to_owned(&self) -> PathBuf { self.to_path_buf() } + fn clone_into(&self, target: &mut PathBuf) { + self.inner.clone_into(&mut target.inner); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3722,4 +3725,13 @@ mod tests { assert_eq!(&*boxed, &*path_buf); assert_eq!(&*path_buf, path); } + + #[test] + fn test_clone_into() { + let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); + let path = Path::new("short"); + path.clone_into(&mut path_buf); + assert_eq!(path, path_buf); + assert!(path_buf.into_os_string().capacity() >= 15); + } } From d6b8d9f75d7ad5ab6f1e198db992f10d4ce5fad5 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Wed, 19 Apr 2017 01:45:34 -0400 Subject: [PATCH 584/905] remove disclaimer from bootstrap/README.md --- src/bootstrap/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 2f7757fb1d5b..1ce99eb893ef 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -4,10 +4,6 @@ This is an in-progress README which is targeted at helping to explain how Rust is bootstrapped and in general some of the technical details of the build system. -> **Note**: This build system is currently under active development and is not -> intended to be the primarily used one just yet. The makefiles are currently -> the ones that are still "guaranteed to work" as much as possible at least. - ## Using rustbuild The rustbuild build system has a primary entry point, a top level `x.py` script: From aa6c2b1cb73edad3ca1e8068151dd7254a3ebce1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 18 Apr 2017 15:48:19 -0400 Subject: [PATCH 585/905] propagate obligations during overlap check --- src/librustc/traits/coherence.rs | 8 ++++---- src/test/run-pass/issue-41298.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/issue-41298.rs diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 383fab3fcd76..a943ef30e534 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -55,16 +55,15 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - match selcx.infcx().eq_impl_headers(true, + let obligations = match selcx.infcx().eq_impl_headers(true, &ObligationCause::dummy(), &a_impl_header, &b_impl_header) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + obligations } Err(_) => return None - } + }; debug!("overlap: unification check succeeded"); @@ -78,6 +77,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, .map(|p| Obligation { cause: ObligationCause::dummy(), recursion_depth: 0, predicate: p }) + .chain(obligations) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { diff --git a/src/test/run-pass/issue-41298.rs b/src/test/run-pass/issue-41298.rs new file mode 100644 index 000000000000..2b9baa746748 --- /dev/null +++ b/src/test/run-pass/issue-41298.rs @@ -0,0 +1,16 @@ +// 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. + +struct Function { t: T, f: F } + +impl Function R> { fn foo() { } } +impl Function R> { fn bar() { } } + +fn main() { } From 93e10977d8b0ccd2cdc41f30e187e6ebecd3240b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 18 Apr 2017 15:48:32 -0400 Subject: [PATCH 586/905] propagate other obligations that were left out cc #32730 -- I left exactly one instance where I wasn't sure of the right behavior. --- src/librustc/infer/mod.rs | 10 +++++++--- src/librustc/traits/fulfill.rs | 10 ++++++++++ src/librustc/traits/specialize/mod.rs | 7 +++---- src/librustc_driver/test.rs | 6 +++--- src/librustc_typeck/check/compare_method.rs | 7 +++---- src/librustc_typeck/check/dropck.rs | 5 ++--- src/librustc_typeck/lib.rs | 17 ++++++++++++----- 7 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a1bafe113e41..4d8b31a33cde 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1597,9 +1597,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // generic so we don't have to do anything quite this // terrible. let trace = TypeTrace::dummy(self.tcx); - self.equate(true, trace, a, b).map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.equate(true, trace, a, b).map(|InferOk { obligations: _, .. }| { + // We can intentionally ignore obligations here, since + // this is part of a simple test for general + // "equatability". However, it's not entirely clear + // that we *ought* to be, perhaps a better thing would + // be to use a mini-fulfillment context or something + // like that. }) }) } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index d771be077ae3..d49affa3e872 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -184,6 +184,16 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { }); } + pub fn register_predicate_obligations(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligations: Vec>) + { + for obligation in obligations { + self.register_predicate_obligation(infcx, obligation); + } + } + + pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 92b7c736d42f..5f02688be34b 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -218,7 +218,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, -> Result<&'tcx Substs<'tcx>, ()> { let selcx = &mut SelectionContext::new(&infcx); let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); - let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, + let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx, target_impl, target_substs); @@ -227,9 +227,8 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, &ObligationCause::dummy(), source_trait_ref, target_trait_ref) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) + Ok(InferOk { obligations: o, .. }) => { + obligations.extend(o); } Err(_) => { debug!("fulfill_implication: {:?} does not unify with {:?}", diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 44e291a44c77..7447fba3038e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -376,7 +376,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { match self.sub(t1, t2) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); } Err(ref e) => { @@ -400,7 +400,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { match self.lub(t1, t2) { Ok(InferOk { obligations, value: t }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); self.assert_eq(t, t_lub); @@ -415,7 +415,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { match self.glb(t1, t2) { Err(e) => panic!("unexpected error computing LUB: {:?}", e), Ok(InferOk { obligations, value: t }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); self.assert_eq(t, t_glb); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 8a6853461a5e..ae70049cc5bd 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -294,10 +294,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_impl_method: trait_fty={:?}", trait_fty); let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - }); + .map(|InferOk { obligations, .. }| { + inh.register_predicates(obligations); + }); if let Err(terr) = sub_result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 9f41373dab1b..b71ff58ccec3 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -82,7 +82,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( // check that the impl type can be made to match the trait type. let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id); - tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| { let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); @@ -97,8 +97,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id); match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + fulfillment_cx.register_predicate_obligations(infcx, obligations); } Err(_) => { let item_span = tcx.hir.span(self_type_node_id); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e9a606dc0ab1..0754b52cf280 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -109,7 +109,7 @@ use rustc::infer::InferOk; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; -use rustc::traits::{ObligationCause, ObligationCauseCode, Reveal}; +use rustc::traits::{FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use session::config; use util::common::time; @@ -153,15 +153,22 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { - tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt((), Reveal::UserFacing).enter(|ref infcx| { + let mut fulfill_cx = FulfillmentContext::new(); match infcx.eq_types(false, &cause, expected, actual) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - true + fulfill_cx.register_predicate_obligations(infcx, obligations); } Err(err) => { infcx.report_mismatched_types(cause, expected, actual, err).emit(); + return false; + } + } + + match fulfill_cx.select_all_or_error(infcx) { + Ok(()) => true, + Err(errors) => { + infcx.report_fulfillment_errors(&errors); false } } From 24640b306ea27371b18317c0b8b4823b07f570fa Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Wed, 19 Apr 2017 16:29:47 +0100 Subject: [PATCH 587/905] Disable git caches again --- .travis.yml | 5 ----- appveyor.yml | 1 - 2 files changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0ffba70d2ef4..5d56379dcceb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -192,10 +192,6 @@ before_cache: grep -v missing | xargs docker save | gzip > $HOME/docker/rust-ci.tar.gz - - if [ ! -f $HOME/rustsrc/cache_valid1 ]; then - echo "WARNING rustsrc cache was invalid when saving"; - rm -rf $HOME/rustsrc && mkdir $HOME/rustsrc; - fi before_install: - zcat $HOME/docker/rust-ci.tar.gz | docker load || true - mkdir -p $HOME/rustsrc @@ -206,7 +202,6 @@ notifications: cache: directories: - $HOME/docker - - $HOME/rustsrc before_deploy: - mkdir -p deploy/$TRAVIS_COMMIT diff --git a/appveyor.yml b/appveyor.yml index 978ca0d9739b..5de5f3bd26c3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -151,7 +151,6 @@ on_failure: - cat %CD%\sccache.log || exit 0 cache: - - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" From 2e2a670073b5abd523418357a2ebbbc1352ec696 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 19 Apr 2017 12:42:07 -0400 Subject: [PATCH 588/905] Remove platform-specific directory separator. --- src/tools/linkchecker/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 531c148de261..3d9a4fba6cde 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -149,7 +149,7 @@ fn check(cache: &mut Cache, // mdbook uses the HTML tag to handle links for subdirectories, which // linkchecker doesn't support - if file.to_str().unwrap().contains("unstable-book/") { + if file.to_str().unwrap().contains("unstable-book") { return None; } From a850cdcb7ec82cc5eaec76ee90b6ee1794a6da9b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 17 Apr 2017 18:06:43 +0200 Subject: [PATCH 589/905] Fix debug infinite loop --- src/libcollections/btree/set.rs | 12 ++++++++---- src/libcollections/enum_set.rs | 3 ++- src/libcollections/linked_list.rs | 11 ++++++----- src/libcollections/vec_deque.rs | 14 ++++++++++---- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index ffca6964c5fd..7b4079207d2e 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -138,7 +138,8 @@ pub struct Difference<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Difference") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } @@ -160,7 +161,8 @@ pub struct SymmetricDifference<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("SymmetricDifference") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } @@ -182,7 +184,8 @@ pub struct Intersection<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Intersection") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } @@ -204,7 +207,8 @@ pub struct Union<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Union") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index ebee75d1a1a6..aaee567bf1db 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -225,7 +225,8 @@ pub struct Iter { impl fmt::Debug for Iter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Iter") - .field(&self.clone()) + .field(&self.index) + .field(&self.bits) .finish() } } diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index bfb03a5b23f1..1cc5e10418f2 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -75,7 +75,7 @@ pub struct Iter<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Iter") - .field(&self.clone()) + .field(&self.len) .finish() } } @@ -107,7 +107,8 @@ pub struct IterMut<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IterMut") - .field(self.clone()) + .field(&self.list) + .field(&self.len) .finish() } } @@ -129,7 +130,7 @@ pub struct IntoIter { impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IntoIter") - .field(self.clone()) + .field(&self.list) .finish() } } @@ -1128,7 +1129,7 @@ pub struct FrontPlace<'a, T: 'a> { 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.clone()) + .field(&self.list) .finish() } } @@ -1183,7 +1184,7 @@ pub struct BackPlace<'a, T: 'a> { 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.clone()) + .field(&self.list) .finish() } } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 2ce3b92843bd..f0e61ebc47bf 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1913,7 +1913,9 @@ pub struct Iter<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Iter") - .field(&self.clone()) + .field(&self.ring) + .field(&self.tail) + .field(&self.head) .finish() } } @@ -2000,7 +2002,9 @@ pub struct IterMut<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IterMut") - .field(&self.clone()) + .field(&self.ring) + .field(&self.tail) + .field(&self.head) .finish() } } @@ -2081,7 +2085,7 @@ pub struct IntoIter { impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IntoIter") - .field(&self.clone()) + .field(&self.inner) .finish() } } @@ -2139,7 +2143,9 @@ pub struct Drain<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Drain") - .field(&self.clone()) + .field(&self.after_tail) + .field(&self.after_head) + .field(&self.iter) .finish() } } From df383b95476d59c26e822bcda69d3255da61622c Mon Sep 17 00:00:00 2001 From: Michael Gattozzi Date: Wed, 19 Apr 2017 14:00:50 -0400 Subject: [PATCH 590/905] Fix link for wait --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index edcf206501a0..9d7f87f06c31 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -78,7 +78,7 @@ use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// run, even after the `Child` handle to the child process has gone out of /// scope. /// -/// Calling [`wait`] (or other functions that wrap around it) will make +/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make /// the parent process wait until the child has actually exited before /// continuing. /// From f85a5337ab0f8b492cb8df56a7c2af103010037e Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Wed, 19 Apr 2017 11:57:29 -0700 Subject: [PATCH 591/905] specialize Extend for Vec with IntoIter --- src/libcollections/tests/vec.rs | 22 ++++++++++++++++++++++ src/libcollections/vec.rs | 27 +++++++++++++++++++-------- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/libcollections/tests/vec.rs b/src/libcollections/tests/vec.rs index 63df0eb73050..64c76142b59d 100644 --- a/src/libcollections/tests/vec.rs +++ b/src/libcollections/tests/vec.rs @@ -84,6 +84,9 @@ fn test_extend() { let mut v = Vec::new(); let mut w = Vec::new(); + v.extend(w.clone()); + assert_eq!(v, &[]); + v.extend(0..3); for i in 0..3 { w.push(i) @@ -100,6 +103,25 @@ fn test_extend() { v.extend(w.clone()); // specializes to `append` assert!(v.iter().eq(w.iter().chain(w.iter()))); + + // Zero sized types + #[derive(PartialEq, Debug)] + struct Foo; + + let mut a = Vec::new(); + let b = vec![Foo, Foo]; + + a.extend(b); + assert_eq!(a, &[Foo, Foo]); + + // Double drop + let mut count_x = 0; + { + let mut x = Vec::new(); + let y = vec![DropCounter { count: &mut count_x }]; + x.extend(y); + } + assert_eq!(count_x, 1); } #[test] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 35ecf411db4e..bf5435922621 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1039,18 +1039,22 @@ impl Vec { #[inline] #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { - self.reserve(other.len()); - let len = self.len(); - unsafe { - ptr::copy_nonoverlapping(other.as_ptr(), self.get_unchecked_mut(len), other.len()); - } - - self.len += other.len(); unsafe { + self.append_elements(other.as_slice() as _); other.set_len(0); } } + /// Appends elements to `Self` from other buffer. + #[inline] + unsafe fn append_elements(&mut self, other: *const [T]) { + let count = (*other).len(); + self.reserve(count); + let len = self.len(); + ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count); + self.len += count; + } + /// Create a draining iterator that removes the specified range in the vector /// and yields the removed items. /// @@ -1681,7 +1685,7 @@ impl SpecExtend for Vec vector } - fn spec_extend(&mut self, iterator: I) { + default fn spec_extend(&mut self, iterator: I) { // This is the case for a TrustedLen iterator. let (low, high) = iterator.size_hint(); if let Some(high_value) = high { @@ -1726,6 +1730,13 @@ impl SpecExtend> for Vec { vector } } + + fn spec_extend(&mut self, mut iterator: IntoIter) { + unsafe { + self.append_elements(iterator.as_slice() as _); + } + iterator.ptr = iterator.end; + } } impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec From f7e9041cd2c7589c98e69339ded8d29a8746a669 Mon Sep 17 00:00:00 2001 From: Maxwell Paul Brickner Date: Wed, 19 Apr 2017 17:45:48 -0400 Subject: [PATCH 592/905] Updated links to use https I just updated a few links to use https instead of http. Thank you! ^ _ ^ --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fca7d1cc5bd3..f387b4be6008 100644 --- a/README.md +++ b/README.md @@ -198,8 +198,8 @@ The Rust community congregates in a few places: * [users.rust-lang.org] - General discussion and broader questions. * [/r/rust] - News and general discussion. -[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust -[/r/rust]: http://reddit.com/r/rust +[Stack Overflow]: https://stackoverflow.com/questions/tagged/rust +[/r/rust]: https://reddit.com/r/rust [users.rust-lang.org]: https://users.rust-lang.org/ ## Contributing From 3f5c311dc1dcb5bfe65d6eecd0dfda04d77c7594 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 17 Apr 2017 18:58:01 +0300 Subject: [PATCH 593/905] rustc: simplify TypeContents drastically. --- src/librustc/ty/contents.rs | 186 ++++++++---------------------------- src/librustc/ty/mod.rs | 2 +- 2 files changed, 41 insertions(+), 147 deletions(-) diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index e14295982916..c690795b3421 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -8,118 +8,45 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::def_id::{DefId}; use ty::{self, Ty, TyCtxt}; use util::common::MemoizationMap; use util::nodemap::FxHashMap; -use std::fmt; -use std::ops; - -use syntax::ast; - -/// Type contents is how the type checker reasons about kinds. -/// They track what kinds of things are found within a type. You can -/// think of them as kind of an "anti-kind". They track the kinds of values -/// and thinks that are contained in types. Having a larger contents for -/// a type tends to rule that type *out* from various kinds. For example, -/// a type that contains a reference is not sendable. -/// -/// The reason we compute type contents and not kinds is that it is -/// easier for me (nmatsakis) to think about what is contained within -/// a type than to think about what is *not* contained within a type. -#[derive(Clone, Copy)] -pub struct TypeContents { - pub bits: u64 -} - -macro_rules! def_type_content_sets { - (mod $mname:ident { $($name:ident = $bits:expr),+ }) => { - #[allow(non_snake_case)] - mod $mname { - use super::TypeContents; - $( - #[allow(non_upper_case_globals)] - pub const $name: TypeContents = TypeContents { bits: $bits }; - )+ - } - } -} - -def_type_content_sets! { - mod TC { - None = 0b0000_0000__0000_0000__0000, - - // Things that are interior to the value (first nibble): - InteriorUnsafe = 0b0000_0000__0000_0000__0010, - InteriorParam = 0b0000_0000__0000_0000__0100, - // InteriorAll = 0b00000000__00000000__1111, - - // Things that are owned by the value (second and third nibbles): - OwnsDtor = 0b0000_0000__0000_0010__0000, - // OwnsAll = 0b0000_0000__1111_1111__0000, - - // All bits - All = 0b1111_1111__1111_1111__1111 +bitflags! { + /// Type contents is how the type checker reasons about kinds. + /// They track what kinds of things are found within a type. You can + /// think of them as kind of an "anti-kind". They track the kinds of values + /// and thinks that are contained in types. Having a larger contents for + /// a type tends to rule that type *out* from various kinds. For example, + /// a type that contains a reference is not sendable. + /// + /// The reason we compute type contents and not kinds is that it is + /// easier for me (nmatsakis) to think about what is contained within + /// a type than to think about what is *not* contained within a type. + flags TypeContents: u8 { + const INTERIOR_UNSAFE = 0b01, + const OWNS_DTOR = 0b10, } } impl TypeContents { pub fn when(&self, cond: bool) -> TypeContents { - if cond {*self} else {TC::None} - } - - pub fn intersects(&self, tc: TypeContents) -> bool { - (self.bits & tc.bits) != 0 - } - - pub fn interior_param(&self) -> bool { - self.intersects(TC::InteriorParam) + if cond {*self} else {TypeContents::empty()} } pub fn interior_unsafe(&self) -> bool { - self.intersects(TC::InteriorUnsafe) + self.intersects(TypeContents::INTERIOR_UNSAFE) } pub fn needs_drop(&self, _: TyCtxt) -> bool { - self.intersects(TC::OwnsDtor) + self.intersects(TypeContents::OWNS_DTOR) } pub fn union(v: I, mut f: F) -> TypeContents where I: IntoIterator, F: FnMut(T) -> TypeContents, { - v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) - } -} - -impl ops::BitOr for TypeContents { - type Output = TypeContents; - - fn bitor(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits | other.bits} - } -} - -impl ops::BitAnd for TypeContents { - type Output = TypeContents; - - fn bitand(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & other.bits} - } -} - -impl ops::Sub for TypeContents { - type Output = TypeContents; - - fn sub(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & !other.bits} - } -} - -impl fmt::Debug for TypeContents { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeContents({:b})", self.bits) + v.into_iter().fold(TypeContents::empty(), |tc, ty| tc | f(ty)) } } @@ -139,19 +66,19 @@ impl<'a, 'tcx> ty::TyS<'tcx> { // // When computing the type contents of such a type, we wind up deeply // recursing as we go. So when we encounter the recursive reference - // to List, we temporarily use TC::None as its contents. Later we'll + // to List, we temporarily use TypeContents::empty() as its contents. Later we'll // patch up the cache with the correct value, once we've computed it // (this is basically a co-inductive process, if that helps). So in - // the end we'll compute TC::OwnsOwned, in this case. + // the end we'll compute TypeContents::OwnsOwned, in this case. // // The problem is, as we are doing the computation, we will also // compute an *intermediate* contents for, e.g., Option of - // TC::None. This is ok during the computation of List itself, but if + // TypeContents::empty(). This is ok during the computation of List itself, but if // we stored this intermediate value into tcx.tc_cache, then later - // requests for the contents of Option would also yield TC::None + // requests for the contents of Option would also yield TypeContents::empty() // which is incorrect. This value was computed based on the crutch // value for the type contents of list. The correct value is - // TC::OwnsOwned. This manifested as issue #4821. + // TypeContents::OwnsOwned. This manifested as issue #4821. if let Some(tc) = cache.get(&ty) { return *tc; } @@ -159,32 +86,14 @@ impl<'a, 'tcx> ty::TyS<'tcx> { if let Some(tc) = tcx.tc_cache.borrow().get(&ty) { return *tc; } - cache.insert(ty, TC::None); + cache.insert(ty, TypeContents::empty()); let result = match ty.sty { - // usize and isize are ffi-unsafe - ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => { - TC::None - } - - // Scalar and unique types are sendable, and durable ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { - TC::None - } - - ty::TyDynamic(..) => { - TC::All - TC::InteriorParam - } - - ty::TyRawPtr(_) => { - TC::None - } - - ty::TyRef(..) => { - TC::None - } + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(_) | ty::TyRef(..) | + ty::TyStr => TypeContents::empty(), ty::TyArray(ty, _) => { tc_ty(tcx, ty, cache) @@ -193,7 +102,6 @@ impl<'a, 'tcx> ty::TyS<'tcx> { ty::TySlice(ty) => { tc_ty(tcx, ty, cache) } - ty::TyStr => TC::None, ty::TyClosure(def_id, ref substs) => { TypeContents::union( @@ -207,29 +115,25 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } ty::TyAdt(def, substs) => { - let mut res = - TypeContents::union(&def.variants, |v| { - TypeContents::union(&v.fields, |f| { - tc_ty(tcx, f.ty(tcx, substs), cache) - }) - }); + TypeContents::union(&def.variants, |v| { + TypeContents::union(&v.fields, |f| { + tc_ty(tcx, f.ty(tcx, substs), cache) + }) + }) - if def.is_union() { - // unions don't have destructors regardless of the child types - res = res - TC::OwnsDtor; - } - - if def.has_dtor(tcx) { - res = res | TC::OwnsDtor; - } - - apply_lang_items(tcx, def.did, res) + // unions don't have destructors regardless of the child types + - TypeContents::OWNS_DTOR.when(def.is_union()) + | TypeContents::OWNS_DTOR.when(def.has_dtor(tcx)) + | TypeContents::INTERIOR_UNSAFE.when( + Some(def.did) == tcx.lang_items.unsafe_cell_type()) } + + ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | ty::TyAnon(..) => { - TC::All + TypeContents::INTERIOR_UNSAFE | TypeContents::OWNS_DTOR } ty::TyInfer(_) | @@ -241,15 +145,5 @@ impl<'a, 'tcx> ty::TyS<'tcx> { cache.insert(ty, result); result } - - fn apply_lang_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, tc: TypeContents) - -> TypeContents { - if Some(did) == tcx.lang_items.unsafe_cell_type() { - tc | TC::InteriorUnsafe - } else { - tc - } - } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ab1a06aeacd1..78d3885bb988 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2405,7 +2405,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // destructor (e.g. zero its memory on move). let contents = ty.type_contents(tcx); - debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); + debug!("type_needs_drop ty={:?} contents={:?}", ty, contents.bits()); contents.needs_drop(tcx) } From 6563374ed2e518ea5fec2b7411dc4331772c46d2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 17 Apr 2017 21:18:56 +0300 Subject: [PATCH 594/905] rustc: replace interior_unsafe with a Freeze trait. --- src/libcore/marker.rs | 17 ++++++++ src/librustc/middle/lang_items.rs | 1 + src/librustc/ty/contents.rs | 14 +------ src/librustc/ty/mod.rs | 8 ++++ src/librustc/ty/util.rs | 44 ++++++++++++++++++++ src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_passes/consts.rs | 4 +- src/librustc_trans/abi.rs | 6 +-- src/librustc_trans/consts.rs | 3 +- src/librustc_trans/context.rs | 4 ++ 10 files changed, 83 insertions(+), 20 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 393c01b0105c..c0aa650a1e85 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -16,6 +16,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use cell::UnsafeCell; use cmp; use hash::Hash; use hash::Hasher; @@ -553,3 +554,19 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {} } + +/// Compiler-internal trait used to determine whether a type contains +/// any `UnsafeCell` internally, but not through an indirection. +/// This affects, for example, whether a `static` of that type is +/// placed in read-only static memory or writable static memory. +#[cfg_attr(not(stage0), lang = "freeze")] +unsafe trait Freeze {} + +unsafe impl Freeze for .. {} + +impl !Freeze for UnsafeCell {} +unsafe impl Freeze for PhantomData {} +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 {} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 5989fa9007c4..32dfb63d6150 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -274,6 +274,7 @@ language_item_table! { UnsizeTraitLangItem, "unsize", unsize_trait; CopyTraitLangItem, "copy", copy_trait; SyncTraitLangItem, "sync", sync_trait; + FreezeTraitLangItem, "freeze", freeze_trait; DropTraitLangItem, "drop", drop_trait; diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index c690795b3421..a1cb848213a8 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -24,8 +24,7 @@ bitflags! { /// easier for me (nmatsakis) to think about what is contained within /// a type than to think about what is *not* contained within a type. flags TypeContents: u8 { - const INTERIOR_UNSAFE = 0b01, - const OWNS_DTOR = 0b10, + const OWNS_DTOR = 0b1, } } @@ -34,10 +33,6 @@ impl TypeContents { if cond {*self} else {TypeContents::empty()} } - pub fn interior_unsafe(&self) -> bool { - self.intersects(TypeContents::INTERIOR_UNSAFE) - } - pub fn needs_drop(&self, _: TyCtxt) -> bool { self.intersects(TypeContents::OWNS_DTOR) } @@ -124,17 +119,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> { // unions don't have destructors regardless of the child types - TypeContents::OWNS_DTOR.when(def.is_union()) | TypeContents::OWNS_DTOR.when(def.has_dtor(tcx)) - | TypeContents::INTERIOR_UNSAFE.when( - Some(def.did) == tcx.lang_items.unsafe_cell_type()) } - ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | - ty::TyAnon(..) => { - TypeContents::INTERIOR_UNSAFE | TypeContents::OWNS_DTOR - } + ty::TyAnon(..) => TypeContents::OWNS_DTOR, ty::TyInfer(_) | ty::TyError => { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 78d3885bb988..7325235ca7b7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -425,6 +425,8 @@ bitflags! { const IS_SIZED = 1 << 17, const MOVENESS_CACHED = 1 << 18, const MOVES_BY_DEFAULT = 1 << 19, + const FREEZENESS_CACHED = 1 << 20, + const IS_FREEZE = 1 << 21, } } @@ -1181,6 +1183,9 @@ pub struct ParameterEnvironment<'tcx> { /// A cache for `type_is_sized` pub is_sized_cache: RefCell, bool>>, + + /// A cache for `type_is_freeze` + pub is_freeze_cache: RefCell, bool>>, } impl<'a, 'tcx> ParameterEnvironment<'tcx> { @@ -1195,6 +1200,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { free_id_outlive: self.free_id_outlive, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), } } @@ -2531,6 +2537,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { free_id_outlive: free_id_outlive, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), } } @@ -2603,6 +2610,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { free_id_outlive: free_id_outlive, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), }; let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps)); diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 5334ee2835db..d43d570397b4 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -655,6 +655,50 @@ impl<'a, 'tcx> ty::TyS<'tcx> { result } + /// Returns `true` if and only if there are no `UnsafeCell`s + /// nested within the type (ignoring `PhantomData` or pointers). + #[inline] + pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>, + span: Span) -> bool + { + if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) { + return self.flags.get().intersects(TypeFlags::IS_FREEZE); + } + + self.is_freeze_uncached(tcx, param_env, span) + } + + fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>, + span: Span) -> bool { + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyStr | TyNever => Some(true), + + TyArray(..) | TySlice(_) | + TyTuple(..) | TyClosure(..) | TyAdt(..) | + TyDynamic(..) | TyProjection(..) | TyParam(..) | + TyInfer(..) | TyAnon(..) | TyError => None + }.unwrap_or_else(|| { + self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem), + ¶m_env.is_freeze_cache, span) }); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE + } else { + TypeFlags::FREEZENESS_CACHED + }); + } + + result + } + #[inline] pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 1313b24fa74f..cc7d25628432 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx> Qualif { fn restrict(&mut self, ty: Ty<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: &ty::ParameterEnvironment<'tcx>) { - if !ty.type_contents(tcx).interior_unsafe() { + if ty.is_freeze(tcx, param_env, DUMMY_SP) { *self = *self - Qualif::MUTABLE_INTERIOR; } if !tcx.type_needs_drop_given_env(ty, param_env) { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 2c4439f80a23..535c6a7ab9e1 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -46,7 +46,7 @@ use rustc::lint::builtin::CONST_ERR; use rustc::hir::{self, PatKind, RangeEnd}; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use std::collections::hash_map::Entry; @@ -85,7 +85,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { // Adds the worst effect out of all the values of one type. fn add_type(&mut self, ty: Ty<'gcx>) { - if ty.type_contents(self.tcx).interior_unsafe() { + if !ty.is_freeze(self.tcx, &self.param_env, DUMMY_SP) { self.promotable = false; } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c4fdc46d030c..e0a75f3caa7b 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -746,13 +746,13 @@ impl<'a, 'tcx> FnType<'tcx> { // `&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 interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe(); + let is_freeze = ccx.shared().type_is_freeze(mt.ty); - if mt.mutbl != hir::MutMutable && !interior_unsafe { + if mt.mutbl != hir::MutMutable && is_freeze { arg.attrs.set(ArgAttribute::NoAlias); } - if mt.mutbl == hir::MutImmutable && !interior_unsafe { + if mt.mutbl == hir::MutImmutable && is_freeze { arg.attrs.set(ArgAttribute::ReadOnly); } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 7a53a03344fc..eb3ac309be16 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -261,8 +261,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. if m != hir::MutMutable { - let tcontents = ty.type_contents(ccx.tcx()); - if !tcontents.interior_unsafe() { + if ccx.shared().type_is_freeze(ty) { llvm::LLVMSetGlobalConstant(g, llvm::True); } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c3770470bfd0..fd9ff17cc648 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -399,6 +399,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP) } + pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { + ty.is_freeze(self.tcx, &self.empty_param_env, DUMMY_SP) + } + pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { &self.exported_symbols } From 9ad3b94847db8cbee27947d7d62a6add28a9c0e9 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 17 Apr 2017 23:26:48 +0300 Subject: [PATCH 595/905] rustc: replace TypeContents::needs_drop with Ty::may_drop. --- src/librustc/ty/contents.rs | 139 ------------------------------------ src/librustc/ty/context.rs | 4 -- src/librustc/ty/mod.rs | 19 +++-- src/librustc/ty/util.rs | 79 +++++++++++++++++++- 4 files changed, 87 insertions(+), 154 deletions(-) delete mode 100644 src/librustc/ty/contents.rs diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs deleted file mode 100644 index a1cb848213a8..000000000000 --- a/src/librustc/ty/contents.rs +++ /dev/null @@ -1,139 +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 ty::{self, Ty, TyCtxt}; -use util::common::MemoizationMap; -use util::nodemap::FxHashMap; - -bitflags! { - /// Type contents is how the type checker reasons about kinds. - /// They track what kinds of things are found within a type. You can - /// think of them as kind of an "anti-kind". They track the kinds of values - /// and thinks that are contained in types. Having a larger contents for - /// a type tends to rule that type *out* from various kinds. For example, - /// a type that contains a reference is not sendable. - /// - /// The reason we compute type contents and not kinds is that it is - /// easier for me (nmatsakis) to think about what is contained within - /// a type than to think about what is *not* contained within a type. - flags TypeContents: u8 { - const OWNS_DTOR = 0b1, - } -} - -impl TypeContents { - pub fn when(&self, cond: bool) -> TypeContents { - if cond {*self} else {TypeContents::empty()} - } - - pub fn needs_drop(&self, _: TyCtxt) -> bool { - self.intersects(TypeContents::OWNS_DTOR) - } - - pub fn union(v: I, mut f: F) -> TypeContents where - I: IntoIterator, - F: FnMut(T) -> TypeContents, - { - v.into_iter().fold(TypeContents::empty(), |tc, ty| tc | f(ty)) - } -} - -impl<'a, 'tcx> ty::TyS<'tcx> { - pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents { - return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap())); - - fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - cache: &mut FxHashMap, TypeContents>) -> TypeContents - { - // Subtle: Note that we are *not* using tcx.tc_cache here but rather a - // private cache for this walk. This is needed in the case of cyclic - // types like: - // - // struct List { next: Box>, ... } - // - // When computing the type contents of such a type, we wind up deeply - // recursing as we go. So when we encounter the recursive reference - // to List, we temporarily use TypeContents::empty() as its contents. Later we'll - // patch up the cache with the correct value, once we've computed it - // (this is basically a co-inductive process, if that helps). So in - // the end we'll compute TypeContents::OwnsOwned, in this case. - // - // The problem is, as we are doing the computation, we will also - // compute an *intermediate* contents for, e.g., Option of - // TypeContents::empty(). This is ok during the computation of List itself, but if - // we stored this intermediate value into tcx.tc_cache, then later - // requests for the contents of Option would also yield TypeContents::empty() - // which is incorrect. This value was computed based on the crutch - // value for the type contents of list. The correct value is - // TypeContents::OwnsOwned. This manifested as issue #4821. - if let Some(tc) = cache.get(&ty) { - return *tc; - } - // Must check both caches! - if let Some(tc) = tcx.tc_cache.borrow().get(&ty) { - return *tc; - } - cache.insert(ty, TypeContents::empty()); - - let result = match ty.sty { - ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | - ty::TyRawPtr(_) | ty::TyRef(..) | - ty::TyStr => TypeContents::empty(), - - ty::TyArray(ty, _) => { - tc_ty(tcx, ty, cache) - } - - ty::TySlice(ty) => { - tc_ty(tcx, ty, cache) - } - - ty::TyClosure(def_id, ref substs) => { - TypeContents::union( - substs.upvar_tys(def_id, tcx), - |ty| tc_ty(tcx, &ty, cache)) - } - - ty::TyTuple(ref tys, _) => { - TypeContents::union(&tys[..], - |ty| tc_ty(tcx, *ty, cache)) - } - - ty::TyAdt(def, substs) => { - TypeContents::union(&def.variants, |v| { - TypeContents::union(&v.fields, |f| { - tc_ty(tcx, f.ty(tcx, substs), cache) - }) - }) - - // unions don't have destructors regardless of the child types - - TypeContents::OWNS_DTOR.when(def.is_union()) - | TypeContents::OWNS_DTOR.when(def.has_dtor(tcx)) - } - - ty::TyDynamic(..) | - ty::TyProjection(..) | - ty::TyParam(_) | - ty::TyAnon(..) => TypeContents::OWNS_DTOR, - - ty::TyInfer(_) | - ty::TyError => { - bug!("asked to compute contents of error type"); - } - }; - - cache.insert(ty, result); - result - } - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 8b7438c0bfad..a41629258716 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -436,9 +436,6 @@ pub struct GlobalCtxt<'tcx> { // Internal cache for metadata decoding. No need to track deps on this. pub rcache: RefCell>>, - // Cache for the type-contents routine. FIXME -- track deps? - pub tc_cache: RefCell, ty::contents::TypeContents>>, - // FIXME dep tracking -- should be harmless enough pub normalized_cache: RefCell, Ty<'tcx>>>, @@ -708,7 +705,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { freevars: RefCell::new(resolutions.freevars), maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports, rcache: RefCell::new(FxHashMap()), - tc_cache: RefCell::new(FxHashMap()), normalized_cache: RefCell::new(FxHashMap()), inhabitedness_cache: RefCell::new(FxHashMap()), lang_items: lang_items, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7325235ca7b7..b6e47568ff4d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -71,7 +71,6 @@ pub use self::sty::InferTy::*; pub use self::sty::Region::*; pub use self::sty::TypeVariants::*; -pub use self::contents::TypeContents; pub use self::context::{TyCtxt, GlobalArenas, tls}; pub use self::context::{Lift, TypeckTables}; @@ -99,7 +98,6 @@ pub mod walk; pub mod wf; pub mod util; -mod contents; mod context; mod flags; mod instance; @@ -427,6 +425,8 @@ bitflags! { const MOVES_BY_DEFAULT = 1 << 19, const FREEZENESS_CACHED = 1 << 20, const IS_FREEZE = 1 << 21, + const MAY_DROP_CACHED = 1 << 22, + const MAY_DROP = 1 << 23, } } @@ -2400,19 +2400,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if implements_copy { return false; } // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking if the `needs_drop` bit is set; we need - // not zero non-Copy types if they have no destructor. + // prior logic of asking for the structural `may_drop`. - // FIXME(#22815): Note that calling `ty::type_contents` is a - // conservative heuristic; it may report that `needs_drop` is set + // FIXME(#22815): Note that calling `ty::may_drop` is a + // conservative heuristic; it may report `true` ("may drop") // when actual type does not actually have a destructor associated // with it. But since `ty` absolutely did not have the `Copy` // bound attached (see above), it is sound to treat it as having a - // destructor (e.g. zero its memory on move). + // destructor. - let contents = ty.type_contents(tcx); - debug!("type_needs_drop ty={:?} contents={:?}", ty, contents.bits()); - contents.needs_drop(tcx) + let may_drop = ty.may_drop(tcx); + debug!("type_needs_drop ty={:?} may_drop={:?}", ty, may_drop); + may_drop } /// Get the attributes of a definition. diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index d43d570397b4..a3d2518909d7 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -21,7 +21,7 @@ use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; use ty::TypeVariants::*; use util::common::ErrorReported; -use util::nodemap::FxHashMap; +use util::nodemap::{FxHashMap, FxHashSet}; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; @@ -699,6 +699,83 @@ impl<'a, 'tcx> ty::TyS<'tcx> { result } + #[inline] + pub fn may_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + if self.flags.get().intersects(TypeFlags::MAY_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::MAY_DROP); + } + + self.may_drop_inner(tcx, &mut FxHashSet()) + } + + fn may_drop_inner(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + visited: &mut FxHashSet>) + -> bool { + if self.flags.get().intersects(TypeFlags::MAY_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::MAY_DROP); + } + + // This should be reported as an error by `check_representable`. + // + // Consider the type as not needing drop in the meanwhile to avoid + // further errors. + if visited.replace(self).is_some() { + return false; + } + + assert!(!self.needs_infer()); + + let result = match self.sty { + // Fast-path for primitive types + ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + + // User destructors are the only way to have concrete drop types. + ty::TyAdt(def, _) if def.has_dtor(tcx) => true, + + // Can refer to a type which may drop. + // FIXME(eddyb) check this against a ParameterEnvironment. + ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | + ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true, + + // Structural recursion. + ty::TyArray(ty, _) | ty::TySlice(ty) => { + ty.may_drop_inner(tcx, visited) + } + + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx) + .any(|ty| ty.may_drop_inner(tcx, visited)) + } + + ty::TyTuple(ref tys, _) => { + tys.iter().any(|ty| ty.may_drop_inner(tcx, visited)) + } + + // unions don't have destructors regardless of the child types + ty::TyAdt(def, _) if def.is_union() => false, + + ty::TyAdt(def, substs) => { + def.variants.iter().any(|v| { + v.fields.iter().any(|f| { + f.ty(tcx, substs).may_drop_inner(tcx, visited) + }) + }) + } + }; + + self.flags.set(self.flags.get() | if result { + TypeFlags::MAY_DROP_CACHED | TypeFlags::MAY_DROP + } else { + TypeFlags::MAY_DROP_CACHED + }); + + result + } + #[inline] pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { From 0adfd810f8aa16ce9e63f6feae182db0ba4833ef Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 18 Apr 2017 00:22:55 +0300 Subject: [PATCH 596/905] rustc: combine type_needs_drop_given_env and may_drop into needs_drop. --- src/librustc/ty/mod.rs | 37 +--------- src/librustc/ty/util.rs | 78 +++++++++++++++----- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 2 +- src/librustc_mir/transform/inline.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/util/elaborate_drops.rs | 3 +- src/librustc_passes/consts.rs | 2 +- src/librustc_trans/context.rs | 2 +- 10 files changed, 68 insertions(+), 64 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b6e47568ff4d..5c0889976c21 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -425,8 +425,8 @@ bitflags! { const MOVES_BY_DEFAULT = 1 << 19, const FREEZENESS_CACHED = 1 << 20, const IS_FREEZE = 1 << 21, - const MAY_DROP_CACHED = 1 << 22, - const MAY_DROP = 1 << 23, + const NEEDS_DROP_CACHED = 1 << 22, + const NEEDS_DROP = 1 << 23, } } @@ -2381,39 +2381,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Some(self.item_mir(did)) } - /// If `type_needs_drop` returns true, then `ty` is definitely - /// non-copy and *might* have a destructor attached; if it returns - /// false, then `ty` definitely has no destructor (i.e. no drop glue). - /// - /// (Note that this implies that if `ty` has a destructor attached, - /// then `type_needs_drop` will definitely return `true` for `ty`.) - pub fn type_needs_drop_given_env(self, - ty: Ty<'gcx>, - param_env: &ty::ParameterEnvironment<'gcx>) -> bool { - // Issue #22536: We first query type_moves_by_default. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - let tcx = self.global_tcx(); - let implements_copy = !ty.moves_by_default(tcx, param_env, DUMMY_SP); - - if implements_copy { return false; } - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking for the structural `may_drop`. - - // FIXME(#22815): Note that calling `ty::may_drop` is a - // conservative heuristic; it may report `true` ("may drop") - // when actual type does not actually have a destructor associated - // with it. But since `ty` absolutely did not have the `Copy` - // bound attached (see above), it is sound to treat it as having a - // destructor. - - let may_drop = ty.may_drop(tcx); - debug!("type_needs_drop ty={:?} may_drop={:?}", ty, may_drop); - may_drop - } - /// Get the attributes of a definition. pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> { if let Some(id) = self.hir.as_local_node_id(did) { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index a3d2518909d7..49d79f6545e2 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -699,31 +699,52 @@ impl<'a, 'tcx> ty::TyS<'tcx> { result } + /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely + /// non-copy and *might* have a destructor attached; if it returns + /// `false`, then `ty` definitely has no destructor (i.e. no drop glue). + /// + /// (Note that this implies that if `ty` has a destructor attached, + /// then `needs_drop` will definitely return `true` for `ty`.) #[inline] - pub fn may_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - if self.flags.get().intersects(TypeFlags::MAY_DROP_CACHED) { - return self.flags.get().intersects(TypeFlags::MAY_DROP); + pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>) -> bool { + if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::NEEDS_DROP); } - self.may_drop_inner(tcx, &mut FxHashSet()) + self.needs_drop_uncached(tcx, param_env, &mut FxHashSet()) } - fn may_drop_inner(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - visited: &mut FxHashSet>) - -> bool { - if self.flags.get().intersects(TypeFlags::MAY_DROP_CACHED) { - return self.flags.get().intersects(TypeFlags::MAY_DROP); + fn needs_drop_inner(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + stack: &mut FxHashSet>) + -> bool { + if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::NEEDS_DROP); } // This should be reported as an error by `check_representable`. // // Consider the type as not needing drop in the meanwhile to avoid // further errors. - if visited.replace(self).is_some() { + if let Some(_) = stack.replace(self) { return false; } + let needs_drop = self.needs_drop_uncached(tcx, param_env, stack); + + // "Pop" the cycle detection "stack". + stack.remove(self); + + needs_drop + } + + fn needs_drop_uncached(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + stack: &mut FxHashSet>) + -> bool { assert!(!self.needs_infer()); let result = match self.sty { @@ -733,6 +754,21 @@ impl<'a, 'tcx> ty::TyS<'tcx> { ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false, + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking for the structural "may drop". + + // FIXME(#22815): Note that this is a conservative heuristic; + // it may report that the type "may drop" when actual type does + // not actually have a destructor associated with it. But since + // the type absolutely did not have the `Copy` bound attached + // (see above), it is sound to treat it as having a destructor. + // User destructors are the only way to have concrete drop types. ty::TyAdt(def, _) if def.has_dtor(tcx) => true, @@ -743,16 +779,16 @@ impl<'a, 'tcx> ty::TyS<'tcx> { // Structural recursion. ty::TyArray(ty, _) | ty::TySlice(ty) => { - ty.may_drop_inner(tcx, visited) + ty.needs_drop_inner(tcx, param_env, stack) } ty::TyClosure(def_id, ref substs) => { substs.upvar_tys(def_id, tcx) - .any(|ty| ty.may_drop_inner(tcx, visited)) + .any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) } ty::TyTuple(ref tys, _) => { - tys.iter().any(|ty| ty.may_drop_inner(tcx, visited)) + tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) } // unions don't have destructors regardless of the child types @@ -761,17 +797,19 @@ impl<'a, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, substs) => { def.variants.iter().any(|v| { v.fields.iter().any(|f| { - f.ty(tcx, substs).may_drop_inner(tcx, visited) + f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack) }) }) } }; - self.flags.set(self.flags.get() | if result { - TypeFlags::MAY_DROP_CACHED | TypeFlags::MAY_DROP - } else { - TypeFlags::MAY_DROP_CACHED - }); + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP + } else { + TypeFlags::NEEDS_DROP_CACHED + }); + } result } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index dc01cbe5e760..de5613dbfaa3 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -322,7 +322,7 @@ fn on_all_drop_children_bits<'a, 'tcx, F>( let ty = lvalue.ty(mir, tcx).to_ty(tcx); debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty); - if tcx.type_needs_drop_given_env(ty, &ctxt.param_env) { + if ty.needs_drop(tcx, &ctxt.param_env) { each_child(child); } else { debug!("on_all_drop_children_bits - skipping") diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 0ee9d4a42c7f..1c69f3cff172 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1152,7 +1152,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { let field_ty = ctx.tcx.item_type(ctx.tcx.hir.local_def_id(field.id)); - if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) { + if field_ty.needs_drop(ctx.tcx, param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, "union contains a field with possibly non-trivial drop code, \ diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 5f9fb8e1b120..db9da2a280b9 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -168,7 +168,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { type with inference types/regions", ty); }); - self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment) + ty.needs_drop(self.tcx.global_tcx(), &self.infcx.parameter_environment) } pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index ac2bdaad24f7..892d67ac2372 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -357,7 +357,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // a regular goto. let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs); let ty = ty.to_ty(tcx); - if tcx.type_needs_drop_given_env(ty, ¶m_env) { + if ty.needs_drop(tcx, ¶m_env) { cost += CALL_PENALTY; if let Some(unwind) = unwind { work_list.push(unwind); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index cc7d25628432..526c1488ab48 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> Qualif { if ty.is_freeze(tcx, param_env, DUMMY_SP) { *self = *self - Qualif::MUTABLE_INTERIOR; } - if !tcx.type_needs_drop_given_env(ty, param_env) { + if !ty.needs_drop(tcx, param_env) { *self = *self - Qualif::NEEDS_DROP; } } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 04a1fc891cf1..07025fcfdb94 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -277,8 +277,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let mut fields = fields; fields.retain(|&(ref lvalue, _)| { - self.tcx().type_needs_drop_given_env( - self.lvalue_ty(lvalue), self.elaborator.param_env()) + self.lvalue_ty(lvalue).needs_drop(self.tcx(), self.elaborator.param_env()) }); debug!("drop_ladder - fields needing drop: {:?}", fields); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 535c6a7ab9e1..fdb675221337 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -89,7 +89,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { self.promotable = false; } - if self.tcx.type_needs_drop_given_env(ty, &self.param_env) { + if ty.needs_drop(self.tcx, &self.param_env) { self.promotable = false; } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index fd9ff17cc648..1d1921bf7b96 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -392,7 +392,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { } pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - self.tcx.type_needs_drop_given_env(ty, &self.empty_param_env) + ty.needs_drop(self.tcx, &self.empty_param_env) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { From 61b7ebe7d3fbe19c7aaf7b8fa5b9661eccca6061 Mon Sep 17 00:00:00 2001 From: Nicolas Bigaouette Date: Thu, 20 Apr 2017 11:20:33 -0400 Subject: [PATCH 597/905] Rename environment variable `GDB_CMD` to `RUST_GDB` to prevent ambiguity --- src/etc/rust-gdb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index ef1689886cb8..52601cd96f80 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -17,10 +17,10 @@ RUSTC_SYSROOT=`rustc --print=sysroot` GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # Run GDB with the additional arguments that load the pretty printers -# Set the environment variable `GDB_CMD` to overwrite the call to a +# Set the environment variable `RUST_GDB` to overwrite the call to a # different/specific command (defaults to `gdb`). -GDB_CMD="${GDB_CMD:-gdb}" -PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${GDB_CMD} \ +RUST_GDB="${RUST_GDB:-gdb}" +PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${RUST_GDB} \ -d "$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ "$@" From 416d6b73dfb583e2b81369b046f24194773146bf Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 20 Apr 2017 13:59:41 -0300 Subject: [PATCH 598/905] Update libc to include x86_64-linux-android support --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 05a2d197356e..c34a802d1eb0 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f +Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 From a65461005a496f0713e5422647b46f53eee34feb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 20 Apr 2017 00:31:34 +0200 Subject: [PATCH 599/905] Fix line display for hoedown --- src/librustdoc/html/markdown.rs | 10 +++++++--- src/librustdoc/lib.rs | 1 + src/librustdoc/test.rs | 35 +++++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b02b60531d10..4bf856240f66 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -492,7 +492,7 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position text: *const hoedown_buffer, lang: *const hoedown_buffer, data: *const hoedown_renderer_data, - line: libc::size_t) { + _line: libc::size_t) { unsafe { if text.is_null() { return } let block_info = if lang.is_null() { @@ -503,11 +503,15 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position LangString::parse(s) }; if !block_info.rust { return } + let text = (*text).as_bytes(); let opaque = (*data).opaque as *mut hoedown_html_renderer_state; let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - let line = tests.get_line() + line; + let text = str::from_utf8(text).unwrap(); + let lines = text.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); let filename = tests.get_filename(); - tests.add_old_test(line, filename); + tests.add_old_test(lines.collect::>().join("\n"), filename); } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d5b997001bb9..0ca267bb82d2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -27,6 +27,7 @@ #![feature(staged_api)] #![feature(test)] #![feature(unicode)] +#![feature(vec_remove_item)] extern crate arena; extern crate getopts; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index fb681b20065f..3206b5021075 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::HashMap; use std::env; use std::ffi::OsString; use std::io::prelude::*; @@ -381,7 +382,7 @@ fn partition_source(s: &str) -> (String, String) { pub struct Collector { pub tests: Vec, // to be removed when hoedown will be definitely gone - pub old_tests: Vec, + pub old_tests: HashMap>, names: Vec, cfgs: Vec, libs: SearchPaths, @@ -403,7 +404,7 @@ impl Collector { codemap: Option>, filename: Option) -> Collector { Collector { tests: Vec::new(), - old_tests: Vec::new(), + old_tests: HashMap::new(), names: Vec::new(), cfgs: cfgs, libs: libs, @@ -432,9 +433,24 @@ impl Collector { } } - pub fn add_old_test(&mut self, line: usize, filename: String) { - let name = self.generate_name(line, &filename); - self.old_tests.push(name); + // to be removed once hoedown is gone + fn generate_name_beginning(&self, filename: &str) -> String { + if self.use_headers { + if let Some(ref header) = self.current_header { + format!("{} - {} (line", filename, header) + } else { + format!("{} - (line", filename) + } + } else { + format!("{} - {} (line", filename, self.names.join("::")) + } + } + + pub fn add_old_test(&mut self, test: String, filename: String) { + let name_beg = self.generate_name_beginning(&filename); + let entry = self.old_tests.entry(name_beg) + .or_insert(Vec::new()); + entry.push(test.trim().to_owned()); } pub fn add_test(&mut self, test: String, @@ -442,7 +458,14 @@ impl Collector { as_test_harness: bool, compile_fail: bool, error_codes: Vec, line: usize, filename: String) { let name = self.generate_name(line, &filename); - if self.old_tests.iter().find(|&x| x == &name).is_none() { + let name_beg = self.generate_name_beginning(&filename); + let mut found = false; + // to be removed when hoedown is removed + let test = test.trim().to_owned(); + if let Some(entry) = self.old_tests.get_mut(&name_beg) { + found = entry.remove_item(&test).is_some(); + } + if !found { let _ = writeln!(&mut io::stderr(), "WARNING: {} Code block is not currently run as a test, but will in \ future versions of rustdoc. Please ensure this code block is a \ From 3b4d34d4faa10336847335e68417f49eb8882693 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 18 Apr 2017 12:20:02 -0700 Subject: [PATCH 600/905] Expanded docs and examples for PathBuf::file_name and friends --- src/libstd/path.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 812b65b61e7f..15bc74a83401 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1189,8 +1189,13 @@ impl PathBuf { /// If [`self.file_name`] was [`None`], this is equivalent to pushing /// `file_name`. /// + /// Otherwise it is equivalent to calling [`pop`] and then pushing + /// `file_name`. The new path will be a sibling of the original path. + /// (That is, it will have the same parent.) + /// /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`pop`]: struct.PathBuf.html#method.pop /// /// # Examples /// @@ -1725,7 +1730,10 @@ impl Path { }) } - /// Returns the final component of the `Path`, if it is a normal file. + /// Returns the final component of the `Path`, if there is one. + /// + /// If the path is a normal file, this is the file name. If it's the path of a directory, this + /// is the directory name. /// /// Returns [`None`] If the path terminates in `..`. /// @@ -1737,10 +1745,12 @@ impl Path { /// use std::path::Path; /// use std::ffi::OsStr; /// - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt").file_name()); + /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name()); + /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").file_name()); + /// assert_eq!(None, Path::new("/").file_name()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { @@ -1926,6 +1936,9 @@ impl Path { /// /// let path = Path::new("/tmp/foo.txt"); /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt")); + /// + /// let path = Path::new("/tmp"); + /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name>(&self, file_name: S) -> PathBuf { From 51cc0e38e34d5ded08403bae351ecf4ee317573d Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 20 Apr 2017 14:02:42 -0300 Subject: [PATCH 601/905] Add x86_64-linux-android target --- configure | 2 + src/bootstrap/config.rs | 6 ++ src/ci/docker/dist-android/Dockerfile | 6 +- src/ci/docker/dist-android/install-ndk.sh | 8 ++- src/librustc_back/target/mod.rs | 1 + .../target/x86_64_linux_android.rs | 34 ++++++++++ src/libstd/os/android/raw.rs | 63 +++++++++++++++++++ src/tools/build-manifest/src/main.rs | 1 + 8 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 src/librustc_back/target/x86_64_linux_android.rs diff --git a/configure b/configure index 35b376d5f27b..c5ecc2236894 100755 --- a/configure +++ b/configure @@ -479,6 +479,7 @@ valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path" valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path" valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path" +valopt x86_64-linux-android-ndk "" "x86_64-linux-android NDK standalone path" valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!" valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)" valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory" @@ -746,6 +747,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK putvar CFG_ARM_LINUX_ANDROIDEABI_NDK putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK putvar CFG_I686_LINUX_ANDROID_NDK +putvar CFG_X86_64_LINUX_ANDROID_NDK putvar CFG_NACL_CROSS_PATH putvar CFG_MANDIR putvar CFG_DOCDIR diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 693114d01ad9..34fbc33d981a 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -570,6 +570,12 @@ impl Config { .or_insert(Target::default()); target.ndk = Some(parse_configure_path(value)); } + "CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => { + let target = "x86_64-linux-android".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.ndk = Some(parse_configure_path(value)); + } "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { let path = parse_configure_path(value); self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 99c176aa820c..28cc885ed30d 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -36,9 +36,10 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi +ENV TARGETS=$TARGETS,armv7-linux-androideabi ENV TARGETS=$TARGETS,i686-linux-android ENV TARGETS=$TARGETS,aarch64-linux-android -ENV TARGETS=$TARGETS,armv7-linux-androideabi +ENV TARGETS=$TARGETS,x86_64-linux-android ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ @@ -46,6 +47,7 @@ ENV RUST_CONFIGURE_ARGS \ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ --i686-linux-android-ndk=/android/ndk-x86-9 \ - --aarch64-linux-android-ndk=/android/ndk-aarch64 + --aarch64-linux-android-ndk=/android/ndk-arm64-21 \ + --x86_64-linux-android-ndk=/android/ndk-x86_64-21 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-android/install-ndk.sh b/src/ci/docker/dist-android/install-ndk.sh index 19c1b94e784c..d3a2d3175454 100644 --- a/src/ci/docker/dist-android/install-ndk.sh +++ b/src/ci/docker/dist-android/install-ndk.sh @@ -25,7 +25,7 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --platform=android-21 \ --toolchain=aarch64-linux-android-4.9 \ - --install-dir=/android/ndk-aarch64 \ + --install-dir=/android/ndk-arm64-21 \ --ndk-dir=/android/android-ndk-r11c \ --arch=arm64 bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ @@ -34,5 +34,11 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --install-dir=/android/ndk-x86-9 \ --ndk-dir=/android/android-ndk-r11c \ --arch=x86 +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-21 \ + --toolchain=x86_64-4.9 \ + --install-dir=/android/ndk-x86_64-21 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=x86_64 rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index ca6894a7b704..e60fdc386ce6 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -162,6 +162,7 @@ supported_targets! { ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), ("i686-linux-android", i686_linux_android), + ("x86_64-linux-android", x86_64_linux_android), ("arm-linux-androideabi", arm_linux_androideabi), ("armv7-linux-androideabi", armv7_linux_androideabi), ("aarch64-linux-android", aarch64_linux_android), diff --git a/src/librustc_back/target/x86_64_linux_android.rs b/src/librustc_back/target/x86_64_linux_android.rs new file mode 100644 index 000000000000..75cf3e124384 --- /dev/null +++ b/src/librustc_back/target/x86_64_linux_android.rs @@ -0,0 +1,34 @@ +// 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 LinkerFlavor; +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::android_base::opts(); + base.cpu = "x86-64".to_string(); + // https://developer.android.com/ndk/guides/abis.html#86-64 + base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string(); + base.max_atomic_width = Some(64); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + + Ok(Target { + llvm_target: "x86_64-linux-android".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), + arch: "x86_64".to_string(), + target_os: "android".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: base, + }) +} diff --git a/src/libstd/os/android/raw.rs b/src/libstd/os/android/raw.rs index 5e473a933a67..60ad8fcc54cc 100644 --- a/src/libstd/os/android/raw.rs +++ b/src/libstd/os/android/raw.rs @@ -165,3 +165,66 @@ mod arch { } } +#[cfg(target_arch = "x86_64")] +mod arch { + use os::raw::{c_uint, c_long, c_ulong}; + use os::unix::raw::{uid_t, gid_t}; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type dev_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type mode_t = u32; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: c_uint, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: uid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: gid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_ulong, + __unused: [c_long; 3], + } +} + diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 28c8d2270732..a8cb30da4351 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -81,6 +81,7 @@ static TARGETS: &'static [&'static str] = &[ "s390x-unknown-linux-gnu", "sparc64-unknown-linux-gnu", "wasm32-unknown-emscripten", + "x86_64-linux-android", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-pc-windows-gnu", From 865f5d099c6912a3f539e6c1db207d67accdd31f Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 21 Apr 2017 09:20:04 +1200 Subject: [PATCH 602/905] Bump the rls submodule revision --- rls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rls b/rls index 016cbc514cf4..6ecff95fdc3e 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 +Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce From 4358e35fda66ab7a00215c7f9d50e7c6dc9b801b Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sun, 15 Jan 2017 09:49:29 +1100 Subject: [PATCH 603/905] Implementation of repr struct alignment RFC 1358. The main changes around rustc::ty::Layout::struct and rustc_trans:adt: * Added primitive_align field which stores alignment before repr align * Always emit field padding when generating the LLVM struct fields * Added methods for adjusting field indexes from the layout index to the LLVM struct field index The main user of this information is rustc_trans::adt::struct_llfields which determines the LLVM fields to be used by LLVM, including padding fields. --- src/librustc/diagnostics.rs | 3 +- src/librustc/hir/check_attr.rs | 17 ++ src/librustc/ty/layout.rs | 89 +++++++- src/librustc/ty/mod.rs | 11 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/adt.rs | 84 ++++++-- src/librustc_trans/builder.rs | 12 +- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_trans/mir/block.rs | 12 +- src/librustc_trans/mir/lvalue.rs | 17 +- src/librustc_trans/mir/mod.rs | 2 +- src/librustc_trans/mir/operand.rs | 36 ++-- src/librustc_trans/mir/rvalue.rs | 16 +- src/librustc_trans/type_of.rs | 10 + src/librustc_typeck/check/mod.rs | 47 +++++ src/librustc_typeck/diagnostics.rs | 1 + src/libsyntax/attr.rs | 50 ++++- src/libsyntax/diagnostic_list.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/test/compile-fail/attr-usage-repr.rs | 4 + .../compile-fail/conflicting-repr-hints.rs | 8 +- src/test/compile-fail/repr-align.rs | 22 ++ .../repr-packed-contains-align.rs | 24 +++ src/test/run-pass/align-struct.rs | 195 ++++++++++++++++++ src/test/ui/print_type_sizes/repr-align.rs | 42 ++++ .../ui/print_type_sizes/repr-align.stdout | 16 ++ 26 files changed, 647 insertions(+), 79 deletions(-) create mode 100644 src/test/compile-fail/repr-align.rs create mode 100644 src/test/compile-fail/repr-packed-contains-align.rs create mode 100644 src/test/run-pass/align-struct.rs create mode 100644 src/test/ui/print_type_sizes/repr-align.rs create mode 100644 src/test/ui/print_type_sizes/repr-align.stdout diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 618561f3b025..2851191dc141 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1847,5 +1847,6 @@ register_diagnostics! { E0489, // type/lifetime parameter not in scope here E0490, // a value of type `..` is borrowed for too long E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0566 // conflicting representation hints + E0566, // conflicting representation hints + E0587, // conflicting packed and align representation hints } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 54ae94721409..bf292ccb8d86 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -57,6 +57,9 @@ impl<'a> CheckAttrVisitor<'a> { }; let mut conflicting_reprs = 0; + let mut found_packed = false; + let mut found_align = false; + for word in words { let name = match word.name() { @@ -84,6 +87,7 @@ impl<'a> CheckAttrVisitor<'a> { ("attribute should be applied to struct or union", "a struct or union") } else { + found_packed = true; continue } } @@ -96,6 +100,15 @@ impl<'a> CheckAttrVisitor<'a> { continue } } + "align" => { + found_align = true; + if target != Target::Struct { + ("attribute should be applied to struct", + "a struct") + } else { + continue + } + } "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "isize" | "usize" => { @@ -117,6 +130,10 @@ impl<'a> CheckAttrVisitor<'a> { span_warn!(self.sess, attr.span, E0566, "conflicting representation hints"); } + if found_align && found_packed { + struct_span_err!(self.sess, attr.span, E0587, + "conflicting packed and align representation hints").emit(); + } } fn check_attribute(&self, attr: &ast::Attribute, target: Target) { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index df60eee8c024..6a206640b3ba 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -548,8 +548,12 @@ pub type FieldPath = Vec; /// A structure, a product type in ADT terms. #[derive(PartialEq, Eq, Hash, Debug)] pub struct Struct { + /// Maximum alignment of fields and repr alignment. pub align: Align, + /// Primitive alignment of fields without repr alignment. + pub primitive_align: Align, + /// If true, no alignment padding is used. pub packed: bool, @@ -583,10 +587,20 @@ impl<'a, 'gcx, 'tcx> Struct { fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, repr: &ReprOptions, kind: StructKind, scapegoat: Ty<'gcx>) -> Result> { - let packed = repr.packed(); + if repr.packed() && repr.align > 0 { + bug!("Struct cannot be packed and aligned"); + } + + let align = if repr.packed() { + dl.i8_align + } else { + dl.aggregate_align + }; + let mut ret = Struct { - align: if packed { dl.i8_align } else { dl.aggregate_align }, - packed: packed, + align: align, + primitive_align: align, + packed: repr.packed(), sized: true, offsets: vec![], memory_index: vec![], @@ -660,7 +674,9 @@ impl<'a, 'gcx, 'tcx> Struct { // Invariant: offset < dl.obj_size_bound() <= 1<<61 if !ret.packed { let align = field.align(dl); + let primitive_align = field.primitive_align(dl); ret.align = ret.align.max(align); + ret.primitive_align = ret.primitive_align.max(primitive_align); offset = offset.abi_align(align); } @@ -671,6 +687,11 @@ impl<'a, 'gcx, 'tcx> Struct { .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?; } + if repr.align > 0 { + let repr_align = repr.align as u64; + ret.align = ret.align.max(Align::from_bytes(repr_align, repr_align).unwrap()); + debug!("Struct::new repr_align: {:?}", repr_align); + } debug!("Struct::new min_size: {:?}", offset); ret.min_size = offset; @@ -836,12 +857,23 @@ impl<'a, 'gcx, 'tcx> Struct { } Ok(None) } + + pub fn over_align(&self) -> Option { + let align = self.align.abi(); + let primitive_align = self.primitive_align.abi(); + if align > primitive_align { + Some(align as u32) + } else { + None + } + } } /// An untagged union. #[derive(PartialEq, Eq, Hash, Debug)] pub struct Union { pub align: Align, + pub primitive_align: Align, pub min_size: Size, @@ -851,8 +883,10 @@ pub struct Union { impl<'a, 'gcx, 'tcx> Union { fn new(dl: &TargetDataLayout, packed: bool) -> Union { + let align = if packed { dl.i8_align } else { dl.aggregate_align }; Union { - align: if packed { dl.i8_align } else { dl.aggregate_align }, + align: align, + primitive_align: align, min_size: Size::from_bytes(0), packed: packed, } @@ -875,6 +909,7 @@ impl<'a, 'gcx, 'tcx> Union { if !self.packed { self.align = self.align.max(field.align(dl)); + self.primitive_align = self.primitive_align.max(field.primitive_align(dl)); } self.min_size = cmp::max(self.min_size, field.size(dl)); } @@ -888,6 +923,16 @@ impl<'a, 'gcx, 'tcx> Union { pub fn stride(&self) -> Size { self.min_size.abi_align(self.align) } + + pub fn over_align(&self) -> Option { + let align = self.align.abi(); + let primitive_align = self.primitive_align.abi(); + if align > primitive_align { + Some(align as u32) + } else { + None + } + } } /// The first half of a fat pointer. @@ -924,6 +969,7 @@ pub enum Layout { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, align: Align, + primitive_align: Align, element_size: Size, count: u64 }, @@ -970,7 +1016,8 @@ pub enum Layout { discr: Integer, variants: Vec, size: Size, - align: Align + align: Align, + primitive_align: Align, }, /// Two cases distinguished by a nullable pointer: the case with discriminant @@ -1118,6 +1165,7 @@ impl<'a, 'gcx, 'tcx> Layout { Array { sized: true, align: element.align(dl), + primitive_align: element.primitive_align(dl), element_size: element_size, count: count } @@ -1127,6 +1175,7 @@ impl<'a, 'gcx, 'tcx> Layout { Array { sized: false, align: element.align(dl), + primitive_align: element.primitive_align(dl), element_size: element.size(dl), count: 0 } @@ -1135,6 +1184,7 @@ impl<'a, 'gcx, 'tcx> Layout { Array { sized: false, align: dl.i8_align, + primitive_align: dl.i8_align, element_size: Size::from_bytes(1), count: 0 } @@ -1340,6 +1390,7 @@ impl<'a, 'gcx, 'tcx> Layout { assert!(discr_max >= 0); let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max); let mut align = dl.aggregate_align; + let mut primitive_align = dl.aggregate_align; let mut size = Size::from_bytes(0); // We're interested in the smallest alignment, so start large. @@ -1369,6 +1420,7 @@ impl<'a, 'gcx, 'tcx> Layout { } size = cmp::max(size, st.min_size); align = align.max(st.align); + primitive_align = primitive_align.max(st.primitive_align); Ok(st) }).collect::, _>>()?; @@ -1435,7 +1487,8 @@ impl<'a, 'gcx, 'tcx> Layout { discr: ity, variants: variants, size: size, - align: align + align: align, + primitive_align: primitive_align } } @@ -1557,6 +1610,30 @@ impl<'a, 'gcx, 'tcx> Layout { } } + /// Returns alignment before repr alignment is applied + pub fn primitive_align(&self, dl: &TargetDataLayout) -> Align { + match *self { + Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align, + Univariant { ref variant, .. } | + StructWrappedNullablePointer { nonnull: ref variant, .. } => { + variant.primitive_align + }, + + _ => self.align(dl) + } + } + + /// Returns repr alignment if it is greater than the primitive alignment. + pub fn over_align(&self, dl: &TargetDataLayout) -> Option { + let align = self.align(dl); + let primitive_align = self.primitive_align(dl); + if align.abi() > primitive_align.abi() { + Some(align.abi() as u32) + } else { + None + } + } + pub fn field_offset(&self, cx: C, i: usize, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ab1a06aeacd1..db8b093e369e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -37,6 +37,7 @@ use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; use std::cell::{Cell, RefCell, Ref}; use std::collections::BTreeMap; +use std::cmp; use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::rc::Rc; @@ -1464,10 +1465,12 @@ impl_stable_hash_for!(struct ReprFlags { #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { pub int: Option, + pub align: u16, pub flags: ReprFlags, } impl_stable_hash_for!(struct ReprOptions { + align, int, flags }); @@ -1476,7 +1479,7 @@ impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { let mut flags = ReprFlags::empty(); let mut size = None; - + let mut max_align = 0; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { flags.insert(match r { @@ -1487,6 +1490,10 @@ impl ReprOptions { size = Some(i); ReprFlags::empty() }, + attr::ReprAlign(align) => { + max_align = cmp::max(align, max_align); + ReprFlags::empty() + }, }); } } @@ -1500,7 +1507,7 @@ impl ReprOptions { if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, flags: flags } + ReprOptions { int: size, align: max_align, flags: flags } } #[inline] diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c4fdc46d030c..efe4acfa9e07 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -553,7 +553,7 @@ impl<'a, 'tcx> ArgType<'tcx> { // bitcasting to the struct type yields invalid cast errors. // We instead thus allocate some scratch space... - let llscratch = bcx.alloca(ty, "abi_cast"); + let llscratch = bcx.alloca(ty, "abi_cast", None); base::Lifetime::Start.call(bcx, llscratch); // ...where we first store the value... diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 87ca410dece0..3c73aba7cd7e 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -90,12 +90,12 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, /// and fill in the actual contents in a second pass to prevent /// unbounded recursion; see also the comments in `trans::type_of`. pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - generic_type_of(cx, t, None, false, false) + generic_type_of(cx, t, None, false) } pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, name: &str) -> Type { - generic_type_of(cx, t, Some(name), false, false) + generic_type_of(cx, t, Some(name), false) } pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, @@ -114,7 +114,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, _ => unreachable!() }; let fields = compute_fields(cx, t, nonnull_variant_index as usize, true); - llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false), + llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false), packed) }, _ => bug!("This function cannot handle {} with layout {:#?}", t, l) @@ -124,11 +124,9 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, name: Option<&str>, - sizing: bool, - dst: bool) -> Type { + sizing: bool) -> Type { let l = cx.layout_of(t); - debug!("adt::generic_type_of t: {:?} name: {:?} sizing: {} dst: {}", - t, name, sizing, dst); + debug!("adt::generic_type_of t: {:?} name: {:?} sizing: {}", t, name, sizing); match *l { layout::CEnum { discr, .. } => Type::from_integer(cx, discr), layout::RawNullablePointer { nndiscr, .. } => { @@ -148,7 +146,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields = compute_fields(cx, t, nndiscr as usize, false); match name { None => { - Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst), + Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing), nonnull.packed) } Some(name) => { @@ -163,7 +161,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields = compute_fields(cx, t, 0, true); match name { None => { - let fields = struct_llfields(cx, &fields, &variant, sizing, dst); + let fields = struct_llfields(cx, &fields, &variant, sizing); Type::struct_(cx, &fields, variant.packed) } Some(name) => { @@ -245,15 +243,65 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type { } -fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec>, +// Double index to account for padding (FieldPath already uses `Struct::memory_index`) +fn struct_llfields_path(discrfield: &layout::FieldPath) -> Vec { + discrfield.iter().map(|&i| (i as usize) << 1).collect::>() +} + + +// Lookup `Struct::memory_index` and double it to account for padding +pub fn struct_llfields_index(variant: &layout::Struct, index: usize) -> usize { + (variant.memory_index[index] as usize) << 1 +} + + +pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, field_tys: &Vec>, variant: &layout::Struct, - sizing: bool, _dst: bool) -> Vec { - let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]); + sizing: bool) -> Vec { if sizing { - bug!() - } else { - fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect() + bug!(); } + debug!("struct_llfields: variant: {:?}", variant); + let mut first_field = true; + let mut min_offset = 0; + let mut result: Vec = Vec::with_capacity(field_tys.len() * 2); + let field_iter = variant.field_index_by_increasing_offset().map(|i| { + (i, field_tys[i as usize], variant.offsets[i as usize].bytes()) }); + for (index, ty, target_offset) in field_iter.filter( + |&(_, ty, _)| !sizing || cx.shared().type_is_sized(ty)) { + if first_field { + debug!("struct_llfields: {} ty: {} min_offset: {} target_offset: {}", + index, ty, min_offset, target_offset); + first_field = false; + } else { + assert!(target_offset >= min_offset); + let padding_bytes = if variant.packed { 0 } else { target_offset - min_offset }; + result.push(Type::array(&Type::i8(cx), padding_bytes)); + debug!("struct_llfields: {} ty: {} pad_bytes: {} min_offset: {} target_offset: {}", + index, ty, padding_bytes, min_offset, target_offset); + } + let llty = type_of::in_memory_type_of(cx, ty); + result.push(llty); + let layout = cx.layout_of(ty); + let target_size = layout.size(&cx.tcx().data_layout).bytes(); + min_offset = target_offset + target_size; + } + if variant.sized && !field_tys.is_empty() { + if variant.stride().bytes() < min_offset { + bug!("variant: {:?} stride: {} min_offset: {}", variant, variant.stride().bytes(), + min_offset); + } + let padding_bytes = variant.stride().bytes() - min_offset; + debug!("struct_llfields: pad_bytes: {} min_offset: {} min_size: {} stride: {}\n", + padding_bytes, min_offset, variant.min_size.bytes(), variant.stride().bytes()); + result.push(Type::array(&Type::i8(cx), padding_bytes)); + assert!(result.len() == (field_tys.len() * 2)); + } else { + debug!("struct_llfields: min_offset: {} min_size: {} stride: {}\n", + min_offset, variant.min_size.bytes(), variant.stride().bytes()); + } + + result } pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool { @@ -309,8 +357,8 @@ fn struct_wrapped_nullable_bitdiscr( scrutinee: ValueRef, alignment: Alignment, ) -> ValueRef { - let llptrptr = bcx.gepi(scrutinee, - &discrfield.iter().map(|f| *f as usize).collect::>()); + let path = struct_llfields_path(discrfield); + let llptrptr = bcx.gepi(scrutinee, &path); let llptr = bcx.load(llptrptr, alignment.to_align()); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; bcx.icmp(cmp, llptr, C_null(val_ty(llptr))) @@ -380,7 +428,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu let align = C_i32(bcx.ccx, nonnull.align.abi() as i32); base::call_memset(bcx, llptr, fill_byte, size, align, false); } else { - let path = discrfield.iter().map(|&i| i as usize).collect::>(); + let path = struct_llfields_path(discrfield); let llptrptr = bcx.gepi(val, &path); let llptrty = val_ty(llptrptr).element_type(); bcx.store(C_null(llptrty), llptrptr, None); diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 8b1010d89fd9..5103ca5c5e10 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -477,24 +477,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn alloca(&self, ty: Type, name: &str) -> ValueRef { + pub fn alloca(&self, ty: Type, name: &str, align: Option) -> ValueRef { let builder = Builder::with_ccx(self.ccx); builder.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); - builder.dynamic_alloca(ty, name) + builder.dynamic_alloca(ty, name, align) } - pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef { + pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Option) -> ValueRef { self.count_insn("alloca"); unsafe { - if name.is_empty() { + 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()) + }; + if let Some(align) = align { + llvm::LLVMSetAlignment(alloca, align as c_uint); } + alloca } } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 7077eade6118..54e20f590c67 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -778,7 +778,7 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, // // More information can be found in libstd's seh.rs implementation. let i64p = Type::i64(ccx).ptr_to(); - let slot = bcx.alloca(i64p, "slot"); + let slot = bcx.alloca(i64p, "slot", None); bcx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 0f5a38ac7f6b..d94d7f4430bf 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -15,6 +15,7 @@ use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; use abi::{Abi, FnType, ArgType}; +use adt; use base::{self, Lifetime}; use callee; use builder::Builder; @@ -177,7 +178,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let llslot = match op.val { Immediate(_) | Pair(..) => { - let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret"); + let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret", None); self.store_operand(&bcx, llscratch, None, op); llscratch } @@ -630,7 +631,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => { if arg.is_indirect() || arg.cast.is_some() { - let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None); self.store_operand(bcx, llscratch, None, op); (llscratch, Alignment::AbiAligned, true) } else { @@ -642,7 +643,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't // have scary latent bugs around. - let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None); base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1)); (llscratch, Alignment::AbiAligned, true) } @@ -711,7 +712,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bug!("Not a tuple."); }; for (n, &ty) in arg_types.iter().enumerate() { - let mut elem = bcx.extract_value(llval, v.memory_index[n] as usize); + let mut elem = bcx.extract_value( + llval, adt::struct_llfields_index(v, n)); // Truncate bools to i1, if needed if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx) { elem = bcx.trunc(elem, Type::i1(bcx.ccx)); @@ -750,7 +752,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { slot } else { let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); - let slot = bcx.alloca(llretty, "personalityslot"); + let slot = bcx.alloca(llretty, "personalityslot", None); self.llpersonalityslot = Some(slot); slot } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index fc889604ab88..9a461e4aafc2 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -97,7 +97,8 @@ impl<'a, 'tcx> LvalueRef<'tcx> { pub fn alloca(bcx: &Builder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> LvalueRef<'tcx> { debug!("alloca({:?}: {:?})", name, ty); - let tmp = bcx.alloca(type_of::type_of(bcx.ccx, ty), name); + let tmp = bcx.alloca( + type_of::type_of(bcx.ccx, ty), name, bcx.ccx.over_align_of(ty)); assert!(!ty.has_param_types()); Self::new_sized_ty(tmp, ty, Alignment::AbiAligned) } @@ -131,11 +132,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> { let alignment = self.alignment | Alignment::from_packed(st.packed); + let llfields = adt::struct_llfields(ccx, fields, st, false); let ptr_val = if needs_cast { - let fields = st.field_index_by_increasing_offset().map(|i| { - type_of::in_memory_type_of(ccx, fields[i]) - }).collect::>(); - let real_ty = Type::struct_(ccx, &fields[..], st.packed); + let real_ty = Type::struct_(ccx, &llfields[..], st.packed); bcx.pointercast(self.llval, real_ty.ptr_to()) } else { self.llval @@ -147,14 +146,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> { // * Field is sized - pointer is properly aligned already if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed || bcx.ccx.shared().type_is_sized(fty) { - return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment); + return (bcx.struct_gep( + ptr_val, adt::struct_llfields_index(st, ix)), alignment); } // If the type of the last field is [T] or str, then we don't need to do // any adjusments match fty.sty { ty::TySlice(..) | ty::TyStr => { - return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment); + return (bcx.struct_gep( + ptr_val, adt::struct_llfields_index(st, ix)), alignment); } _ => () } @@ -163,7 +164,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> { if !self.has_extra() { debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment", ix, Value(ptr_val)); - return (bcx.struct_gep(ptr_val, ix), alignment); + return (bcx.struct_gep(ptr_val, adt::struct_llfields_index(st, ix)), alignment); } // We need to get the pointer manually now. diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 3d8c5085462a..d39a91405c18 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -524,7 +524,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, // 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 alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr"); + let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr", None); bcx.store(llval, alloc, None); alloc } else { diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index c31142323c85..6889b5064b64 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -15,6 +15,7 @@ use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; +use adt; use base; use common::{self, CrateContext, C_null}; use builder::Builder; @@ -134,6 +135,12 @@ impl<'a, 'tcx> OperandRef<'tcx> { if common::val_ty(elem) == Type::i1(bcx.ccx) { elem = bcx.zext(elem, Type::i8(bcx.ccx)); } + let layout = bcx.ccx.layout_of(self.ty); + let i = if let Layout::Univariant { ref variant, .. } = *layout { + adt::struct_llfields_index(variant, i) + } else { + i + }; llpair = bcx.insert_value(llpair, elem, i); } self.val = OperandValue::Immediate(llpair); @@ -183,14 +190,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (lldata, llextra) = base::load_fat_ptr(bcx, llval, align, ty); OperandValue::Pair(lldata, llextra) } else if common::type_is_imm_pair(bcx.ccx, ty) { - let f_align = match *bcx.ccx.layout_of(ty) { - Layout::Univariant { ref variant, .. } => - Alignment::from_packed(variant.packed) | align, - _ => align + let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(ty) { + Layout::Univariant { ref variant, .. } => { + (adt::struct_llfields_index(variant, 0), + adt::struct_llfields_index(variant, 1), + Alignment::from_packed(variant.packed) | align) + }, + _ => (0, 1, align) }; let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx, ty).unwrap(); - let a_ptr = bcx.struct_gep(llval, 0); - let b_ptr = bcx.struct_gep(llval, 1); + let a_ptr = bcx.struct_gep(llval, ix0); + let b_ptr = bcx.struct_gep(llval, ix1); OperandValue::Pair( base::load_ty(bcx, a_ptr, f_align, a_ty), @@ -302,17 +312,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx.store(base::from_immediate(bcx, s), lldest, align); } OperandValue::Pair(a, b) => { - let f_align = match *bcx.ccx.layout_of(operand.ty) { - Layout::Univariant { ref variant, .. } if variant.packed => { - Some(1) + let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(operand.ty) { + Layout::Univariant { ref variant, .. } => { + (adt::struct_llfields_index(variant, 0), + adt::struct_llfields_index(variant, 1), + if variant.packed { Some(1) } else { None }) } - _ => align + _ => (0, 1, align) }; let a = base::from_immediate(bcx, a); let b = base::from_immediate(bcx, b); - bcx.store(a, bcx.struct_gep(lldest, 0), f_align); - bcx.store(b, bcx.struct_gep(lldest, 1), f_align); + bcx.store(a, bcx.struct_gep(lldest, ix0), f_align); + bcx.store(b, bcx.struct_gep(lldest, ix1), f_align); } } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 98e9008f829f..de1c1e492f39 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -130,10 +130,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { _ => { // If this is a tuple or closure, we need to translate GEP indices. let layout = bcx.ccx.layout_of(dest.ty.to_ty(bcx.tcx())); - let translation = if let Layout::Univariant { ref variant, .. } = *layout { - Some(&variant.memory_index) - } else { - None + let get_memory_index = |i| { + if let Layout::Univariant { ref variant, .. } = *layout { + adt::struct_llfields_index(variant, i) + } else { + i + } }; let alignment = dest.alignment; for (i, operand) in operands.iter().enumerate() { @@ -143,11 +145,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // Note: perhaps this should be StructGep, but // note that in some cases the values here will // not be structs but arrays. - let i = if let Some(ref t) = translation { - t[i] as usize - } else { - i - }; + let i = get_memory_index(i); let dest = bcx.gepi(dest.llval, &[0, i]); self.store_operand(&bcx, dest, alignment.to_align(), op); } diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index d4ab6b078285..9f9126ba83a8 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -214,6 +214,16 @@ impl<'a, 'tcx> CrateContext<'a, 'tcx> { pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize { self.layout_of(ty).size(self).bytes() as machine::llsize } + + pub fn over_align_of(&self, t: Ty<'tcx>) + -> Option { + let layout = self.layout_of(t); + if let Some(align) = layout.over_align(&self.tcx().data_layout) { + Some(align as machine::llalign) + } else { + None + } + } } fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 902cfb889f8c..839af0fa6706 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -953,6 +953,12 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if def.repr.simd() { check_simd(tcx, span, def_id); } + + // if struct is packed and not aligned, check fields for alignment. + // Checks for combining packed and align attrs on single struct are done elsewhere. + if tcx.lookup_adt_def(def_id).repr.packed() && tcx.lookup_adt_def(def_id).repr.align == 0 { + check_packed(tcx, span, def_id); + } } fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1371,6 +1377,47 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId } } +fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { + if check_packed_inner(tcx, def_id, &mut Vec::new()) { + struct_span_err!(tcx.sess, sp, E0588, + "packed struct cannot transitively contain a `[repr(align)]` struct").emit(); + } +} + +fn check_packed_inner<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + stack: &mut Vec) -> bool { + let t = tcx.item_type(def_id); + if stack.contains(&def_id) { + debug!("check_packed_inner: {:?} is recursive", t); + return false; + } + match t.sty { + ty::TyAdt(def, substs) if def.is_struct() => { + if tcx.lookup_adt_def(def.did).repr.align > 0 { + return true; + } + // push struct def_id before checking fields + stack.push(def_id); + for field in &def.struct_variant().fields { + let f = field.ty(tcx, substs); + match f.sty { + ty::TyAdt(def, _) => { + if check_packed_inner(tcx, def.did, stack) { + return true; + } + } + _ => () + } + } + // only need to pop if not early out + stack.pop(); + } + _ => () + } + false +} + #[allow(trivial_numeric_casts)] pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 68afcae2b674..c50156fa5f27 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4168,5 +4168,6 @@ register_diagnostics! { // but `{}` was found in the type `{}` E0567, // auto traits can not have type parameters E0568, // auto-traits can not have predicates, + E0588, // packed struct cannot transitively contain a `[repr(align)]` struct E0592, // duplicate definitions with name `{}` } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 6f5f52ff1e95..442345ceb3c1 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -147,6 +147,24 @@ impl NestedMetaItem { self.meta_item().and_then(|meta_item| meta_item.value_str()) } + /// Returns a name and single literal value tuple of the MetaItem. + pub fn name_value_literal(&self) -> Option<(Name, &Lit)> { + self.meta_item().and_then( + |meta_item| meta_item.meta_item_list().and_then( + |meta_item_list| { + if meta_item_list.len() == 1 { + let nested_item = &meta_item_list[0]; + if nested_item.is_literal() { + Some((meta_item.name(), nested_item.literal().unwrap())) + } else { + None + } + } + else { + None + }})) + } + /// Returns a MetaItem if self is a MetaItem with Kind Word. pub fn word(&self) -> Option<&MetaItem> { self.meta_item().and_then(|meta_item| if meta_item.is_word() { @@ -931,6 +949,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec continue } + let mut recognised = false; if let Some(mi) = item.word() { let word = &*mi.name().as_str(); let hint = match word { @@ -941,20 +960,38 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec _ => match int_type_of_word(word) { Some(ity) => Some(ReprInt(ity)), None => { - // Not a word we recognize - span_err!(diagnostic, item.span, E0552, - "unrecognized representation hint"); None } } }; if let Some(h) = hint { + recognised = true; acc.push(h); } - } else { - span_err!(diagnostic, item.span, E0553, - "unrecognized enum representation hint"); + } else if let Some((name, value)) = item.name_value_literal() { + if name == "align" { + recognised = true; + let mut valid_align = false; + if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node { + if align.is_power_of_two() { + // rustc::ty::layout::Align restricts align to <= 32768 + if align <= 32768 { + acc.push(ReprAlign(align as u16)); + valid_align = true; + } + } + } + if !valid_align { + span_err!(diagnostic, item.span, E0589, + "align representation must be a u16 power of two"); + } + } + } + if !recognised { + // Not a word we recognize + span_err!(diagnostic, item.span, E0552, + "unrecognized representation hint"); } } } @@ -986,6 +1023,7 @@ pub enum ReprAttr { ReprExtern, ReprPacked, ReprSimd, + ReprAlign(u16), } #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 2d59051ec4a5..775775875a4d 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -287,10 +287,10 @@ register_diagnostics! { E0550, // multiple deprecated attributes E0551, // incorrect meta item E0552, // unrecognized representation hint - E0553, // unrecognized enum representation hint E0554, // #[feature] may not be used on the [] release channel E0555, // malformed feature attribute, expected #![feature(...)] E0556, // malformed feature, expected just one word E0557, // feature has been removed E0584, // file for module `..` found at both .. and .. + E0589, // align representation must be a u16 power of two } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1ff0fec1c96a..e96883c26f33 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -773,7 +773,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { - attr::ReprPacked | attr::ReprSimd => continue, + attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) => continue, attr::ReprExtern => "i32", attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize", diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs index b07d3e2f9067..c0bfd3690c85 100644 --- a/src/test/compile-fail/attr-usage-repr.rs +++ b/src/test/compile-fail/attr-usage-repr.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code)] +#![feature(attr_literals)] #![feature(repr_simd)] #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union @@ -29,6 +30,9 @@ struct SInt(f64, f64); #[repr(C)] enum EExtern { A, B } +#[repr(align(8))] //~ ERROR: attribute should be applied to struct +enum EAlign { A, B } + #[repr(packed)] //~ ERROR: attribute should be applied to struct enum EPacked { A, B } diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs index 9e0c0d845ca2..af38673d3650 100644 --- a/src/test/compile-fail/conflicting-repr-hints.rs +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] #![allow(dead_code)] +#![feature(attr_literals)] #[repr(C)] enum A { A } @@ -26,5 +26,7 @@ enum D { D } #[repr(C, packed)] struct E(i32); -#[rustc_error] -fn main() {} //~ ERROR compilation successful +#[repr(packed, align(8))] //~ ERROR conflicting packed and align representation hints +struct F(i32); + +fn main() {} diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs new file mode 100644 index 000000000000..96dfe1c05f9a --- /dev/null +++ b/src/test/compile-fail/repr-align.rs @@ -0,0 +1,22 @@ +// 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. +#![allow(dead_code)] +#![feature(attr_literals)] + +#[repr(align(16.0))] //~ ERROR: align representation must be a u16 power of two +struct A(i32); + +#[repr(align(15))] //~ ERROR: align representation must be a u16 power of two +struct B(i32); + +#[repr(align(65536))] //~ ERROR: align representation must be a u16 power of tw +struct C(i32); + +fn main() {} diff --git a/src/test/compile-fail/repr-packed-contains-align.rs b/src/test/compile-fail/repr-packed-contains-align.rs new file mode 100644 index 000000000000..11829dfae8cb --- /dev/null +++ b/src/test/compile-fail/repr-packed-contains-align.rs @@ -0,0 +1,24 @@ +// 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(attr_literals)] +#![allow(dead_code)] + +#[repr(align(16))] +struct A(i32); + +struct B(A); + +#[repr(packed)] +struct C(A); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct + +#[repr(packed)] +struct D(B); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct + +fn main() {} diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs new file mode 100644 index 000000000000..4793189d366d --- /dev/null +++ b/src/test/run-pass/align-struct.rs @@ -0,0 +1,195 @@ +// 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(attr_literals)] + +use std::mem; + +// Raising alignment +#[repr(align(16))] +struct Align16(i32); + +// Lowering has no effect +#[repr(align(1))] +struct Align1(i32); + +// Multiple attributes take the max +#[repr(align(4))] +#[repr(align(16))] +#[repr(align(8))] +struct AlignMany(i32); + +// Raising alignment may not alter size. +#[repr(align(8))] +#[allow(dead_code)] +struct Align8Many { + a: i32, + b: i32, + c: i32, + d: u8, +} + +enum Enum { + #[allow(dead_code)] + A(i32), + B(Align16) +} + +// Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test +#[repr(C)] +struct Nested { + a: i32, + b: i32, + c: Align16, + d: i8, +} + +#[repr(packed)] +struct Packed(i32); + +#[repr(align(16))] +struct AlignContainsPacked { + a: Packed, + b: Packed, +} + +impl Align16 { + // return aligned type + pub fn new(i: i32) -> Align16 { + Align16(i) + } + // pass aligned type + pub fn consume(a: Align16) -> i32 { + a.0 + } +} + +const CONST_ALIGN16: Align16 = Align16(7); +static STATIC_ALIGN16: Align16 = Align16(8); + +// Check the actual address is aligned +fn is_aligned_to(p: &T, align: usize) -> bool { + let addr = p as *const T as usize; + (addr & (align - 1)) == 0 +} + +pub fn main() { + // check alignment and size by type and value + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + + let a = Align16(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + + assert!(is_aligned_to(&a, 16)); + + // lowering should have no effect + assert_eq!(mem::align_of::(), 4); + assert_eq!(mem::size_of::(), 4); + let a = Align1(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 4); + assert_eq!(mem::size_of_val(&a), 4); + assert!(is_aligned_to(&a, 4)); + + // when multiple attributes are specified the max should be used + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + let a = AlignMany(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 16)); + + // raising alignment should not reduce size + assert_eq!(mem::align_of::(), 8); + assert_eq!(mem::size_of::(), 16); + let a = Align8Many { a: 1, b: 2, c: 3, d: 4 }; + assert_eq!(a.a, 1); + assert_eq!(mem::align_of_val(&a), 8); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 8)); + + // return type + let a = Align16::new(1); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + assert_eq!(a.0, 1); + assert!(is_aligned_to(&a, 16)); + assert_eq!(Align16::consume(a), 1); + + // check const alignment, size and value + assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16); + assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16); + assert_eq!(CONST_ALIGN16.0, 7); + assert!(is_aligned_to(&CONST_ALIGN16, 16)); + + // check global static alignment, size and value + assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16); + assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16); + assert_eq!(STATIC_ALIGN16.0, 8); + assert!(is_aligned_to(&STATIC_ALIGN16, 16)); + + // Note that the size of Nested may change if struct field re-ordering is enabled + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 48); + let a = Nested{ a: 1, b: 2, c: Align16(3), d: 4}; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.b), 4); + assert_eq!(mem::align_of_val(&a.c), 16); + assert_eq!(mem::size_of_val(&a), 48); + assert!(is_aligned_to(&a, 16)); + // check the correct fields are indexed + assert_eq!(a.a, 1); + assert_eq!(a.b, 2); + assert_eq!(a.c.0, 3); + assert_eq!(a.d, 4); + + // enum should be aligned to max alignment + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16); + let e = Enum::B(Align16(15)); + match e { + Enum::B(ref a) => { + assert_eq!(a.0, 15); + assert_eq!(mem::align_of_val(a), 16); + assert_eq!(mem::size_of_val(a), 16); + }, + _ => () + } + assert!(is_aligned_to(&e, 16)); + + // arrays of aligned elements should also be aligned + assert_eq!(mem::align_of::<[Align16;2]>(), 16); + assert_eq!(mem::size_of::<[Align16;2]>(), 32); + + let a = [Align16(0), Align16(1)]; + assert_eq!(mem::align_of_val(&a[0]), 16); + assert_eq!(mem::align_of_val(&a[1]), 16); + assert!(is_aligned_to(&a, 16)); + + // check heap value is aligned + assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16); + + // check heap array is aligned + let a = vec!(Align16(0), Align16(1)); + assert_eq!(mem::align_of_val(&a[0]), 16); + assert_eq!(mem::align_of_val(&a[1]), 16); + + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + let a = AlignContainsPacked { a: Packed(1), b: Packed(2) }; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.a), 1); + assert_eq!(mem::align_of_val(&a.b), 1); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 16)); +} diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs new file mode 100644 index 000000000000..ea2910f86c45 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr-align.rs @@ -0,0 +1,42 @@ +// 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. + +// compile-flags: -Z print-type-sizes + +// This file illustrates how padding is handled: alignment +// requirements can lead to the introduction of padding, either before +// fields or at the end of the structure as a whole. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. +#![feature(attr_literals)] +#![allow(dead_code)] + +#[repr(align(16))] +#[derive(Default)] +struct A(i32); + +enum E { + A(i32), + B(A) +} + +#[derive(Default)] +struct S { + a: i32, + b: i32, + c: A, + d: i8, +} + +fn main() { + let _s: S = Default::default(); +} diff --git a/src/test/ui/print_type_sizes/repr-align.stdout b/src/test/ui/print_type_sizes/repr-align.stdout new file mode 100644 index 000000000000..7df12f040b15 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr-align.stdout @@ -0,0 +1,16 @@ +print-type-size type: `E`: 32 bytes, alignment: 16 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `A`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `B`: 28 bytes +print-type-size padding: 12 bytes +print-type-size field `.0`: 16 bytes, alignment: 16 bytes +print-type-size type: `S`: 32 bytes, alignment: 16 bytes +print-type-size field `.c`: 16 bytes +print-type-size field `.a`: 4 bytes +print-type-size field `.b`: 4 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 7 bytes +print-type-size type: `A`: 16 bytes, alignment: 16 bytes +print-type-size field `.0`: 4 bytes +print-type-size end padding: 12 bytes From 7971a47eff4b178ffe7c38c67b1926dacea4c0dd Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 25 Mar 2017 19:00:49 +1100 Subject: [PATCH 604/905] Added feature gate, updated error messages and tests. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../src/language-features/repr-align.md | 11 +++++++++++ src/libsyntax/attr.rs | 13 +++++++++---- src/libsyntax/diagnostic_list.rs | 2 +- src/libsyntax/feature_gate.rs | 8 ++++++++ src/test/compile-fail/conflicting-repr-hints.rs | 1 + src/test/compile-fail/feature-gate-repr_align.rs | 15 +++++++++++++++ src/test/compile-fail/repr-align.rs | 7 ++++--- .../compile-fail/repr-packed-contains-align.rs | 1 + src/test/run-pass/align-struct.rs | 1 + src/test/ui/print_type_sizes/repr-align.rs | 1 + 11 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/repr-align.md create mode 100644 src/test/compile-fail/feature-gate-repr_align.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 3e0415439774..ee4e568a5ca9 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -72,6 +72,7 @@ - [proc_macro](language-features/proc-macro.md) - [quote](language-features/quote.md) - [relaxed_adts](language-features/relaxed-adts.md) + - [repr_align](language-features/repr-align.md) - [repr_simd](language-features/repr-simd.md) - [rustc_attrs](language-features/rustc-attrs.md) - [rustc_diagnostic_macros](language-features/rustc-diagnostic-macros.md) diff --git a/src/doc/unstable-book/src/language-features/repr-align.md b/src/doc/unstable-book/src/language-features/repr-align.md new file mode 100644 index 000000000000..deea04f4c51c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/repr-align.md @@ -0,0 +1,11 @@ +# `repr_align` + +The tracking issue for this feature is: [#33626] + +[#33626]: https://github.com/rust-lang/rust/issues/33626 + +------------------------ + + + + diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 442345ceb3c1..82492d976276 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -972,19 +972,24 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec } else if let Some((name, value)) = item.name_value_literal() { if name == "align" { recognised = true; - let mut valid_align = false; + let mut align_error = None; if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node { if align.is_power_of_two() { // rustc::ty::layout::Align restricts align to <= 32768 if align <= 32768 { acc.push(ReprAlign(align as u16)); - valid_align = true; + } else { + align_error = Some("larger than 32768"); } + } else { + align_error = Some("not a power of two"); } + } else { + align_error = Some("not an unsuffixed integer"); } - if !valid_align { + if let Some(align_error) = align_error { span_err!(diagnostic, item.span, E0589, - "align representation must be a u16 power of two"); + "invalid `repr(align)` attribute: {}", align_error); } } } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 775775875a4d..01d1277ea626 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -292,5 +292,5 @@ register_diagnostics! { E0556, // malformed feature, expected just one word E0557, // feature has been removed E0584, // file for module `..` found at both .. and .. - E0589, // align representation must be a u16 power of two + E0589, // invalid `repr(align)` attribute } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 175447e11127..9b55a860b359 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -338,6 +338,9 @@ declare_features! ( // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), + // Allows `repr(align(u16))` struct attribute (RFC 1358) + (active, repr_align, "1.17.0", Some(33626)), + // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), @@ -1189,6 +1192,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { and possibly buggy"); } + if item.check_name("align") { + gate_feature_post!(&self, repr_align, i.span, + "the struct `#[repr(align(u16))]` attribute \ + is experimental"); + } } } } diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs index af38673d3650..01fa3ffbaa6a 100644 --- a/src/test/compile-fail/conflicting-repr-hints.rs +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -10,6 +10,7 @@ #![allow(dead_code)] #![feature(attr_literals)] +#![feature(repr_align)] #[repr(C)] enum A { A } diff --git a/src/test/compile-fail/feature-gate-repr_align.rs b/src/test/compile-fail/feature-gate-repr_align.rs new file mode 100644 index 000000000000..8e986e197f26 --- /dev/null +++ b/src/test/compile-fail/feature-gate-repr_align.rs @@ -0,0 +1,15 @@ +// 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(attr_literals)] + +#[repr(align(64))] +struct Foo(u64, u64); //~ error: the struct `#[repr(align(u16))]` attribute is experimental + +fn main() {} diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs index 96dfe1c05f9a..eb0b27fe9c07 100644 --- a/src/test/compile-fail/repr-align.rs +++ b/src/test/compile-fail/repr-align.rs @@ -9,14 +9,15 @@ // except according to those terms. #![allow(dead_code)] #![feature(attr_literals)] +#![feature(repr_align)] -#[repr(align(16.0))] //~ ERROR: align representation must be a u16 power of two +#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer struct A(i32); -#[repr(align(15))] //~ ERROR: align representation must be a u16 power of two +#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two struct B(i32); -#[repr(align(65536))] //~ ERROR: align representation must be a u16 power of tw +#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768 struct C(i32); fn main() {} diff --git a/src/test/compile-fail/repr-packed-contains-align.rs b/src/test/compile-fail/repr-packed-contains-align.rs index 11829dfae8cb..c584dcf3e599 100644 --- a/src/test/compile-fail/repr-packed-contains-align.rs +++ b/src/test/compile-fail/repr-packed-contains-align.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(attr_literals)] +#![feature(repr_align)] #![allow(dead_code)] #[repr(align(16))] diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs index 4793189d366d..0b9a3594502b 100644 --- a/src/test/run-pass/align-struct.rs +++ b/src/test/run-pass/align-struct.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(attr_literals)] +#![feature(repr_align)] use std::mem; diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs index ea2910f86c45..e9b43145de46 100644 --- a/src/test/ui/print_type_sizes/repr-align.rs +++ b/src/test/ui/print_type_sizes/repr-align.rs @@ -18,6 +18,7 @@ // aligned (while on most it is 8-byte aligned) and so the resulting // padding and overall computed sizes can be quite different. #![feature(attr_literals)] +#![feature(repr_align)] #![allow(dead_code)] #[repr(align(16))] From c219cdfa11b0bb23f1dabbef9415ffb94f10386a Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Mon, 10 Apr 2017 21:40:24 +1200 Subject: [PATCH 605/905] Removed sizing parameter from struct_llfields. --- src/librustc_trans/adt.rs | 26 +++++++++----------------- src/librustc_trans/mir/lvalue.rs | 2 +- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 3c73aba7cd7e..5326e9344c89 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -90,12 +90,12 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, /// and fill in the actual contents in a second pass to prevent /// unbounded recursion; see also the comments in `trans::type_of`. pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - generic_type_of(cx, t, None, false) + generic_type_of(cx, t, None) } pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, name: &str) -> Type { - generic_type_of(cx, t, Some(name), false) + generic_type_of(cx, t, Some(name)) } pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, @@ -114,7 +114,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, _ => unreachable!() }; let fields = compute_fields(cx, t, nonnull_variant_index as usize, true); - llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false), + llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant), packed) }, _ => bug!("This function cannot handle {} with layout {:#?}", t, l) @@ -123,10 +123,9 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, - name: Option<&str>, - sizing: bool) -> Type { + name: Option<&str>) -> Type { let l = cx.layout_of(t); - debug!("adt::generic_type_of t: {:?} name: {:?} sizing: {}", t, name, sizing); + debug!("adt::generic_type_of t: {:?} name: {:?}", t, name); match *l { layout::CEnum { discr, .. } => Type::from_integer(cx, discr), layout::RawNullablePointer { nndiscr, .. } => { @@ -146,11 +145,10 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields = compute_fields(cx, t, nndiscr as usize, false); match name { None => { - Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing), + Type::struct_(cx, &struct_llfields(cx, &fields, nonnull), nonnull.packed) } Some(name) => { - assert_eq!(sizing, false); Type::named_struct(cx, name) } } @@ -161,13 +159,12 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields = compute_fields(cx, t, 0, true); match name { None => { - let fields = struct_llfields(cx, &fields, &variant, sizing); + let fields = struct_llfields(cx, &fields, &variant); Type::struct_(cx, &fields, variant.packed) } Some(name) => { // Hypothesis: named_struct's can never need a // drop flag. (... needs validation.) - assert_eq!(sizing, false); Type::named_struct(cx, name) } } @@ -256,19 +253,14 @@ pub fn struct_llfields_index(variant: &layout::Struct, index: usize) -> usize { pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, field_tys: &Vec>, - variant: &layout::Struct, - sizing: bool) -> Vec { - if sizing { - bug!(); - } + variant: &layout::Struct) -> Vec { debug!("struct_llfields: variant: {:?}", variant); let mut first_field = true; let mut min_offset = 0; let mut result: Vec = Vec::with_capacity(field_tys.len() * 2); let field_iter = variant.field_index_by_increasing_offset().map(|i| { (i, field_tys[i as usize], variant.offsets[i as usize].bytes()) }); - for (index, ty, target_offset) in field_iter.filter( - |&(_, ty, _)| !sizing || cx.shared().type_is_sized(ty)) { + for (index, ty, target_offset) in field_iter { if first_field { debug!("struct_llfields: {} ty: {} min_offset: {} target_offset: {}", index, ty, min_offset, target_offset); diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 9a461e4aafc2..88e46b5c99a4 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -132,7 +132,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> { let alignment = self.alignment | Alignment::from_packed(st.packed); - let llfields = adt::struct_llfields(ccx, fields, st, false); + let llfields = adt::struct_llfields(ccx, fields, st); let ptr_val = if needs_cast { let real_ty = Type::struct_(ccx, &llfields[..], st.packed); bcx.pointercast(self.llval, real_ty.ptr_to()) From 910532ea4559684e16d4acbd058c643599fe9536 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Thu, 20 Apr 2017 16:13:13 -0700 Subject: [PATCH 606/905] Don't panic if an attribute macro fails to resolve at crate root Adds temporary regression test; this ideally should work as-is (#41430) Closes #41211 --- src/libsyntax/ext/expand.rs | 14 +++++++++-- .../proc-macro/auxiliary/issue-41211.rs | 23 +++++++++++++++++++ .../proc-macro/issue-41211.rs | 22 ++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs create mode 100644 src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 680bd7599ace..842398ea02b9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -205,6 +205,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { module.directory.pop(); self.cx.current_expansion.module = Rc::new(module); + let orig_mod_span = krate.module.inner; + let krate_item = Expansion::Items(SmallVector::one(P(ast::Item { attrs: krate.attrs, span: krate.span, @@ -214,11 +216,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { vis: ast::Visibility::Public, }))); - match self.expand(krate_item).make_items().pop().unwrap().unwrap() { - ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => { + match self.expand(krate_item).make_items().pop().map(P::unwrap) { + Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => { krate.attrs = attrs; krate.module = module; }, + None => { + // Resolution failed so we return an empty expansion + krate.attrs = vec![]; + krate.module = ast::Mod { + inner: orig_mod_span, + items: vec![], + }; + }, _ => unreachable!(), }; diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs new file mode 100644 index 000000000000..99400bd147c2 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs @@ -0,0 +1,23 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn emit_unchanged(_args: TokenStream, input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs new file mode 100644 index 000000000000..17237912be49 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs @@ -0,0 +1,22 @@ +// 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. + +// aux-build:issue-41211.rs + +// FIXME: https://github.com/rust-lang/rust/issues/41430 +// This is a temporary regression test for the ICE reported in #41211 + +#![feature(proc_macro)] +#![emit_unchanged] +//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope +extern crate issue_41211; +use issue_41211::emit_unchanged; + +fn main() {} From cd60307acb110ae268556e41a6abdc8d59d7e72b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 20 Apr 2017 16:58:42 -0700 Subject: [PATCH 607/905] Do not show `::constructor` on tuple struct diagnostics --- src/librustc/ty/item_path.rs | 5 ++++- src/test/compile-fail/numeric-fields.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 386991052905..64dfd2b71b45 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -175,7 +175,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::LifetimeDef(..) | data @ DefPathData::EnumVariant(..) | data @ DefPathData::Field(..) | - data @ DefPathData::StructCtor | data @ DefPathData::Initializer | data @ DefPathData::MacroDef(..) | data @ DefPathData::ClosureExpr | @@ -186,6 +185,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.push_item_path(buffer, parent_def_id); buffer.push(&data.as_interned_str()); } + DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}` + let parent_def_id = self.parent_def_id(def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + } } } diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs index a67707257d2f..0dc5c4bcfa20 100644 --- a/src/test/compile-fail/numeric-fields.rs +++ b/src/test/compile-fail/numeric-fields.rs @@ -19,6 +19,6 @@ fn main() { match s { S{0: a, 0x1: b, ..} => {} //~^ ERROR does not have a field named `0x1` - //~| NOTE struct `S::{{constructor}}` does not have field `0x1` + //~| NOTE struct `S` does not have field `0x1` } } From 903bdfccd0ecc5bf1aa4207df365ea088de2c3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 20 Apr 2017 17:06:39 -0700 Subject: [PATCH 608/905] Add test for issue 33884 Fix #33884 --- src/test/ui/span/issue-33884.rs | 27 +++++++++++++++++++++++++++ src/test/ui/span/issue-33884.stderr | 12 ++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/test/ui/span/issue-33884.rs create mode 100644 src/test/ui/span/issue-33884.stderr diff --git a/src/test/ui/span/issue-33884.rs b/src/test/ui/span/issue-33884.rs new file mode 100644 index 000000000000..93aa502ee153 --- /dev/null +++ b/src/test/ui/span/issue-33884.rs @@ -0,0 +1,27 @@ +// 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::net::TcpListener; +use std::net::TcpStream; +use std::io::{self, Read, Write}; + +fn handle_client(stream: TcpStream) -> io::Result<()> { + stream.write_fmt(format!("message received")) +} + +fn main() { + if let Ok(listener) = TcpListener::bind("127.0.0.1:8080") { + for incoming in listener.incoming() { + if let Ok(stream) = incoming { + handle_client(stream); + } + } + } +} diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr new file mode 100644 index 000000000000..2a874181c7ad --- /dev/null +++ b/src/test/ui/span/issue-33884.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/issue-33884.rs:16:22 + | +16 | stream.write_fmt(format!("message received")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::fmt::Arguments`, found struct `std::string::String` + | + = note: expected type `std::fmt::Arguments<'_>` + found type `std::string::String` + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + From cc07c357e421eebff58eb6948c8e1412ae7d8069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 14 Apr 2017 16:38:10 -0700 Subject: [PATCH 609/905] Reduce visual clutter of multiline start when possible When a span starts on a line with nothing but whitespace to the left, and there are no other annotations in that line, simplify the visual representation of the span. Go from: ```rust error[E0072]: recursive type `A` has infinite size --> file2.rs:1:1 | 1 | struct A { | _^ starting here... 2 | | a: A, 3 | | } | |_^ ...ending here: recursive type has infinite size | ``` To: ```rust error[E0072]: recursive type `A` has infinite size --> file2.rs:1:1 | 1 | / struct A { 2 | | a: A, 3 | | } | |_^ recursive type has infinite size ``` Remove `starting here...`/`...ending here` labels from all multiline diagnostics. --- src/librustc_errors/emitter.rs | 67 ++++++++++--- src/librustc_errors/snippet.rs | 22 +++-- src/libsyntax/test_snippet.rs | 93 +++++++++---------- .../ui/compare-method/region-extra-2.stderr | 5 +- .../traits-misc-mismatch-2.stderr | 5 +- src/test/ui/did_you_mean/issue-40006.stderr | 16 ++-- ...dropck-eyepatch-implies-unsafe-impl.stderr | 10 +- .../issue-37311.stderr | 5 +- ...x1-return-one-existing-name-if-else.stderr | 8 +- .../ex2a-push-one-existing-name.stderr | 8 +- .../ex2b-push-no-existing-names.stderr | 8 +- .../ex2c-push-inference-variable.stderr | 8 +- .../ex2d-push-inference-variable-2.stderr | 8 +- .../ex2e-push-inference-variable-3.stderr | 8 +- src/test/ui/mismatched_types/abridged.stderr | 10 +- src/test/ui/mismatched_types/main.stderr | 4 +- src/test/ui/missing-items/m2.stderr | 5 +- .../ui/span/impl-wrong-item-for-trait.stderr | 20 ++-- src/test/ui/span/issue-23729.stderr | 5 +- src/test/ui/span/issue-23827.stderr | 5 +- src/test/ui/span/issue-24356.stderr | 5 +- src/test/ui/span/issue-7575.stderr | 10 +- src/test/ui/span/lint-unused-unsafe.stderr | 30 +++--- src/test/ui/span/multiline-span-E0072.stderr | 5 +- src/test/ui/span/multiline-span-simple.stderr | 4 +- src/test/ui/type-check/issue-40294.stderr | 5 +- 26 files changed, 200 insertions(+), 179 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a52628ceb47a..64652bb308bd 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -263,6 +263,41 @@ impl EmitterWriter { draw_col_separator(buffer, line_offset, width_offset - 2); + // Special case when there's only one annotation involved, it is the start of a multiline + // span and there's no text at the beginning of the code line. Instead of doing the whole + // graph: + // + // 2 | fn foo() { + // | _^ + // 3 | | + // 4 | | } + // | |_^ test + // + // we simplify the output to: + // + // 2 | / fn foo() { + // 3 | | + // 4 | | } + // | |_^ test + if line.annotations.len() == 1 { + if let Some(ref ann) = line.annotations.get(0) { + if let AnnotationType::MultilineStart(depth) = ann.annotation_type { + if source_string[0..ann.start_col].trim() == "" { + let style = if ann.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }; + buffer.putc(line_offset, + width_offset + depth - 1, + '/', + style); + return vec![(depth, style)]; + } + } + } + } + // We want to display like this: // // vec.push(vec.pop().unwrap()); @@ -355,10 +390,8 @@ impl EmitterWriter { for (i, annotation) in annotations.iter().enumerate() { for (j, next) in annotations.iter().enumerate() { if overlaps(next, annotation, 0) // This label overlaps with another one and both - && !annotation.is_line() // take space (they have text and are not - && !next.is_line() // multiline lines). - && annotation.has_label() - && j > i + && annotation.has_label() // take space (they have text and are not + && j > i // multiline lines). && p == 0 // We're currently on the first line, move the label one line down { // This annotation needs a new line in the output. @@ -374,7 +407,7 @@ impl EmitterWriter { } else { 0 }; - if overlaps(next, annotation, l) // Do not allow two labels to be in the same + if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to // avoid situations like: // @@ -383,11 +416,18 @@ impl EmitterWriter { // | | // fn_spanx_span // - && !annotation.is_line() // Do not add a new line if this annotation - && !next.is_line() // or the next are vertical line placeholders. && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label() // they are not overlapping. + && next.has_label()) // they are not overlapping. + // Do not add a new line if this annotation + // or the next are vertical line placeholders. + || (annotation.takes_space() // If either this or the next annotation is + && next.has_label()) // multiline start/end, move it to a new line + || (annotation.has_label() // so as not to overlap the orizontal lines. + && next.takes_space()) + || (annotation.takes_space() + && next.takes_space()) { + // This annotation needs a new line in the output. p += 1; break; } @@ -397,6 +437,7 @@ impl EmitterWriter { line_len = p; } } + if line_len != 0 { line_len += 1; } @@ -480,7 +521,7 @@ impl EmitterWriter { }; let pos = pos + 1; - if pos > 1 && annotation.has_label() { + if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..line_offset + pos + 1 { buffer.putc(p, code_offset + annotation.start_col, @@ -514,12 +555,12 @@ impl EmitterWriter { // After this we will have: // // 2 | fn foo() { - // | __________ starting here... + // | __________ // | | // | something about `foo` // 3 | // 4 | } - // | _ ...ending here: test + // | _ test for &(pos, annotation) in &annotations_position { let style = if annotation.is_primary { Style::LabelPrimary @@ -557,12 +598,12 @@ impl EmitterWriter { // After this we will have: // // 2 | fn foo() { - // | ____-_____^ starting here... + // | ____-_____^ // | | // | something about `foo` // 3 | // 4 | } - // | _^ ...ending here: test + // | _^ test for &(_, annotation) in &annotations_position { let (underline, style) = if annotation.is_primary { ('^', Style::UnderlinePrimary) diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 9aa4682e1afc..7401ead22089 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -63,7 +63,7 @@ impl MultilineAnnotation { start_col: self.start_col, end_col: self.start_col + 1, is_primary: self.is_primary, - label: Some("starting here...".to_owned()), + label: None, annotation_type: AnnotationType::MultilineStart(self.depth) } } @@ -73,10 +73,7 @@ impl MultilineAnnotation { start_col: self.end_col - 1, end_col: self.end_col, is_primary: self.is_primary, - label: match self.label { - Some(ref label) => Some(format!("...ending here: {}", label)), - None => Some("...ending here".to_owned()), - }, + label: self.label.clone(), annotation_type: AnnotationType::MultilineEnd(self.depth) } } @@ -106,9 +103,9 @@ pub enum AnnotationType { // Each of these corresponds to one part of the following diagram: // // x | foo(1 + bar(x, - // | _________^ starting here... < MultilineStart - // x | | y), < MultilineLine - // | |______________^ ...ending here: label < MultilineEnd + // | _________^ < MultilineStart + // x | | y), < MultilineLine + // | |______________^ label < MultilineEnd // x | z); /// Annotation marking the first character of a fully shown multiline span MultilineStart(usize), @@ -189,6 +186,15 @@ impl Annotation { false } } + + pub fn takes_space(&self) -> bool { + // Multiline annotations always have to keep vertical space. + match self.annotation_type { + AnnotationType::MultilineStart(_) | + AnnotationType::MultilineEnd(_) => true, + _ => false, + } + } } #[derive(Debug)] diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index a74f59b004bb..dc9b22c37e28 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -128,9 +128,9 @@ error: foo --> test.rs:2:10 | 2 | fn foo() { - | __________^ starting here... + | __________^ 3 | | } - | |_^ ...ending here: test + | |_^ test "#); } @@ -161,11 +161,11 @@ error: foo --> test.rs:2:10 | 2 | fn foo() { - | __________^ starting here... + | __________^ 3 | | 4 | | 5 | | } - | |___^ ...ending here: test + | |___^ test "#); } @@ -207,14 +207,14 @@ error: foo --> test.rs:3:3 | 3 | X0 Y0 - | ____^__- starting here... + | ____^__- | | ___| - | || starting here... + | || 4 | || X1 Y1 5 | || X2 Y2 - | ||____^__- ...ending here: `Y` is a good letter too + | ||____^__- `Y` is a good letter too | |____| - | ...ending here: `X` is a good letter + | `X` is a good letter "#); } @@ -256,13 +256,13 @@ error: foo --> test.rs:3:3 | 3 | X0 Y0 - | ____^__- starting here... + | ____^__- | | ___| - | || starting here... + | || 4 | || Y1 X1 - | ||____-__^ ...ending here: `X` is a good letter + | ||____-__^ `X` is a good letter | |_____| - | ...ending here: `Y` is a good letter too + | `Y` is a good letter too "#); } @@ -306,13 +306,13 @@ error: foo --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |_________- starting here... + | |_________- 5 | || X2 Y2 Z2 - | ||____^ ...ending here: `X` is a good letter + | ||____^ `X` is a good letter 6 | | X3 Y3 Z3 - | |_____- ...ending here: `Y` is a good letter too + | |_____- `Y` is a good letter too "#); } @@ -366,16 +366,16 @@ error: foo --> test.rs:3:3 | 3 | X0 Y0 Z0 - | _____^__-__- starting here... + | _____^__-__- | | ____|__| - | || ___| starting here... - | ||| starting here... + | || ___| + | ||| 4 | ||| X1 Y1 Z1 5 | ||| X2 Y2 Z2 - | |||____^__-__- ...ending here: `Z` label + | |||____^__-__- `Z` label | ||____|__| - | |____| ...ending here: `Y` is a good letter too - | ...ending here: `X` is a good letter + | |____| `Y` is a good letter too + | `X` is a good letter "#); } @@ -430,17 +430,17 @@ error: foo --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |____^_- starting here... + | |____^_- | ||____| - | | ...ending here: `X` is a good letter + | | `X` is a good letter 5 | | X2 Y2 Z2 - | |____-______- ...ending here: `Y` is a good letter too + | |____-______- `Y` is a good letter too | ____| - | | starting here... + | | 6 | | X3 Y3 Z3 - | |________- ...ending here: `Z` + | |________- `Z` "#); } @@ -458,7 +458,7 @@ fn foo() { vec![ SpanLabel { start: Position { - string: "Y0", + string: "X0", count: 1, }, end: Position { @@ -481,16 +481,15 @@ fn foo() { ], r#" error: foo - --> test.rs:3:6 + --> test.rs:3:3 | -3 | X0 Y0 Z0 - | ______^ starting here... +3 | / X0 Y0 Z0 4 | | X1 Y1 Z1 - | |____^ ...ending here: `X` is a good letter + | |____^ `X` is a good letter 5 | X2 Y2 Z2 - | ______- starting here... + | ______- 6 | | X3 Y3 Z3 - | |__________- ...ending here: `Y` is a good letter too + | |__________- `Y` is a good letter too "#); } @@ -534,14 +533,14 @@ error: foo --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |____^____- starting here... + | |____^____- | ||____| - | | ...ending here: `X` is a good letter + | | `X` is a good letter 5 | | X2 Y2 Z2 6 | | X3 Y3 Z3 - | |___________- ...ending here: `Y` is a good letter too + | |___________- `Y` is a good letter too "#); } @@ -982,18 +981,18 @@ error: foo --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |____^____- starting here... + | |____^____- | ||____| - | | ...ending here: `X` is a good letter + | | `X` is a good letter 5 | | 1 6 | | 2 7 | | 3 ... | 15 | | X2 Y2 Z2 16 | | X3 Y3 Z3 - | |___________- ...ending here: `Y` is a good letter too + | |___________- `Y` is a good letter too "#); } @@ -1047,21 +1046,21 @@ error: foo --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | 1 5 | | 2 6 | | 3 7 | | X1 Y1 Z1 - | |_________- starting here... + | |_________- 8 | || 4 9 | || 5 10 | || 6 11 | || X2 Y2 Z2 - | ||__________- ...ending here: `Z` is a good letter too + | ||__________- `Z` is a good letter too ... | 15 | | 10 16 | | X3 Y3 Z3 - | |_______^ ...ending here: `Y` is a good letter + | |_______^ `Y` is a good letter "#); } diff --git a/src/test/ui/compare-method/region-extra-2.stderr b/src/test/ui/compare-method/region-extra-2.stderr index 12b0ecabcc72..af974d501839 100644 --- a/src/test/ui/compare-method/region-extra-2.stderr +++ b/src/test/ui/compare-method/region-extra-2.stderr @@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait 15 | fn renew<'b: 'a>(self) -> &'b mut [T]; | -------------------------------------- definition of `renew` from trait ... -19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { - | _____^ starting here... +19 | / fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { 20 | | //~^ ERROR E0276 21 | | &mut self[..] 22 | | } - | |_____^ ...ending here: impl has extra requirement `'a: 'b` + | |_____^ impl has extra requirement `'a: 'b` error: aborting due to previous error diff --git a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr index 77b056f69789..622e144c53a0 100644 --- a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr +++ b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr @@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait 19 | fn zip>(self, other: U) -> ZipIterator; | ------------------------------------------------------------------ definition of `zip` from trait ... -23 | fn zip>(self, other: U) -> ZipIterator { - | _____^ starting here... +23 | / fn zip>(self, other: U) -> ZipIterator { 24 | | //~^ ERROR E0276 25 | | ZipIterator{a: self, b: other} 26 | | } - | |_____^ ...ending here: impl has extra requirement `U: Iterator` + | |_____^ impl has extra requirement `U: Iterator` error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 29ff0cee3af5..8e8773eba3e2 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -2,17 +2,17 @@ error: missing `fn`, `type`, or `const` for impl-item declaration --> $DIR/issue-40006.rs:11:9 | 11 | impl X { - | _________^ starting here... + | _________^ 12 | | Y - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:17:10 | 17 | trait X { - | __________^ starting here... + | __________^ 18 | | X() {} - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: expected `[`, found `#` --> $DIR/issue-40006.rs:19:17 @@ -24,17 +24,17 @@ error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:19:21 | 19 | fn xxx() { ### } - | _____________________^ starting here... + | _____________________^ 20 | | L = M; - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:20:11 | 20 | L = M; - | ___________^ starting here... + | ___________^ 21 | | Z = { 2 + 3 }; - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` --> $DIR/issue-40006.rs:21:18 diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr index 92e2fe8e9367..2c788e952edb 100644 --- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -1,26 +1,24 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1 | -32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { - | _^ starting here... +32 | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { 33 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute 34 | | 35 | | // (unsafe to access self.1 due to #[may_dangle] on A) 36 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } 37 | | } - | |_^ ...ending here + | |_^ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1 | -38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { - | _^ starting here... +38 | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { 39 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute 40 | | 41 | | // (unsafe to access self.1 due to #[may_dangle] on 'a) 42 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } 43 | | } - | |_^ ...ending here + | |_^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr index 5a63d235a7f0..b51b683a1ac3 100644 --- a/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr @@ -1,11 +1,10 @@ error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(), &()), &(&()...` --> $DIR/issue-37311.rs:23:5 | -23 | fn recurse(&self) { - | _____^ starting here... +23 | / fn recurse(&self) { 24 | | (self, self).recurse(); 25 | | } - | |_____^ ...ending here + | |_____^ | = note: consider adding a `#![type_length_limit="2097152"]` attribute to your crate diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr index 85e05422ab3b..cf272b63128e 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr @@ -8,18 +8,18 @@ note: ...the reference is valid for the lifetime 'a as defined on the body at 11 --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44 | 11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { - | ____________________________________________^ starting here... + | ____________________________________________^ 12 | | if x > y { x } else { y } 13 | | } - | |_^ ...ending here + | |_^ note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the body at 11:43 --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44 | 11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { - | ____________________________________________^ starting here... + | ____________________________________________^ 12 | | if x > y { x } else { y } 13 | | } - | |_^ ...ending here + | |_^ error: aborting due to previous error diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr index 6956a043cc69..6e03e66dd258 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -10,18 +10,18 @@ note: the anonymous lifetime #2 defined on the body at 15:51... --> $DIR/ex2a-push-one-existing-name.rs:15:52 | 15 | fn foo<'a>(x: &mut Vec>, y: Ref) { - | ____________________________________________________^ starting here... + | ____________________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ note: ...does not necessarily outlive the lifetime 'a as defined on the body at 15:51 --> $DIR/ex2a-push-one-existing-name.rs:15:52 | 15 | fn foo<'a>(x: &mut Vec>, y: Ref) { - | ____________________________________________________^ starting here... + | ____________________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ error: aborting due to previous error diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr index 990ae65ba985..028f54ce9787 100644 --- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -10,18 +10,18 @@ note: the anonymous lifetime #3 defined on the body at 15:43... --> $DIR/ex2b-push-no-existing-names.rs:15:44 | 15 | fn foo(x: &mut Vec>, y: Ref) { - | ____________________________________________^ starting here... + | ____________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 15:43 --> $DIR/ex2b-push-no-existing-names.rs:15:44 | 15 | fn foo(x: &mut Vec>, y: Ref) { - | ____________________________________________^ starting here... + | ____________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ error: aborting due to previous error diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr index 82f6c71ec1c2..4621214419e4 100644 --- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr +++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr @@ -8,11 +8,11 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body --> $DIR/ex2c-push-inference-variable.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let z = Ref { data: y.data }; 17 | | x.push(z); 18 | | } - | |_^ ...ending here + | |_^ note: ...so that reference does not outlive borrowed content --> $DIR/ex2c-push-inference-variable.rs:16:25 | @@ -22,11 +22,11 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body --> $DIR/ex2c-push-inference-variable.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let z = Ref { data: y.data }; 17 | | x.push(z); 18 | | } - | |_^ ...ending here + | |_^ note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>) --> $DIR/ex2c-push-inference-variable.rs:17:12 | diff --git a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr index daa6ea2d91aa..a69694fdc2e5 100644 --- a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr +++ b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr @@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body --> $DIR/ex2d-push-inference-variable-2.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | a.push(b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that reference does not outlive borrowed content --> $DIR/ex2d-push-inference-variable-2.rs:17:25 | @@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body --> $DIR/ex2d-push-inference-variable-2.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | a.push(b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that expression is assignable (expected &mut std::vec::Vec>, found &mut std::vec::Vec>) --> $DIR/ex2d-push-inference-variable-2.rs:16:33 | diff --git a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr index b679532a4d91..eff15bb794b7 100644 --- a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr +++ b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr @@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body --> $DIR/ex2e-push-inference-variable-3.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | Vec::push(a, b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that reference does not outlive borrowed content --> $DIR/ex2e-push-inference-variable-3.rs:17:25 | @@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body --> $DIR/ex2e-push-inference-variable-3.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | Vec::push(a, b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that expression is assignable (expected &mut std::vec::Vec>, found &mut std::vec::Vec>) --> $DIR/ex2e-push-inference-variable-3.rs:16:33 | diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index c67c6113d17c..36bdec8d43af 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -37,15 +37,14 @@ error[E0308]: mismatched types error[E0308]: mismatched types --> $DIR/abridged.rs:42:5 | -42 | X { - | _____^ starting here... +42 | / X { 43 | | x: X { 44 | | x: "".to_string(), 45 | | y: 2, 46 | | }, 47 | | y: 3, 48 | | } - | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | |_____^ expected struct `std::string::String`, found integral variable | = note: expected type `X, std::string::String>` found type `X, {integer}>` @@ -53,15 +52,14 @@ error[E0308]: mismatched types error[E0308]: mismatched types --> $DIR/abridged.rs:52:5 | -52 | X { - | _____^ starting here... +52 | / X { 53 | | x: X { 54 | | x: "".to_string(), 55 | | y: 2, 56 | | }, 57 | | y: "".to_string(), 58 | | } - | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | |_____^ expected struct `std::string::String`, found integral variable | = note: expected type `X, _>` found type `X, _>` diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 5dd124ebcdff..c8941fbf9507 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -2,9 +2,9 @@ error[E0308]: mismatched types --> $DIR/main.rs:12:18 | 12 | let x: u32 = ( - | __________________^ starting here... + | __________________^ 13 | | ); - | |_____^ ...ending here: expected u32, found () + | |_____^ expected u32, found () | = note: expected type `u32` found type `()` diff --git a/src/test/ui/missing-items/m2.stderr b/src/test/ui/missing-items/m2.stderr index 331354345446..503ce5618d48 100644 --- a/src/test/ui/missing-items/m2.stderr +++ b/src/test/ui/missing-items/m2.stderr @@ -3,10 +3,9 @@ error: main function not found error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method` --> $DIR/m2.rs:20:1 | -20 | impl m1::X for X { - | _^ starting here... +20 | / impl m1::X for X { 21 | | } - | |_^ ...ending here: missing `CONSTANT`, `Type`, `method` in implementation + | |_^ missing `CONSTANT`, `Type`, `method` in implementation | = note: `CONSTANT` from trait: `const CONSTANT: u32;` = note: `Type` from trait: `type Type;` diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 367af12bb6b1..ae290b3b11aa 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -19,15 +19,14 @@ error[E0046]: not all trait items implemented, missing: `bar` 16 | fn bar(&self); | -------------- `bar` from trait ... -22 | impl Foo for FooConstForMethod { - | _^ starting here... +22 | / impl Foo for FooConstForMethod { 23 | | //~^ ERROR E0046 24 | | //~| NOTE missing `bar` in implementation 25 | | const bar: u64 = 1; ... | 28 | | const MY_CONST: u32 = 1; 29 | | } - | |_^ ...ending here: missing `bar` in implementation + | |_^ missing `bar` in implementation error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `Foo` --> $DIR/impl-wrong-item-for-trait.rs:37:5 @@ -44,15 +43,14 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST` 17 | const MY_CONST: u32; | -------------------- `MY_CONST` from trait ... -33 | impl Foo for FooMethodForConst { - | _^ starting here... +33 | / impl Foo for FooMethodForConst { 34 | | //~^ ERROR E0046 35 | | //~| NOTE missing `MY_CONST` in implementation 36 | | fn bar(&self) {} ... | 39 | | //~| NOTE does not match trait 40 | | } - | |_^ ...ending here: missing `MY_CONST` in implementation + | |_^ missing `MY_CONST` in implementation error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo` --> $DIR/impl-wrong-item-for-trait.rs:47:5 @@ -69,23 +67,21 @@ error[E0046]: not all trait items implemented, missing: `bar` 16 | fn bar(&self); | -------------- `bar` from trait ... -44 | impl Foo for FooTypeForMethod { - | _^ starting here... +44 | / impl Foo for FooTypeForMethod { 45 | | //~^ ERROR E0046 46 | | //~| NOTE missing `bar` in implementation 47 | | type bar = u64; ... | 50 | | const MY_CONST: u32 = 1; 51 | | } - | |_^ ...ending here: missing `bar` in implementation + | |_^ missing `bar` in implementation error[E0046]: not all trait items implemented, missing: `fmt` --> $DIR/impl-wrong-item-for-trait.rs:53:1 | -53 | impl Debug for FooTypeForMethod { - | _^ starting here... +53 | / impl Debug for FooTypeForMethod { 54 | | } - | |_^ ...ending here: missing `fmt` in implementation + | |_^ missing `fmt` in implementation | = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr index 701576ff6f47..d9f4bacce35a 100644 --- a/src/test/ui/span/issue-23729.stderr +++ b/src/test/ui/span/issue-23729.stderr @@ -1,15 +1,14 @@ error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | -20 | impl Iterator for Recurrence { - | _________^ starting here... +20 | / impl Iterator for Recurrence { 21 | | //~^ ERROR E0046 22 | | //~| NOTE missing `Item` in implementation 23 | | //~| NOTE `Item` from trait: `type Item;` ... | 36 | | } 37 | | } - | |_________^ ...ending here: missing `Item` in implementation + | |_________^ missing `Item` in implementation | = note: `Item` from trait: `type Item;` diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr index 457fed34ff1a..3127af157a62 100644 --- a/src/test/ui/span/issue-23827.stderr +++ b/src/test/ui/span/issue-23827.stderr @@ -1,15 +1,14 @@ error[E0046]: not all trait items implemented, missing: `Output` --> $DIR/issue-23827.rs:36:1 | -36 | impl FnOnce<(C,)> for Prototype { - | _^ starting here... +36 | / impl FnOnce<(C,)> for Prototype { 37 | | //~^ ERROR E0046 38 | | //~| NOTE missing `Output` in implementation 39 | | //~| NOTE `Output` from trait: `type Output;` ... | 42 | | } 43 | | } - | |_^ ...ending here: missing `Output` in implementation + | |_^ missing `Output` in implementation | = note: `Output` from trait: `type Output;` diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr index 963f4bd9bbcd..71ab82d98b80 100644 --- a/src/test/ui/span/issue-24356.stderr +++ b/src/test/ui/span/issue-24356.stderr @@ -1,14 +1,13 @@ error[E0046]: not all trait items implemented, missing: `Target` --> $DIR/issue-24356.rs:30:9 | -30 | impl Deref for Thing { - | _________^ starting here... +30 | / impl Deref for Thing { 31 | | //~^ ERROR E0046 32 | | //~| NOTE missing `Target` in implementation 33 | | //~| NOTE `Target` from trait: `type Target;` 34 | | fn deref(&self) -> i8 { self.0 } 35 | | } - | |_________^ ...ending here: missing `Target` in implementation + | |_________^ missing `Target` in implementation | = note: `Target` from trait: `type Target;` diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 765aceffe655..8b813220d789 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -38,11 +38,10 @@ error: no method named `fff` found for type `Myisize` in the current scope note: candidate #1 is defined in an impl for the type `Myisize` --> $DIR/issue-7575.rs:51:5 | -51 | fn fff(i: isize) -> isize { //~ NOTE candidate - | _____^ starting here... +51 | / fn fff(i: isize) -> isize { //~ NOTE candidate 52 | | i 53 | | } - | |_____^ ...ending here + | |_____^ error: no method named `is_str` found for type `T` in the current scope --> $DIR/issue-7575.rs:85:7 @@ -54,11 +53,10 @@ error: no method named `is_str` found for type `T` in the current scope note: candidate #1 is defined in the trait `ManyImplTrait` --> $DIR/issue-7575.rs:57:5 | -57 | fn is_str() -> bool { //~ NOTE candidate - | _____^ starting here... +57 | / fn is_str() -> bool { //~ NOTE candidate 58 | | false 59 | | } - | |_____^ ...ending here + | |_____^ = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `is_str`, perhaps you need to implement it: = help: candidate #1: `ManyImplTrait` diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr index 0df3fa43022a..f4998e08907a 100644 --- a/src/test/ui/span/lint-unused-unsafe.stderr +++ b/src/test/ui/span/lint-unused-unsafe.stderr @@ -49,68 +49,62 @@ note: because it's nested under this `unsafe` fn error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:33:9 | -33 | unsafe { //~ ERROR: unnecessary `unsafe` block - | _________^ starting here... +33 | / unsafe { //~ ERROR: unnecessary `unsafe` block 34 | | unsf() 35 | | } - | |_________^ ...ending here: unnecessary `unsafe` block + | |_________^ unnecessary `unsafe` block | note: because it's nested under this `unsafe` block --> $DIR/lint-unused-unsafe.rs:32:5 | -32 | unsafe { // don't put the warning here - | _____^ starting here... +32 | / unsafe { // don't put the warning here 33 | | unsafe { //~ ERROR: unnecessary `unsafe` block 34 | | unsf() 35 | | } 36 | | } - | |_____^ ...ending here + | |_____^ error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:39:5 | -39 | unsafe { //~ ERROR: unnecessary `unsafe` block - | _____^ starting here... +39 | / unsafe { //~ ERROR: unnecessary `unsafe` block 40 | | unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } 43 | | } - | |_____^ ...ending here: unnecessary `unsafe` block + | |_____^ unnecessary `unsafe` block | note: because it's nested under this `unsafe` fn --> $DIR/lint-unused-unsafe.rs:38:1 | -38 | unsafe fn bad7() { - | _^ starting here... +38 | / unsafe fn bad7() { 39 | | unsafe { //~ ERROR: unnecessary `unsafe` block 40 | | unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } 43 | | } 44 | | } - | |_^ ...ending here + | |_^ error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:40:9 | -40 | unsafe { //~ ERROR: unnecessary `unsafe` block - | _________^ starting here... +40 | / unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } - | |_________^ ...ending here: unnecessary `unsafe` block + | |_________^ unnecessary `unsafe` block | note: because it's nested under this `unsafe` fn --> $DIR/lint-unused-unsafe.rs:38:1 | -38 | unsafe fn bad7() { - | _^ starting here... +38 | / unsafe fn bad7() { 39 | | unsafe { //~ ERROR: unnecessary `unsafe` block 40 | | unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } 43 | | } 44 | | } - | |_^ ...ending here + | |_^ error: aborting due to 8 previous errors diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index 58cdc5023006..9c6816e73631 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -1,14 +1,13 @@ error[E0072]: recursive type `ListNode` has infinite size --> $DIR/multiline-span-E0072.rs:12:1 | -12 | struct - | _^ starting here... +12 | / struct 13 | | ListNode 14 | | { 15 | | head: u8, 16 | | tail: Option, 17 | | } - | |_^ ...ending here: recursive type has infinite size + | |_^ recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 161b6ca48b28..843c1e811d57 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -2,12 +2,12 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied --> $DIR/multiline-span-simple.rs:23:9 | 23 | foo(1 as u32 + - | _________^ starting here... + | _________^ 24 | | 25 | | bar(x, 26 | | 27 | | y), - | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32` + | |______________^ the trait `std::ops::Add<()>` is not implemented for `u32` | = note: no implementation for `u32 + ()` diff --git a/src/test/ui/type-check/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr index 5c388c9d602e..7a76799889b9 100644 --- a/src/test/ui/type-check/issue-40294.stderr +++ b/src/test/ui/type-check/issue-40294.stderr @@ -1,15 +1,14 @@ error[E0282]: type annotations needed --> $DIR/issue-40294.rs:15:1 | -15 | fn foo<'a,'b,T>(x: &'a T, y: &'b T) - | _^ starting here... +15 | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) 16 | | where &'a T : Foo, 17 | | &'b T : Foo 18 | | { 19 | | x.foo(); 20 | | y.foo(); 21 | | } - | |_^ ...ending here: cannot infer type for `&'a T` + | |_^ cannot infer type for `&'a T` error: aborting due to previous error From a76274e533969c8458c4471fbfc1b84ba44137e0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 11:25:05 -0700 Subject: [PATCH 610/905] Remove EnumSet [unstable, deprecated since 1.16.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../src/library-features/enumset.md | 7 - src/libcollections/enum_set.rs | 313 ------------------ src/libcollections/lib.rs | 4 - .../sync-send-iterators-in-libcollections.rs | 19 +- 5 files changed, 1 insertion(+), 343 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/enumset.md delete mode 100644 src/libcollections/enum_set.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 3e0415439774..b803b6556cfa 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -130,7 +130,6 @@ - [derive_clone_copy](library-features/derive-clone-copy.md) - [derive_eq](library-features/derive-eq.md) - [discriminant_value](library-features/discriminant-value.md) - - [enumset](library-features/enumset.md) - [error_type_id](library-features/error-type-id.md) - [exact_size_is_empty](library-features/exact-size-is-empty.md) - [fd](library-features/fd.md) diff --git a/src/doc/unstable-book/src/library-features/enumset.md b/src/doc/unstable-book/src/library-features/enumset.md deleted file mode 100644 index 24c8d8fa7dbb..000000000000 --- a/src/doc/unstable-book/src/library-features/enumset.md +++ /dev/null @@ -1,7 +0,0 @@ -# `enumset` - -The tracking issue for this feature is: [#37966] - -[#37966]: https://github.com/rust-lang/rust/issues/37966 - ------------------------- diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs deleted file mode 100644 index aaee567bf1db..000000000000 --- a/src/libcollections/enum_set.rs +++ /dev/null @@ -1,313 +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 structure for holding a set of enum variants. -//! -//! This module defines a container which uses an efficient bit mask -//! representation to hold C-like enum variants. - -#![unstable(feature = "enumset", - reason = "matches collection reform specification, \ - waiting for dust to settle", - issue = "37966")] -#![rustc_deprecated(since = "1.16.0", reason = "long since replaced")] -#![allow(deprecated)] - -use core::marker; -use core::fmt; -use core::iter::{FromIterator, FusedIterator}; -use core::ops::{Sub, BitOr, BitAnd, BitXor}; - -// FIXME(contentions): implement union family of methods? (general design may be -// wrong here) - -/// A specialized set implementation to use enum types. -/// -/// It is a logic error for an item to be modified in such a way that the -/// transformation of the item to or from a `usize`, as determined by the -/// `CLike` trait, changes while the item is in the set. This is normally only -/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EnumSet { - // We must maintain the invariant that no bits are set - // for which no variant exists - bits: usize, - marker: marker::PhantomData, -} - -impl Copy for EnumSet {} - -impl Clone for EnumSet { - fn clone(&self) -> EnumSet { - *self - } -} - -impl fmt::Debug for EnumSet { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_set().entries(self).finish() - } -} - -/// An interface for casting C-like enum to usize and back. -/// A typically implementation is as below. -/// -/// ```{rust,ignore} -/// #[repr(usize)] -/// enum Foo { -/// A, B, C -/// } -/// -/// impl CLike for Foo { -/// fn to_usize(&self) -> usize { -/// *self as usize -/// } -/// -/// fn from_usize(v: usize) -> Foo { -/// unsafe { mem::transmute(v) } -/// } -/// } -/// ``` -pub trait CLike { - /// Converts a C-like enum to a `usize`. - fn to_usize(&self) -> usize; - /// Converts a `usize` to a C-like enum. - fn from_usize(usize) -> Self; -} - -fn bit(e: &E) -> usize { - use core::mem; - let value = e.to_usize(); - let bits = mem::size_of::() * 8; - assert!(value < bits, - "EnumSet only supports up to {} variants.", - bits - 1); - 1 << value -} - -impl EnumSet { - /// Returns an empty `EnumSet`. - pub fn new() -> EnumSet { - EnumSet { - bits: 0, - marker: marker::PhantomData, - } - } - - /// Returns the number of elements in the given `EnumSet`. - pub fn len(&self) -> usize { - self.bits.count_ones() as usize - } - - /// Returns `true` if the `EnumSet` is empty. - pub fn is_empty(&self) -> bool { - self.bits == 0 - } - - pub fn clear(&mut self) { - self.bits = 0; - } - - /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`. - pub fn is_disjoint(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == 0 - } - - /// Returns `true` if a given `EnumSet` is included in this `EnumSet`. - pub fn is_superset(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == other.bits - } - - /// Returns `true` if this `EnumSet` is included in the given `EnumSet`. - pub fn is_subset(&self, other: &EnumSet) -> bool { - other.is_superset(self) - } - - /// Returns the union of both `EnumSets`. - pub fn union(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } - - /// Returns the intersection of both `EnumSets`. - pub fn intersection(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } - - /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before - pub fn insert(&mut self, e: E) -> bool { - let result = !self.contains(&e); - self.bits |= bit(&e); - result - } - - /// Removes an enum from the EnumSet - pub fn remove(&mut self, e: &E) -> bool { - let result = self.contains(e); - self.bits &= !bit(e); - result - } - - /// Returns `true` if an `EnumSet` contains a given enum. - pub fn contains(&self, e: &E) -> bool { - (self.bits & bit(e)) != 0 - } - - /// Returns an iterator over an `EnumSet`. - pub fn iter(&self) -> Iter { - Iter::new(self.bits) - } -} - -impl Sub for EnumSet { - type Output = EnumSet; - - fn sub(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & !e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitOr for EnumSet { - type Output = EnumSet; - - fn bitor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitAnd for EnumSet { - type Output = EnumSet; - - fn bitand(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitXor for EnumSet { - type Output = EnumSet; - - fn bitxor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits ^ e.bits, - marker: marker::PhantomData, - } - } -} - -/// An iterator over an `EnumSet` -pub struct Iter { - index: usize, - bits: usize, - marker: marker::PhantomData, -} - -impl fmt::Debug for Iter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.index) - .field(&self.bits) - .finish() - } -} - -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` -impl Clone for Iter { - fn clone(&self) -> Iter { - Iter { - index: self.index, - bits: self.bits, - marker: marker::PhantomData, - } - } -} - -impl Iter { - fn new(bits: usize) -> Iter { - Iter { - index: 0, - bits: bits, - marker: marker::PhantomData, - } - } -} - -impl Iterator for Iter { - type Item = E; - - fn next(&mut self) -> Option { - if self.bits == 0 { - return None; - } - - while (self.bits & 1) == 0 { - self.index += 1; - self.bits >>= 1; - } - let elem = CLike::from_usize(self.index); - self.index += 1; - self.bits >>= 1; - Some(elem) - } - - fn size_hint(&self) -> (usize, Option) { - let exact = self.bits.count_ones() as usize; - (exact, Some(exact)) - } -} - -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Iter {} - -impl FromIterator for EnumSet { - fn from_iter>(iter: I) -> EnumSet { - let mut ret = EnumSet::new(); - ret.extend(iter); - ret - } -} - -impl<'a, E> IntoIterator for &'a EnumSet - where E: CLike -{ - type Item = E; - type IntoIter = Iter; - - fn into_iter(self) -> Iter { - self.iter() - } -} - -impl Extend for EnumSet { - fn extend>(&mut self, iter: I) { - for element in iter { - self.insert(element); - } - } -} - -impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 3bea61f6220b..8d056afdb571 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -89,9 +89,6 @@ pub use btree_set::BTreeSet; #[doc(no_inline)] pub use linked_list::LinkedList; #[doc(no_inline)] -#[allow(deprecated)] -pub use enum_set::EnumSet; -#[doc(no_inline)] pub use vec_deque::VecDeque; #[doc(no_inline)] pub use string::String; @@ -107,7 +104,6 @@ mod macros; pub mod binary_heap; mod btree; pub mod borrow; -pub mod enum_set; pub mod fmt; pub mod linked_list; pub mod range; 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 d046705c94bb..ea154590deef 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -10,13 +10,12 @@ #![allow(warnings)] #![feature(collections)] -#![feature(drain, enumset, collections_bound, btree_range, vecmap)] +#![feature(drain, collections_bound, btree_range, vecmap)] extern crate collections; use collections::BinaryHeap; use collections::{BTreeMap, BTreeSet}; -use collections::EnumSet; use collections::LinkedList; use collections::String; use collections::Vec; @@ -25,7 +24,6 @@ use std::collections::HashMap; use std::collections::HashSet; use collections::Bound::Included; -use collections::enum_set::CLike; use std::mem; fn is_sync(_: T) where T: Sync {} @@ -76,21 +74,6 @@ fn main() { all_sync_send!(LinkedList::::new(), iter, iter_mut, into_iter); - #[derive(Copy, Clone)] - #[repr(usize)] - #[allow(dead_code)] - enum Foo { A, B, C } - impl CLike for Foo { - fn to_usize(&self) -> usize { - *self as usize - } - - fn from_usize(v: usize) -> Foo { - unsafe { mem::transmute(v) } - } - } - all_sync_send!(EnumSet::::new(), iter); - all_sync_send!(VecDeque::::new(), iter, iter_mut, into_iter); is_sync_send!(VecDeque::::new(), drain(..)); From a724ff90e744c782e425e634defbf143b8ef62b9 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 13:36:23 -0700 Subject: [PATCH 611/905] Remove BinaryHeap::{push_pop,replace} [unstable, deprecated since 1.13.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../library-features/binary-heap-extras.md | 7 -- src/libcollections/binary_heap.rs | 76 ------------------- src/libcollections/tests/binary_heap.rs | 37 --------- src/libcollections/tests/lib.rs | 1 - src/test/run-pass/while-let.rs | 2 - 6 files changed, 124 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/binary-heap-extras.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index b803b6556cfa..4951ff7965a8 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -103,7 +103,6 @@ - [as_c_str](library-features/as-c-str.md) - [as_unsafe_cell](library-features/as-unsafe-cell.md) - [ascii_ctype](library-features/ascii-ctype.md) - - [binary_heap_extras](library-features/binary-heap-extras.md) - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md) - [borrow_state](library-features/borrow-state.md) - [box_heap](library-features/box-heap.md) diff --git a/src/doc/unstable-book/src/library-features/binary-heap-extras.md b/src/doc/unstable-book/src/library-features/binary-heap-extras.md deleted file mode 100644 index aa535f3b6784..000000000000 --- a/src/doc/unstable-book/src/library-features/binary-heap-extras.md +++ /dev/null @@ -1,7 +0,0 @@ -# `binary_heap_extras` - -The tracking issue for this feature is: [#28147] - -[#28147]: https://github.com/rust-lang/rust/issues/28147 - ------------------------- diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 149c285a72a9..e61d5b316960 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -555,82 +555,6 @@ impl BinaryHeap { self.sift_up(0, old_len); } - /// Pushes an item onto the binary heap, then pops the greatest item off the queue in - /// an optimized fashion. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.push(1); - /// heap.push(5); - /// - /// assert_eq!(heap.push_pop(3), 5); - /// assert_eq!(heap.push_pop(9), 9); - /// assert_eq!(heap.len(), 2); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn push_pop(&mut self, mut item: T) -> T { - match self.data.get_mut(0) { - None => return item, - Some(top) => { - if *top > item { - swap(&mut item, top); - } else { - return item; - } - } - } - - self.sift_down(0); - item - } - - /// Pops the greatest item off the binary heap, then pushes an item onto the queue in - /// an optimized fashion. The push is done regardless of whether the binary heap - /// was empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// - /// assert_eq!(heap.replace(1), None); - /// assert_eq!(heap.replace(3), Some(1)); - /// assert_eq!(heap.len(), 1); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn replace(&mut self, mut item: T) -> Option { - if !self.is_empty() { - swap(&mut item, &mut self.data[0]); - self.sift_down(0); - Some(item) - } else { - self.push(item); - None - } - } - /// Consumes the `BinaryHeap` and returns the underlying vector /// in arbitrary order. /// diff --git a/src/libcollections/tests/binary_heap.rs b/src/libcollections/tests/binary_heap.rs index d284937a9e67..af18cddaddb0 100644 --- a/src/libcollections/tests/binary_heap.rs +++ b/src/libcollections/tests/binary_heap.rs @@ -152,36 +152,6 @@ fn test_push_unique() { assert!(*heap.peek().unwrap() == box 103); } -#[test] -#[allow(deprecated)] -fn test_push_pop() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(6), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(0), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(4), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(1), 4); - assert_eq!(heap.len(), 5); -} - -#[test] -#[allow(deprecated)] -fn test_replace() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(6).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(0).unwrap(), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(4).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(1).unwrap(), 4); - assert_eq!(heap.len(), 5); -} - fn check_to_vec(mut data: Vec) { let heap = BinaryHeap::from(data.clone()); let mut v = heap.clone().into_vec(); @@ -227,13 +197,6 @@ fn test_empty_peek_mut() { assert!(empty.peek_mut().is_none()); } -#[test] -#[allow(deprecated)] -fn test_empty_replace() { - let mut heap = BinaryHeap::new(); - assert!(heap.replace(5).is_none()); -} - #[test] fn test_from_iter() { let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1]; diff --git a/src/libcollections/tests/lib.rs b/src/libcollections/tests/lib.rs index 618eb386c0f4..9c6e31d70a54 100644 --- a/src/libcollections/tests/lib.rs +++ b/src/libcollections/tests/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![feature(binary_heap_extras)] #![feature(binary_heap_peek_mut_pop)] #![feature(box_syntax)] #![feature(inclusive_range_syntax)] diff --git a/src/test/run-pass/while-let.rs b/src/test/run-pass/while-let.rs index 9ffba2c7999f..aed6986c5fe5 100644 --- a/src/test/run-pass/while-let.rs +++ b/src/test/run-pass/while-let.rs @@ -9,8 +9,6 @@ // except according to those terms. -#![feature(binary_heap_extras)] - use std::collections::BinaryHeap; fn make_pq() -> BinaryHeap { From df86cecdd2ca927110c48c97227a62d1d0c8f7ce Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 13:50:47 -0700 Subject: [PATCH 612/905] Remove OccupiedEntry::remove_pair [unstable, deprecated since 1.12.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../src/library-features/map-entry-recover-keys.md | 5 ----- src/libcollections/btree/map.rs | 7 ------- src/libstd/collections/hash/map.rs | 7 ------- 4 files changed, 20 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/map-entry-recover-keys.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 4951ff7965a8..0d5aa4b5c422 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -163,7 +163,6 @@ - [linked_list_extras](library-features/linked-list-extras.md) - [lookup_host](library-features/lookup-host.md) - [manually_drop](library-features/manually-drop.md) - - [map_entry_recover_keys](library-features/map-entry-recover-keys.md) - [mpsc_select](library-features/mpsc-select.md) - [n16](library-features/n16.md) - [never_type_impls](library-features/never-type-impls.md) diff --git a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md b/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md deleted file mode 100644 index 2d15aa0e90de..000000000000 --- a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md +++ /dev/null @@ -1,5 +0,0 @@ -# `map_entry_recover_keys` - -The tracking issue for this feature is: [#34285] - -[#34285]: https://github.com/rust-lang/rust/issues/34285 diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index fb0b852d1027..885b97dda816 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -2217,13 +2217,6 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { self.handle.reborrow().into_kv().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take ownership of the key and value from the map. /// /// # Examples diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index eacb59d375a5..c8732e68c853 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2017,13 +2017,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { self.elem.read().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take the ownership of the key and value from the map. /// /// # Examples From f4aaae9bdbca695d8d60feaa63cb09cf06598d50 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 13:55:38 -0700 Subject: [PATCH 613/905] Remove Rc::would_wrap [unstable, deprecated since 1.15.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../src/library-features/rc-would-unwrap.md | 5 ----- src/liballoc/rc.rs | 13 ------------- 3 files changed, 19 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/rc-would-unwrap.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 0d5aa4b5c422..cc03ac4d244d 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -185,7 +185,6 @@ - [rand](library-features/rand.md) - [range_contains](library-features/range-contains.md) - [raw](library-features/raw.md) - - [rc_would_unwrap](library-features/rc-would-unwrap.md) - [retain_hash_collection](library-features/retain-hash-collection.md) - [reverse_cmp_key](library-features/reverse-cmp-key.md) - [rt](library-features/rt.md) diff --git a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md b/src/doc/unstable-book/src/library-features/rc-would-unwrap.md deleted file mode 100644 index 462387dfdcc4..000000000000 --- a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md +++ /dev/null @@ -1,5 +0,0 @@ -# `rc_would_unwrap` - -The tracking issue for this feature is: [#28356] - -[#28356]: https://github.com/rust-lang/rust/issues/28356 diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index fed718e9be4c..dab6cf011bdf 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -341,19 +341,6 @@ impl Rc { } } - /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return - /// [`Ok`]. - /// - /// [try_unwrap]: struct.Rc.html#method.try_unwrap - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - #[unstable(feature = "rc_would_unwrap", - reason = "just added for niche usecase", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", reason = "too niche; use `strong_count` instead")] - pub fn would_unwrap(this: &Self) -> bool { - Rc::strong_count(&this) == 1 - } - /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using From f0c5e8b8fc6d3631de39cfc250868da993ff4086 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 14:02:20 -0700 Subject: [PATCH 614/905] Privatize Rc::is_unique [unstable, deprecated since 1.15.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - src/doc/unstable-book/src/library-features/is-unique.md | 7 ------- src/liballoc/rc.rs | 6 +----- 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/is-unique.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index cc03ac4d244d..0362ed6ba9d3 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -155,7 +155,6 @@ - [io_error_internals](library-features/io-error-internals.md) - [io](library-features/io.md) - [ip](library-features/ip.md) - - [is_unique](library-features/is-unique.md) - [iter_rfind](library-features/iter-rfind.md) - [libstd_io_internals](library-features/libstd-io-internals.md) - [libstd_sys_internals](library-features/libstd-sys-internals.md) diff --git a/src/doc/unstable-book/src/library-features/is-unique.md b/src/doc/unstable-book/src/library-features/is-unique.md deleted file mode 100644 index 6070006758b7..000000000000 --- a/src/doc/unstable-book/src/library-features/is-unique.md +++ /dev/null @@ -1,7 +0,0 @@ -# `is_unique` - -The tracking issue for this feature is: [#28356] - -[#28356]: https://github.com/rust-lang/rust/issues/28356 - ------------------------- diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index dab6cf011bdf..b12d89867c8e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -488,11 +488,7 @@ impl Rc { /// /// [weak]: struct.Weak.html #[inline] - #[unstable(feature = "is_unique", reason = "uniqueness has unclear meaning", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", - reason = "too niche; use `strong_count` and `weak_count` instead")] - pub fn is_unique(this: &Self) -> bool { + fn is_unique(this: &Self) -> bool { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } From cc605c895e3ac3d19b70da58a683a65200c491fe Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 14:06:18 -0700 Subject: [PATCH 615/905] Remove {Cell,RefCell}::as_unsafe_cell [unstable, deprecated since 1.12.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../src/library-features/as-unsafe-cell.md | 7 --- src/libcore/cell.rs | 43 ------------------- 3 files changed, 51 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/as-unsafe-cell.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 0362ed6ba9d3..2a932e342f6a 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -101,7 +101,6 @@ - [alloc_system](library-features/alloc-system.md) - [alloc](library-features/alloc.md) - [as_c_str](library-features/as-c-str.md) - - [as_unsafe_cell](library-features/as-unsafe-cell.md) - [ascii_ctype](library-features/ascii-ctype.md) - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md) - [borrow_state](library-features/borrow-state.md) diff --git a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md b/src/doc/unstable-book/src/library-features/as-unsafe-cell.md deleted file mode 100644 index 79d7a7cad0b6..000000000000 --- a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md +++ /dev/null @@ -1,7 +0,0 @@ -# `as_unsafe_cell` - -The tracking issue for this feature is: [#27708] - -[#27708]: https://github.com/rust-lang/rust/issues/27708 - ------------------------- diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 0186d9727828..a5dda5625bd3 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -310,26 +310,6 @@ impl Cell { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let uc = c.as_unsafe_cell(); - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples @@ -769,29 +749,6 @@ impl RefCell { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// This can be used to circumvent `RefCell`'s safety checks. - /// - /// This function is `unsafe` because `UnsafeCell`'s field is public. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// let c = unsafe { c.as_unsafe_cell() }; - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples From 313aab8fbeb98730f8ffa741ccf54f843d5e3525 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 14:10:22 -0700 Subject: [PATCH 616/905] Remove RefCell::borrow_state [unstable, deprecated since 1.15.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../src/library-features/borrow-state.md | 7 --- src/libcore/cell.rs | 46 ------------------- src/libstd/lib.rs | 1 - 4 files changed, 55 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/borrow-state.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 2a932e342f6a..ae3b23a33b24 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -103,7 +103,6 @@ - [as_c_str](library-features/as-c-str.md) - [ascii_ctype](library-features/ascii-ctype.md) - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md) - - [borrow_state](library-features/borrow-state.md) - [box_heap](library-features/box-heap.md) - [c_void_variant](library-features/c-void-variant.md) - [char_escape_debug](library-features/char-escape-debug.md) diff --git a/src/doc/unstable-book/src/library-features/borrow-state.md b/src/doc/unstable-book/src/library-features/borrow-state.md deleted file mode 100644 index 304b8dffe986..000000000000 --- a/src/doc/unstable-book/src/library-features/borrow-state.md +++ /dev/null @@ -1,7 +0,0 @@ -# `borrow_state` - -The tracking issue for this feature is: [#27733] - -[#27733]: https://github.com/rust-lang/rust/issues/27733 - ------------------------- diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index a5dda5625bd3..ba04cbb0543c 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -460,20 +460,6 @@ pub struct RefCell { value: UnsafeCell, } -/// An enumeration of values returned from the `state` method on a `RefCell`. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "borrow_state", issue = "27733")] -#[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] -#[allow(deprecated)] -pub enum BorrowState { - /// The cell is currently being read, there is at least one active `borrow`. - Reading, - /// The cell is currently being written to, there is an active `borrow_mut`. - Writing, - /// There are no outstanding borrows on this cell. - Unused, -} - /// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow). #[stable(feature = "try_borrow", since = "1.13.0")] pub struct BorrowError { @@ -562,38 +548,6 @@ impl RefCell { } impl RefCell { - /// Query the current state of this `RefCell` - /// - /// The returned value can be dispatched on to determine if a call to - /// `borrow` or `borrow_mut` would succeed. - /// - /// # Examples - /// - /// ``` - /// #![feature(borrow_state)] - /// - /// use std::cell::{BorrowState, RefCell}; - /// - /// let c = RefCell::new(5); - /// - /// match c.borrow_state() { - /// BorrowState::Writing => println!("Cannot be borrowed"), - /// BorrowState::Reading => println!("Cannot be borrowed mutably"), - /// BorrowState::Unused => println!("Can be borrowed (mutably as well)"), - /// } - /// ``` - #[unstable(feature = "borrow_state", issue = "27733")] - #[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] - #[allow(deprecated)] - #[inline] - pub fn borrow_state(&self) -> BorrowState { - match self.borrow.get() { - WRITING => BorrowState::Writing, - UNUSED => BorrowState::Unused, - _ => BorrowState::Reading, - } - } - /// Immutably borrows the wrapped value. /// /// The borrow lasts until the returned `Ref` exits scope. Multiple diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 367779bb701c..6c3abf99d11f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -248,7 +248,6 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_consts)] -#![feature(borrow_state)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] From c903ac64e58241a71ec42e791b0cc1451ffc3840 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 15:12:42 -0700 Subject: [PATCH 617/905] Remove num::{Zero,One} [unstable, deprecated since 1.11.0] --- src/doc/unstable-book/src/SUMMARY.md | 2 - .../src/library-features/zero-one.md | 7 -- src/libcore/fmt/num.rs | 5 +- src/libcore/num/mod.rs | 72 ------------------- src/libstd/lib.rs | 1 - src/libstd/num.rs | 3 - src/test/run-pass/issue-8460.rs | 35 +++++---- 7 files changed, 26 insertions(+), 99 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/zero-one.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index ae3b23a33b24..48659413cad0 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -217,5 +217,3 @@ - [windows_handle](library-features/windows-handle.md) - [windows_net](library-features/windows-net.md) - [windows_stdio](library-features/windows-stdio.md) - - [zero_one](library-features/zero-one.md) ->>>>>> Add top level sections to the Unstable Book. diff --git a/src/doc/unstable-book/src/library-features/zero-one.md b/src/doc/unstable-book/src/library-features/zero-one.md deleted file mode 100644 index 4d1cf38c3c2e..000000000000 --- a/src/doc/unstable-book/src/library-features/zero-one.md +++ /dev/null @@ -1,7 +0,0 @@ -# `zero_one` - -The tracking issue for this feature is: [#27739] - -[#27739]: https://github.com/rust-lang/rust/issues/27739 - ------------------------- diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index a324a4aed257..4ca303dee43f 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -15,7 +15,6 @@ // FIXME: #6220 Implement floating point formatting use fmt; -use num::Zero; use ops::{Div, Rem, Sub}; use str; use slice; @@ -23,8 +22,9 @@ use ptr; use mem; #[doc(hidden)] -trait Int: Zero + PartialEq + PartialOrd + Div + Rem + +trait Int: PartialEq + PartialOrd + Div + Rem + Sub + Copy { + fn zero() -> Self; fn from_u8(u: u8) -> Self; fn to_u8(&self) -> u8; fn to_u16(&self) -> u16; @@ -35,6 +35,7 @@ trait Int: Zero + PartialEq + PartialOrd + Div + Rem + macro_rules! doit { ($($t:ident)*) => ($(impl Int for $t { + fn zero() -> $t { 0 } fn from_u8(u: u8) -> $t { u as $t } fn to_u8(&self) -> u8 { *self as u8 } fn to_u16(&self) -> u16 { *self as u16 } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f665cfdee77a..1e25d45bfbb5 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -96,78 +96,6 @@ pub mod dec2flt; pub mod bignum; pub mod diy_float; -/// Types that have a "zero" value. -/// -/// This trait is intended for use in conjunction with `Add`, as an identity: -/// `x + T::zero() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::sum")] -pub trait Zero: Sized { - /// The "zero" (usually, additive identity) for this type. - fn zero() -> Self; -} - -/// Types that have a "one" value. -/// -/// This trait is intended for use in conjunction with `Mul`, as an identity: -/// `x * T::one() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::product")] -pub trait One: Sized { - /// The "one" (usually, multiplicative identity) for this type. - fn one() -> Self; -} - -macro_rules! zero_one_impl { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1 } - } - )*) -} -zero_one_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } - -macro_rules! zero_one_impl_float { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0.0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1.0 } - } - )*) -} -zero_one_impl_float! { f32 f64 } - macro_rules! checked_op { ($U:ty, $op:path, $x:expr, $y:expr) => {{ let (result, overflowed) = unsafe { $op($x as $U, $y as $U) }; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 6c3abf99d11f..28b94107c425 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -318,7 +318,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] -#![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(stage0, feature(pub_restricted))] #![cfg_attr(test, feature(float_bits_conv))] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 5f83d077a136..ff89887ac92c 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -16,9 +16,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use core::num::{Zero, One}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index 5148be5af830..17ea5b9a7948 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -9,11 +9,22 @@ // except according to those terms. // ignore-emscripten no threads support -#![feature(rustc_attrs, zero_one)] +#![feature(rustc_attrs)] -use std::num::Zero; use std::thread; +trait Int { + fn zero() -> Self; + fn one() -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl Int for $t { + fn zero() -> $t { 0 } + fn one() -> $t { 1 } + })*) +} +doit! { i8 i16 i32 i64 isize } + macro_rules! check { ($($e:expr),*) => { $(assert!(thread::spawn({ @@ -24,21 +35,21 @@ macro_rules! check { fn main() { check![ - isize::min_value() / -1, - i8::min_value() / -1, - i16::min_value() / -1, - i32::min_value() / -1, - i64::min_value() / -1, + isize::min_value() / -isize::one(), + i8::min_value() / -i8::one(), + i16::min_value() / -i16::one(), + i32::min_value() / -i32::one(), + i64::min_value() / -i64::one(), 1isize / isize::zero(), 1i8 / i8::zero(), 1i16 / i16::zero(), 1i32 / i32::zero(), 1i64 / i64::zero(), - isize::min_value() % -1, - i8::min_value() % -1, - i16::min_value() % -1, - i32::min_value() % -1, - i64::min_value() % -1, + isize::min_value() % -isize::one(), + i8::min_value() % -i8::one(), + i16::min_value() % -i16::one(), + i32::min_value() % -i32::one(), + i64::min_value() % -i64::one(), 1isize % isize::zero(), 1i8 % i8::zero(), 1i16 % i16::zero(), From c1aaa60d8de1c90939671f10ce7ce08400e27ad7 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 20 Apr 2017 16:09:54 -0700 Subject: [PATCH 618/905] Remove float_extras [unstable, deprecated since 1.11.0] --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../src/library-features/float-extras.md | 7 - src/libcore/num/dec2flt/rawfp.rs | 41 +++- src/libcore/num/f32.rs | 45 ---- src/libcore/num/f64.rs | 45 ---- src/libcore/num/flt2dec/decoder.rs | 4 +- src/libcore/num/mod.rs | 51 ----- src/libcore/tests/num/dec2flt/rawfp.rs | 47 ++-- src/libstd/f32.rs | 204 ------------------ src/libstd/f64.rs | 179 --------------- src/libstd/lib.rs | 1 - src/test/run-pass/union/union-transmute.rs | 8 +- 12 files changed, 74 insertions(+), 559 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/float-extras.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 48659413cad0..9fbd4e300f8f 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -133,7 +133,6 @@ - [fd_read](library-features/fd-read.md) - [fixed_size_array](library-features/fixed-size-array.md) - [float_bits_conv](library-features/float-bits-conv.md) - - [float_extras](library-features/float-extras.md) - [flt2dec](library-features/flt2dec.md) - [fmt_flags_align](library-features/fmt-flags-align.md) - [fmt_internals](library-features/fmt-internals.md) diff --git a/src/doc/unstable-book/src/library-features/float-extras.md b/src/doc/unstable-book/src/library-features/float-extras.md deleted file mode 100644 index ff2d20a545fe..000000000000 --- a/src/doc/unstable-book/src/library-features/float-extras.md +++ /dev/null @@ -1,7 +0,0 @@ -# `float_extras` - -The tracking issue for this feature is: [#27752] - -[#27752]: https://github.com/rust-lang/rust/issues/27752 - ------------------------- diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 1485c79ead25..2a60292d0232 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -63,11 +63,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp const NAN: Self; const ZERO: Self; - // suffix of "2" because Float::integer_decode is deprecated - #[allow(deprecated)] - fn integer_decode2(self) -> (u64, i16, i8) { - Float::integer_decode(self) - } + /// 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; @@ -160,6 +157,21 @@ impl RawFloat for f32 { const ZERO_CUTOFF: i64 = -48; other_constants!(f32); + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u32 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; + let mantissa = if exponent == 0 { + (bits & 0x7fffff) << 1 + } else { + (bits & 0x7fffff) | 0x800000 + }; + // Exponent bias + mantissa shift + exponent -= 127 + 23; + (mantissa as u64, exponent, sign) + } + fn transmute(self) -> u64 { let bits: u32 = unsafe { transmute(self) }; bits as u64 @@ -171,7 +183,7 @@ impl RawFloat for f32 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } @@ -196,6 +208,21 @@ impl RawFloat for f64 { const ZERO_CUTOFF: i64 = -326; other_constants!(f64); + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u64 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; + let mantissa = if exponent == 0 { + (bits & 0xfffffffffffff) << 1 + } else { + (bits & 0xfffffffffffff) | 0x10000000000000 + }; + // Exponent bias + mantissa shift + exponent -= 1023 + 52; + (mantissa, exponent, sign) + } + fn transmute(self) -> u64 { let bits: u64 = unsafe { transmute(self) }; bits @@ -206,7 +233,7 @@ impl RawFloat for f64 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 4527d46a27d8..91ca213e96e0 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f32 { - #[inline] - fn nan() -> f32 { - NAN - } - - #[inline] - fn infinity() -> f32 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f32 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f32 { - 0.0 - } - - #[inline] - fn neg_zero() -> f32 { - -0.0 - } - - #[inline] - fn one() -> f32 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ impl Float for f32 { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u32 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; - let mantissa = if exponent == 0 { - (bits & 0x7fffff) << 1 - } else { - (bits & 0x7fffff) | 0x800000 - }; - // Exponent bias + mantissa shift - exponent -= 127 + 23; - (mantissa as u64, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 991a85683494..7d6d6cef0497 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f64 { - #[inline] - fn nan() -> f64 { - NAN - } - - #[inline] - fn infinity() -> f64 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f64 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f64 { - 0.0 - } - - #[inline] - fn neg_zero() -> f64 { - -0.0 - } - - #[inline] - fn one() -> f64 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ impl Float for f64 { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs index 72529d3da01d..b779eefce575 100644 --- a/src/libcore/num/flt2dec/decoder.rs +++ b/src/libcore/num/flt2dec/decoder.rs @@ -67,7 +67,7 @@ impl DecodableFloat for f64 { /// Returns a sign (true when negative) and `FullDecoded` value /// from given floating point number. pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { - let (mant, exp, sign) = v.integer_decode2(); + let (mant, exp, sign) = v.integer_decode(); let even = (mant & 1) == 0; let decoded = match v.classify() { FpCategory::Nan => FullDecoded::Nan, @@ -81,7 +81,7 @@ pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { exp: exp, inclusive: even }) } FpCategory::Normal => { - let minnorm = ::min_pos_norm_value().integer_decode2(); + let minnorm = ::min_pos_norm_value().integer_decode(); if mant == minnorm.0 { // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp) // where maxmant = minnormmant * 2 - 1 diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1e25d45bfbb5..5c4a43fbd110 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2453,49 +2453,6 @@ pub enum FpCategory { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] pub trait Float: Sized { - /// Returns the NaN value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn nan() -> Self; - /// Returns the infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn infinity() -> Self; - /// Returns the negative infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_infinity() -> Self; - /// Returns -0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_zero() -> Self; - /// Returns 0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn zero() -> Self; - /// Returns 1.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn one() -> Self; - /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; @@ -2513,14 +2470,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; - /// Returns the mantissa, exponent and sign as integers, respectively. - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn integer_decode(self) -> (u64, i16, i8); - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[stable(feature = "core", since = "1.6.0")] diff --git a/src/libcore/tests/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs index 1a3533317dae..2b0afc402027 100644 --- a/src/libcore/tests/num/dec2flt/rawfp.rs +++ b/src/libcore/tests/num/dec2flt/rawfp.rs @@ -8,23 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::f32; use std::f64; -use std::mem; use core::num::diy_float::Fp; use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal}; +use core::num::dec2flt::rawfp::RawFloat; fn integer_decode(f: f64) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(f) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) + RawFloat::integer_decode(f) } #[test] @@ -152,3 +143,35 @@ fn next_float_monotonic() { } assert!(x > 0.5); } + +#[test] +fn test_f32_integer_decode() { + assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); + assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); + assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + assert_eq!(0f32.integer_decode(), (0, -150, 1)); + assert_eq!((-0f32).integer_decode(), (0, -150, -1)); + assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); + assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (12582912, 105)); +} + +#[test] +fn test_f64_integer_decode() { + assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); + assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); + assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); + assert_eq!(0f64.integer_decode(), (0, -1075, 1)); + assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); + assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); + assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (6755399441055744, 972)); +} diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 316e6841c4fe..4ed0afcfc235 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -22,8 +22,6 @@ use core::num; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; @@ -73,8 +71,6 @@ mod cmath { pub fn atan2f(a: c_float, b: c_float) -> c_float; pub fn atanf(n: c_float) -> c_float; pub fn coshf(n: c_float) -> c_float; - pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; - pub fn ldexpf(x: c_float, n: c_int) -> c_float; pub fn sinhf(n: c_float) -> c_float; pub fn tanf(n: c_float) -> c_float; pub fn tanhf(n: c_float) -> c_float; @@ -111,20 +107,6 @@ mod cmath { f64::cosh(n as f64) as c_float } - #[inline] - #[allow(deprecated)] - pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { - let (a, b) = f64::frexp(x as f64); - *value = b as c_int; - a as c_float - } - - #[inline] - #[allow(deprecated)] - pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { - f64::ldexp(x as f64, n as isize) as c_float - } - #[inline] pub unsafe fn sinhf(n: c_float) -> c_float { f64::sinh(n as f64) as c_float @@ -244,40 +226,6 @@ impl f32 { #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let num = 2.0f32; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f32; - /// let mantissa_f = mantissa as f32; - /// let exponent_f = num.powf(exponent as f32); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { - num::Float::integer_decode(self) - } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -712,89 +660,6 @@ impl f32 { #[inline] pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f32, exp: isize) -> f32 { - unsafe { cmath::ldexpf(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 4.0f32; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f32 - 3.0).abs(); - /// - /// assert!(abs_difference_0 <= f32::EPSILON); - /// assert!(abs_difference_1 <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f32, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexpf(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 1.0f32; - /// - /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs(); - /// - /// assert!(abs_diff <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f32) -> f32 { - unsafe { cmath::nextafterf(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1462,23 +1327,6 @@ mod tests { assert_eq!(1e-38f32.classify(), Fp::Subnormal); } - #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); - assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); - assert_eq!(0f32.integer_decode(), (0, -150, 1)); - assert_eq!((-0f32).integer_decode(), (0, -150, -1)); - assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (12582912, 105)); - } - #[test] fn test_floor() { assert_approx_eq!(1.0f32.floor(), 1.0f32); @@ -1790,58 +1638,6 @@ mod tests { assert_eq!(neg_inf.to_radians(), neg_inf); } - #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-12); - assert_eq!(f32::ldexp(1f32, -123), f1); - assert_eq!(f32::ldexp(1f32, -111), f2); - assert_eq!(f32::ldexp(1.75f32, -12), f3); - - assert_eq!(f32::ldexp(0f32, -123), 0f32); - assert_eq!(f32::ldexp(-0f32, -123), -0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(f32::ldexp(inf, -123), inf); - assert_eq!(f32::ldexp(neg_inf, -123), neg_inf); - assert!(f32::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f32, -122)); - assert_eq!((x2, exp2), (0.5f32, -110)); - assert_eq!((x3, exp3), (0.875f32, -122)); - assert_eq!(f32::ldexp(x1, exp1), f1); - assert_eq!(f32::ldexp(x2, exp2), f2); - assert_eq!(f32::ldexp(x3, exp3), f3); - - assert_eq!(0f32.frexp(), (0f32, 0)); - assert_eq!((-0f32).frexp(), (-0f32, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - #[test] fn test_asinh() { assert_eq!(0.0f32.asinh(), 0.0f32); diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index be55cb80c92f..82e3903eec7b 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -22,8 +22,6 @@ use core::num; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; #[stable(feature = "rust1", since = "1.0.0")] @@ -188,36 +186,6 @@ impl f64 { #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let num = 2.0f64; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f64; - /// let mantissa_f = mantissa as f64; - /// let exponent_f = num.powf(exponent as f64); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -606,84 +574,6 @@ impl f64 { #[inline] pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f64, exp: isize) -> f64 { - unsafe { cmath::ldexp(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 4.0_f64; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f64 - 3.0).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_1 < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f64, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexp(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 1.0f64; - /// - /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs(); - /// - /// assert!(abs_diff < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f64) -> f64 { - unsafe { cmath::nextafter(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1353,23 +1243,6 @@ mod tests { assert_eq!(1e-308f64.classify(), Fp::Subnormal); } - #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); - assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); - assert_eq!(0f64.integer_decode(), (0, -1075, 1)); - assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); - assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (6755399441055744, 972)); - } - #[test] fn test_floor() { assert_approx_eq!(1.0f64.floor(), 1.0f64); @@ -1681,58 +1554,6 @@ mod tests { assert_eq!(neg_inf.to_radians(), neg_inf); } - #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-12); - assert_eq!(f64::ldexp(1f64, -123), f1); - assert_eq!(f64::ldexp(1f64, -111), f2); - assert_eq!(f64::ldexp(1.75f64, -12), f3); - - assert_eq!(f64::ldexp(0f64, -123), 0f64); - assert_eq!(f64::ldexp(-0f64, -123), -0f64); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(f64::ldexp(inf, -123), inf); - assert_eq!(f64::ldexp(neg_inf, -123), neg_inf); - assert!(f64::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f64, -122)); - assert_eq!((x2, exp2), (0.5f64, -110)); - assert_eq!((x3, exp3), (0.875f64, -122)); - assert_eq!(f64::ldexp(x1, exp1), f1); - assert_eq!(f64::ldexp(x2, exp2), f2); - assert_eq!(f64::ldexp(x3, exp3), f3); - - assert_eq!(0f64.frexp(), (0f64, 0)); - assert_eq!((-0f64).frexp(), (-0f64, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - #[test] fn test_asinh() { assert_eq!(0.0f64.asinh(), 0.0f64); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 28b94107c425..70225da5f335 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -262,7 +262,6 @@ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] -#![feature(float_extras)] #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] diff --git a/src/test/run-pass/union/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs index 4eb66268ab8e..7a0b4c6aaca4 100644 --- a/src/test/run-pass/union/union-transmute.rs +++ b/src/test/run-pass/union/union-transmute.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core_float)] -#![feature(float_extras)] #![feature(untagged_unions)] extern crate core; -use core::num::Float; +use core::f32; union U { a: (u8, u8), @@ -33,8 +31,8 @@ fn main() { assert_eq!(u.a, (2, 2)); let mut w = W { a: 0b0_11111111_00000000000000000000000 }; - assert_eq!(w.b, f32::infinity()); - w.b = f32::neg_infinity(); + assert_eq!(w.b, f32::INFINITY); + w.b = f32::NEG_INFINITY; assert_eq!(w.a, 0b1_11111111_00000000000000000000000); } } From c49d0906da09972f447013834dcf891ec887151b Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 21 Apr 2017 10:32:13 +0200 Subject: [PATCH 619/905] Specify behavior of `write_all` for `ErrorKind::Interrupted` errors Also spell out that read and write operations should be retried on `ErrorKind::Interrupted` errors. Fixes #38494. --- src/libstd/io/mod.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index cd096c115ba5..39a0602eab82 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -466,6 +466,9 @@ pub trait Read { /// variant will be returned. If an error is returned then it must be /// guaranteed that no bytes were read. /// + /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the read + /// operation should be retried if there is nothing else to do. + /// /// # Examples /// /// [`File`][file]s implement `Read`: @@ -481,7 +484,7 @@ pub trait Read { /// let mut f = File::open("foo.txt")?; /// let mut buffer = [0; 10]; /// - /// // read 10 bytes + /// // read up to 10 bytes /// f.read(&mut buffer[..])?; /// # Ok(()) /// # } @@ -885,6 +888,9 @@ pub trait Write { /// It is **not** considered an error if the entire buffer could not be /// written to this writer. /// + /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the + /// write operation should be retried if there is nothing else to do. + /// /// # Examples /// /// ``` @@ -894,6 +900,7 @@ pub trait Write { /// # fn foo() -> std::io::Result<()> { /// let mut buffer = File::create("foo.txt")?; /// + /// // Writes some prefix of the byte string, not necessarily all of it. /// buffer.write(b"some bytes")?; /// # Ok(()) /// # } @@ -929,14 +936,17 @@ pub trait Write { /// Attempts to write an entire buffer into this write. /// - /// This method will continuously call `write` while there is more data to - /// write. This method will not return until the entire buffer has been - /// successfully written or an error occurs. The first error generated from - /// this method will be returned. + /// This method will continuously call `write` until there is no more data + /// to be written or an error of non-`ErrorKind::Interrupted` kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of `ErrorKind::Interrupted` kind generated from this method will be + /// returned. /// /// # Errors /// - /// This function will return the first error that `write` returns. + /// This function will return the first error of + /// non-`ErrorKind::Interrupted` kind that `write` returns. /// /// # Examples /// From d360091e799b14a81ced54a67bc67ae0b0bc3afe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Nov 2016 22:54:31 +0100 Subject: [PATCH 620/905] Add suggestion for & coercions --- src/librustc_typeck/check/demand.rs | 77 ++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index e922c7447ff8..2933f35abfb6 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -11,8 +11,9 @@ use check::FnCtxt; use rustc::ty::Ty; -use rustc::infer::{InferOk}; +use rustc::infer::{InferOk, TypeOrigin}; use rustc::traits::ObligationCause; +use rustc::ty; use syntax::ast; use syntax_pos::{self, Span}; @@ -80,12 +81,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); - let mode = probe::Mode::MethodCall; - let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, - mode, - expected, - checked_ty, - ast::DUMMY_NODE_ID); + let suggestions = if let Some(suggestions) = self.check_ref(expr, + checked_ty, + expected) { + suggestions + } else { + let mode = probe::Mode::MethodCall; + self.probe_for_return_type(syntax_pos::DUMMY_SP, + mode, + expected, + checked_ty, + ast::DUMMY_NODE_ID) + } let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); if suggestions.len() > 0 { err.help(&format!("here are some functions which \ @@ -140,4 +147,60 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false, } } + + /// This function is used to determine potential "simple" improvements or users' errors and + /// provide them useful help. For example: + /// + /// ``` + /// fn some_fn(s: &str) {} + /// + /// let x = "hey!".to_owned(); + /// some_fn(x); // error + /// ``` + /// + /// No need to find every potential function which could make a coercion to transform a + /// `String` into a `&str` since a `&` would do the trick! + /// + /// In addition of this check, it also checks between references mutability state. If the + /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with + /// `&mut`!". + fn check_ref(&self, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected: Ty<'tcx>) + -> Option { + match (&expected.sty, &checked_ty.sty) { + (&ty::TyRef(_, _), &ty::TyRef(_, _)) => None, + (&ty::TyRef(_, mutability), _) => { + // Check if it can work when put into a ref. For example: + // + // ``` + // fn bar(x: &mut i32) {} + // + // let x = 0u32; + // bar(&x); // error, expected &mut + // ``` + let ref_ty = match mutability.mutbl { + hir::Mutability::MutMutable => self.tcx.mk_mut_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + }; + if self.try_coerce(expr, ref_ty, expected).is_ok() { + if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { + return Some(format!("try with `{}{}`", + match mutability.mutbl { + hir::Mutability::MutMutable => "&mut ", + hir::Mutability::MutImmutable => "&", + }, + &src)); + } + } + None + } + _ => None, + } + } } From 8fe3a9a8f123fa759d35000bfbfb623167a76409 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Nov 2016 22:55:58 +0100 Subject: [PATCH 621/905] Update tests --- src/test/compile-fail/coercion-slice.rs | 1 - src/test/compile-fail/cross-borrow-trait.rs | 2 ++ src/test/compile-fail/dst-bad-coercions.rs | 2 ++ src/test/compile-fail/issue-13058.rs | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index 6b468ff96620..7c5a4e0c3c6f 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -14,6 +14,5 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| found type `[{integer}; 1]` //~| expected &[i32], found array of 1 elements } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index e5afccb9cf39..ee67a30fa1c3 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -20,4 +20,6 @@ pub fn main() { let _y: &Trait = x; //~ ERROR mismatched types //~| expected type `&Trait` //~| found type `std::boxed::Box` + //~| expected &Trait, found box + //~| ERROR the trait bound `Box: Trait` is not satisfied } diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index 883c16b08958..ff2e2d619a5e 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -23,11 +23,13 @@ pub fn main() { let x: *const S = &S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types + //~^ ERROR the trait bound `*const S: T` is not satisfied // Test that we cannot convert from *-ptr to &S and &T (mut version) let x: *mut S = &mut S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types + //~^ ERROR the trait bound `*mut S: T` is not satisfied // Test that we cannot convert an immutable ptr to a mutable one using *-ptrs let x: &mut T = &S; //~ ERROR mismatched types diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs index 408c6d411de9..ed1634441498 100644 --- a/src/test/compile-fail/issue-13058.rs +++ b/src/test/compile-fail/issue-13058.rs @@ -35,4 +35,5 @@ fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool fn main() { check((3, 5)); //~^ ERROR mismatched types +//~| HELP try with `&(3, 5)` } From 89bd3f39cadbbe0b361303ddbda2796ea7f39bb9 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 18 Apr 2017 11:02:21 +0300 Subject: [PATCH 622/905] Update #[no_core] users with the "freeze" lang item. --- src/bootstrap/compile.rs | 1 + src/rtstartup/rsbegin.rs | 7 +++++-- src/test/run-make/simd-ffi/simd.rs | 6 +++++- src/test/run-make/target-specs/foo.rs | 6 +++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index bddd570a13d2..cd87b27d4f1a 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -151,6 +151,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st if !up_to_date(src_file, dst_file) { let mut cmd = Command::new(&compiler_path); build.run(cmd.env("RUSTC_BOOTSTRAP", "1") + .arg("--cfg").arg(format!("stage{}", compiler.stage)) .arg("--target").arg(target) .arg("--emit=obj") .arg("--out-dir").arg(dst_dir) diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 65c85697ce72..e8b92aab1da1 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -22,7 +22,7 @@ // object (usually called `crtX.o), which then invokes initialization callbacks // of other runtime components (registered via yet another special image section). -#![feature(no_core, lang_items)] +#![feature(no_core, lang_items, optin_builtin_traits)] #![crate_type="rlib"] #![no_core] #![allow(non_camel_case_types)] @@ -31,9 +31,12 @@ trait Sized {} #[lang = "sync"] trait Sync {} +impl Sync for .. {} #[lang = "copy"] trait Copy {} -impl Sync for T {} +#[cfg_attr(not(stage0), lang = "freeze")] +trait Freeze {} +impl Freeze for .. {} #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index 49fec6f3619e..8ab8f4715755 100644 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -12,7 +12,7 @@ #![crate_type = "lib"] // we can compile to a variety of platforms, because we don't need // cross-compiled standard libraries. -#![feature(no_core)] +#![feature(no_core, optin_builtin_traits)] #![no_core] #![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items)] @@ -78,3 +78,7 @@ pub trait Copy { } pub mod marker { pub use Copy; } + +#[lang = "freeze"] +trait Freeze {} +impl Freeze for .. {} diff --git a/src/test/run-make/target-specs/foo.rs b/src/test/run-make/target-specs/foo.rs index 15b569772321..af24c3b460b2 100644 --- a/src/test/run-make/target-specs/foo.rs +++ b/src/test/run-make/target-specs/foo.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, no_core)] +#![feature(lang_items, no_core, optin_builtin_traits)] #![no_core] #[lang="copy"] @@ -17,6 +17,10 @@ trait Copy { } #[lang="sized"] trait Sized { } +#[lang = "freeze"] +trait Freeze {} +impl Freeze for .. {} + #[lang="start"] fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 } From 7d3284ebc18f3d4087d71352421726b2240a7c20 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 10 Nov 2016 00:25:45 +0100 Subject: [PATCH 623/905] Create a new method to run coercion inside probe --- src/librustc_typeck/check/coercion.rs | 30 ++++++++++++++-- src/librustc_typeck/check/demand.rs | 38 ++++++++++----------- src/test/compile-fail/cross-borrow-trait.rs | 4 +-- src/test/compile-fail/dst-bad-coercions.rs | 2 -- src/test/compile-fail/issue-11374.rs | 2 +- 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c6a1f6cfc0d7..a769b55c520b 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -65,8 +65,8 @@ use check::{Diverges, FnCtxt}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace}; -use rustc::infer::type_variable::TypeVariableOrigin; -use rustc::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc::infer::type_variable::{TypeVariableOrigin}; +use rustc::traits::{self, /*FulfillmentContext,*/ ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty, ClosureSubsts}; @@ -78,6 +78,7 @@ use errors::DiagnosticBuilder; use syntax::abi; use syntax::feature_gate; use syntax::ptr::P; +use syntax_pos; use std::collections::VecDeque; use std::ops::Deref; @@ -722,6 +723,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok(target) } + /// Same as `try_coerce()`, but without side-effects. + pub fn can_coerce(&self, + expr_ty: Ty<'tcx>, + target: Ty<'tcx>) + -> bool { + // FIXME: This is a hack, but coercion wasn't made to be run + // in a probe. It leaks obligations and bounds and things out + // into the environment. For now we just save-and-restore the + // fulfillment context. + /*let saved_fulfillment_cx = + mem::replace( + &mut *self.inh.fulfillment_cx.borrow_mut(), + FulfillmentContext::new());*/ + let source = self.resolve_type_vars_with_obligations(expr_ty); + debug!("coercion::can({:?} -> {:?})", source, target); + + let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); + let coerce = Coerce::new(self, cause); + let result = self.probe(|_| coerce.coerce::(&[], source, target)).is_ok(); + + //*self.inh.fulfillment_cx.borrow_mut() = saved_fulfillment_cx; + + result + } + /// Given some expressions, their known unified type and another expression, /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 2933f35abfb6..0fd98232becf 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,16 +10,14 @@ use check::FnCtxt; -use rustc::ty::Ty; -use rustc::infer::{InferOk, TypeOrigin}; +use rustc::infer::InferOk; use rustc::traits::ObligationCause; -use rustc::ty; use syntax::ast; use syntax_pos::{self, Span}; use rustc::hir; use rustc::hir::def::Def; -use rustc::ty::{self, AssociatedItem}; +use rustc::ty::{self, Ty, AssociatedItem}; use errors::DiagnosticBuilder; use super::method::probe; @@ -81,24 +79,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); - let suggestions = if let Some(suggestions) = self.check_ref(expr, - checked_ty, - expected) { - suggestions + let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); + if let Some(suggestion) = self.check_ref(expr, + checked_ty, + expected) { + err.help(&suggestion); } else { let mode = probe::Mode::MethodCall; - self.probe_for_return_type(syntax_pos::DUMMY_SP, - mode, - expected, - checked_ty, - ast::DUMMY_NODE_ID) + let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, + mode, + expected, + checked_ty, + ast::DUMMY_NODE_ID); + if suggestions.len() > 0 { + err.help(&format!("here are some functions which \ + might fulfill your needs:\n - {}", + self.get_best_match(&suggestions).join("\n"))); + } } - let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - if suggestions.len() > 0 { - err.help(&format!("here are some functions which \ - might fulfill your needs:\n{}", - self.get_best_match(&suggestions).join("\n"))); - }; err.emit(); } } @@ -188,7 +186,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_region(ty::ReStatic), checked_ty), }; - if self.try_coerce(expr, ref_ty, expected).is_ok() { + if self.can_coerce(ref_ty, expected) { if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { return Some(format!("try with `{}{}`", match mutability.mutbl { diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index ee67a30fa1c3..847a82c08265 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -17,9 +17,7 @@ impl Trait for Foo {} pub fn main() { let x: Box = Box::new(Foo); - let _y: &Trait = x; //~ ERROR mismatched types + let _y: &Trait = x; //~ ERROR E0308 //~| expected type `&Trait` //~| found type `std::boxed::Box` - //~| expected &Trait, found box - //~| ERROR the trait bound `Box: Trait` is not satisfied } diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index ff2e2d619a5e..883c16b08958 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -23,13 +23,11 @@ pub fn main() { let x: *const S = &S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types - //~^ ERROR the trait bound `*const S: T` is not satisfied // Test that we cannot convert from *-ptr to &S and &T (mut version) let x: *mut S = &mut S; let y: &S = x; //~ ERROR mismatched types let y: &T = x; //~ ERROR mismatched types - //~^ ERROR the trait bound `*mut S: T` is not satisfied // Test that we cannot convert an immutable ptr to a mutable one using *-ptrs let x: &mut T = &S; //~ ERROR mismatched types diff --git a/src/test/compile-fail/issue-11374.rs b/src/test/compile-fail/issue-11374.rs index f78786a2889d..1e444a6bebf9 100644 --- a/src/test/compile-fail/issue-11374.rs +++ b/src/test/compile-fail/issue-11374.rs @@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> { fn main() { let mut c = for_stdin(); let mut v = Vec::new(); - c.read_to(v); //~ ERROR mismatched types + c.read_to(v); //~ ERROR E0308 } From e038f58105cc1769a9c7991981822d01ebffe277 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 5 Apr 2017 01:12:53 +0300 Subject: [PATCH 624/905] syntax: Support parentheses around trait bounds --- src/libsyntax/parse/parser.rs | 29 ++++++++++++++++--- .../parse-fail/trait-object-bad-parens.rs | 20 +++++++++++++ .../trait-object-lifetime-parens.rs | 18 ++++++++++++ .../parse-fail/trait-object-trait-parens.rs | 21 ++++++++++++++ 4 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/test/parse-fail/trait-object-bad-parens.rs create mode 100644 src/test/parse-fail/trait-object-lifetime-parens.rs create mode 100644 src/test/parse-fail/trait-object-trait-parens.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0cdb09a842f4..1232411d1ecf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -152,6 +152,7 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) enum PrevTokenKind { DocComment, Comma, + Plus, Interpolated, Eof, Other, @@ -1061,6 +1062,7 @@ impl<'a> Parser<'a> { self.prev_token_kind = match self.token { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, + token::BinOp(token::Plus) => PrevTokenKind::Plus, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, _ => PrevTokenKind::Other, @@ -1354,20 +1356,29 @@ impl<'a> Parser<'a> { break; } } + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; self.expect(&token::CloseDelim(token::Paren))?; if ts.len() == 1 && !last_comma { let ty = ts.into_iter().nth(0).unwrap().unwrap(); + let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus); match ty.node { - // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318). - TyKind::Path(None, ref path) - if allow_plus && self.token == token::BinOp(token::Plus) => { + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { self.bump(); // `+` let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; bounds.append(&mut self.parse_ty_param_bounds()?); TyKind::TraitObject(bounds) } + TyKind::TraitObject(ref bounds) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + self.bump(); // `+` + let mut bounds = bounds.clone(); + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } + // `(TYPE)` _ => TyKind::Paren(P(ty)) } } else { @@ -4070,10 +4081,12 @@ impl<'a> Parser<'a> { // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) - // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) + // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + // TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { + let has_parens = self.eat(&token::OpenDelim(token::Paren)); let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.check_lifetime() { if let Some(question_span) = question { @@ -4081,6 +4094,11 @@ impl<'a> Parser<'a> { "`?` may only modify trait bounds, not lifetime bounds"); } bounds.push(RegionTyParamBound(self.expect_lifetime())); + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + self.span_err(self.prev_span, + "parenthesized lifetime bounds are not supported"); + } } else if self.check_keyword(keywords::For) || self.check_path() { let lo = self.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; @@ -4092,6 +4110,9 @@ impl<'a> Parser<'a> { TraitBoundModifier::None }; bounds.push(TraitTyParamBound(poly_trait, modifier)); + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } } else { break } diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs new file mode 100644 index 000000000000..a44c0c3f32fe --- /dev/null +++ b/src/test/parse-fail/trait-object-bad-parens.rs @@ -0,0 +1,20 @@ +// 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: -Z parse-only -Z continue-parse-after-error + +fn main() { + let _: Box<((Copy)) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `((Copy))` + let _: Box<(Copy + Copy) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)` + let _: Box<(Copy +) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)` +} diff --git a/src/test/parse-fail/trait-object-lifetime-parens.rs b/src/test/parse-fail/trait-object-lifetime-parens.rs new file mode 100644 index 000000000000..6be62d966eb9 --- /dev/null +++ b/src/test/parse-fail/trait-object-lifetime-parens.rs @@ -0,0 +1,18 @@ +// 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: -Z parse-only -Z continue-parse-after-error + +fn f() {} //~ ERROR parenthesized lifetime bounds are not supported + +fn main() { + let _: Box; //~ ERROR parenthesized lifetime bounds are not supported + let _: Box<('a) + Copy>; //~ ERROR expected type, found `'a` +} diff --git a/src/test/parse-fail/trait-object-trait-parens.rs b/src/test/parse-fail/trait-object-trait-parens.rs new file mode 100644 index 000000000000..dc44f4f3fb13 --- /dev/null +++ b/src/test/parse-fail/trait-object-trait-parens.rs @@ -0,0 +1,21 @@ +// 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: -Z parse-only + +fn f Trait<'a>)>() {} + +fn main() { + let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; + let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; + let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; +} + +FAIL //~ ERROR From 6e75def7dba6ee28660b8479f0ede72986c299f7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 21 Apr 2017 00:19:06 +0300 Subject: [PATCH 625/905] Fix issue with single question mark or paren --- src/doc/grammar.md | 5 +- src/libsyntax/parse/parser.rs | 51 ++++++++++--------- .../parse-fail/bound-single-question-mark.rs | 13 +++++ 3 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 src/test/parse-fail/bound-single-question-mark.rs diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 3fbf9f06d99f..12daa24e857f 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -781,10 +781,11 @@ never_type : "!" ; ### Type parameter bounds ```antlr +bound-list := bound | bound '+' bound-list '+' ? bound := ty_bound | lt_bound lt_bound := lifetime -ty_bound := [?] [ for ] simple_path -bound-list := bound | bound '+' bound-list '+' ? +ty_bound := ty_bound_noparen | (ty_bound_noparen) +ty_bound_noparen := [?] [ for ] simple_path ``` ### Self types diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1232411d1ecf..79ae1d629152 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4086,32 +4086,37 @@ impl<'a> Parser<'a> { fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { - let has_parens = self.eat(&token::OpenDelim(token::Paren)); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.check_lifetime() { - if let Some(question_span) = question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } - bounds.push(RegionTyParamBound(self.expect_lifetime())); - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - self.span_err(self.prev_span, - "parenthesized lifetime bounds are not supported"); - } - } else if self.check_keyword(keywords::For) || self.check_path() { - let lo = self.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe + let is_bound_start = self.check_path() || self.check_lifetime() || + self.check(&token::Question) || + self.check_keyword(keywords::For) || + self.check(&token::OpenDelim(token::Paren)); + if is_bound_start { + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + if let Some(question_span) = question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); + } + bounds.push(RegionTyParamBound(self.expect_lifetime())); } else { - TraitBoundModifier::None - }; - bounds.push(TraitTyParamBound(poly_trait, modifier)); + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(TraitTyParamBound(poly_trait, modifier)); + } if has_parens { self.expect(&token::CloseDelim(token::Paren))?; + if let Some(&RegionTyParamBound(..)) = bounds.last() { + self.span_err(self.prev_span, + "parenthesized lifetime bounds are not supported"); + } } } else { break diff --git a/src/test/parse-fail/bound-single-question-mark.rs b/src/test/parse-fail/bound-single-question-mark.rs new file mode 100644 index 000000000000..9dde5268c087 --- /dev/null +++ b/src/test/parse-fail/bound-single-question-mark.rs @@ -0,0 +1,13 @@ +// 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: -Z parse-only + +fn f() {} //~ ERROR expected identifier, found `>` From 8838cd10f2374ed51c4b219c1f070d0c29af3b86 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 21 Apr 2017 21:32:11 +0300 Subject: [PATCH 626/905] Move parse_remaining_bounds into a separate function --- src/libsyntax/parse/parser.rs | 41 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 79ae1d629152..1baf0d1b54ce 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1365,18 +1365,15 @@ impl<'a> Parser<'a> { match ty.node { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, ref path) if maybe_bounds => { - self.bump(); // `+` - let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? } TyKind::TraitObject(ref bounds) if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - self.bump(); // `+` - let mut bounds = bounds.clone(); - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + let path = match bounds[0] { + TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(), + _ => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true)? } // `(TYPE)` _ => TyKind::Paren(P(ty)) @@ -1429,11 +1426,8 @@ impl<'a> Parser<'a> { // Just a type path or bound list (trait object type) starting with a trait. // `Type` // `Trait1 + Trait2 + 'a` - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + if allow_plus && self.check(&token::BinOp(token::Plus)) { + self.parse_remaining_bounds(Vec::new(), path, lo, true)? } else { TyKind::Path(None, path) } @@ -1451,12 +1445,8 @@ impl<'a> Parser<'a> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - bounds.append(&mut self.parse_ty_param_bounds()?) - } - TyKind::TraitObject(bounds) + let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); + self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(keywords::Impl) { // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). @@ -1479,6 +1469,17 @@ impl<'a> Parser<'a> { Ok(P(ty)) } + fn parse_remaining_bounds(&mut self, lifetime_defs: Vec, path: ast::Path, + lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; + if parse_plus { + self.bump(); // `+` + bounds.append(&mut self.parse_ty_param_bounds()?); + } + Ok(TyKind::TraitObject(bounds)) + } + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. if !allow_plus || self.token != token::BinOp(token::Plus) { From 1a5c01ccfcf2b1826bc0560fd073bf26fac361e5 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Fri, 21 Apr 2017 11:40:16 -0700 Subject: [PATCH 627/905] Update cargo. Bump our associated cargo to pick up the RUSTC_WRAPPER feature for use with build caches. --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index c416fb60b11e..8326a3683a90 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 From 7ce1eb77c77ce0a56efc7d11ac8003e6a95208d0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Apr 2017 13:28:31 +0200 Subject: [PATCH 628/905] Update ui test --- src/librustc_typeck/check/coercion.rs | 23 ++++------------------ src/librustc_typeck/check/demand.rs | 2 +- src/test/ui/span/coerce-suggestions.rs | 1 - src/test/ui/span/coerce-suggestions.stderr | 14 +++++-------- 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a769b55c520b..d21b5f739bd7 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -65,8 +65,8 @@ use check::{Diverges, FnCtxt}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace}; -use rustc::infer::type_variable::{TypeVariableOrigin}; -use rustc::traits::{self, /*FulfillmentContext,*/ ObligationCause, ObligationCauseCode}; +use rustc::infer::type_variable::TypeVariableOrigin; +use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty, ClosureSubsts}; @@ -724,28 +724,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Same as `try_coerce()`, but without side-effects. - pub fn can_coerce(&self, - expr_ty: Ty<'tcx>, - target: Ty<'tcx>) - -> bool { - // FIXME: This is a hack, but coercion wasn't made to be run - // in a probe. It leaks obligations and bounds and things out - // into the environment. For now we just save-and-restore the - // fulfillment context. - /*let saved_fulfillment_cx = - mem::replace( - &mut *self.inh.fulfillment_cx.borrow_mut(), - FulfillmentContext::new());*/ + pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::can({:?} -> {:?})", source, target); let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - let result = self.probe(|_| coerce.coerce::(&[], source, target)).is_ok(); - - //*self.inh.fulfillment_cx.borrow_mut() = saved_fulfillment_cx; - - result + self.probe(|_| coerce.coerce::(&[], source, target)).is_ok() } /// Given some expressions, their known unified type and another expression, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 0fd98232becf..4cc3f2dacdfe 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -93,7 +93,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ast::DUMMY_NODE_ID); if suggestions.len() > 0 { err.help(&format!("here are some functions which \ - might fulfill your needs:\n - {}", + might fulfill your needs:\n{}", self.get_best_match(&suggestions).join("\n"))); } } diff --git a/src/test/ui/span/coerce-suggestions.rs b/src/test/ui/span/coerce-suggestions.rs index 3177e858ff4f..bc3122bf71c0 100644 --- a/src/test/ui/span/coerce-suggestions.rs +++ b/src/test/ui/span/coerce-suggestions.rs @@ -32,7 +32,6 @@ fn main() { //~| NOTE types differ in mutability //~| NOTE expected type `&mut std::string::String` //~| NOTE found type `&std::string::String` - //~| HELP try with `&mut y` test2(&y); //~^ ERROR E0308 //~| NOTE types differ in mutability diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 6a70b8ff851d..220b2f471da9 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -18,11 +18,7 @@ error[E0308]: mismatched types | = note: expected type `&str` found type `std::string::String` - = help: here are some functions which might fulfill your needs: - - .as_str() - - .trim() - - .trim_left() - - .trim_right() + = help: try with `&String::new()` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:30:10 @@ -34,18 +30,18 @@ error[E0308]: mismatched types found type `&std::string::String` error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:36:11 + --> $DIR/coerce-suggestions.rs:35:11 | -36 | test2(&y); +35 | test2(&y); | ^^ types differ in mutability | = note: expected type `&mut i32` found type `&std::string::String` error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:42:9 + --> $DIR/coerce-suggestions.rs:41:9 | -42 | f = box f; +41 | f = box f; | ^^^^^ cyclic type of infinite size | = note: expected type `_` From 8289e5a73e411f994d14c0b80ed97d7a6aa3c4cc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Apr 2017 10:51:22 -0400 Subject: [PATCH 629/905] introduce `is_foreign_item` query This may seem like overkill, but it's exactly what we want/need for incremental compilation I think. In particular, while generating code for some codegen unit X, we can wind up querying about any number of external items, and we only want to be forced to rebuild X is some of those changed from a foreign item to otherwise. Factoring this into a query means we would re-run only if some `false` became `true` (or vice versa). --- src/librustc/dep_graph/dep_node.rs | 3 +++ src/librustc/ty/maps.rs | 3 +++ src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_trans/callee.rs | 22 ++++++++++++---------- src/librustc_typeck/collect.rs | 11 +++++++++++ 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index fd9750dbfe3f..224e9751e73d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -88,6 +88,7 @@ pub enum DepNode { // predicates for an item wind up in `ItemSignature`). AssociatedItems(D), ItemSignature(D), + IsForeignItem(D), TypeParamPredicates((D, D)), SizedConstraint(D), AdtDestructor(D), @@ -171,6 +172,7 @@ impl DepNode { TransCrateItem, AssociatedItems, ItemSignature, + IsForeignItem, AssociatedItemDefIds, InherentImpls, TypeckTables, @@ -221,6 +223,7 @@ impl DepNode { TransInlinedItem(ref d) => op(d).map(TransInlinedItem), AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), + IsForeignItem(ref d) => op(d).map(IsForeignItem), TypeParamPredicates((ref item, ref param)) => { Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param))))) } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index e9eb5e97582b..1cb3de3fa01e 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -380,6 +380,9 @@ define_maps! { <'tcx> pub adt_destructor: AdtDestructor(DefId) -> Option, pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>, + /// True if this is a foreign item (i.e., linked via `extern { ... }`). + pub is_foreign_item: IsForeignItem(DefId) -> bool, + /// Maps from def-id of a type or region parameter to its /// (inferred) variance. pub variances: ItemSignature(DefId) -> Rc>, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3239dfb937b5..3cff063a8f56 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -111,6 +111,7 @@ provide! { <'tcx> tcx, def_id, cdata closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } + is_foreign_item => { cdata.is_foreign_item(def_id.index) } } impl CrateStore for cstore::CStore { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index aefee51191ac..d4d9015d08fc 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -14,18 +14,18 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -use llvm::{self, ValueRef}; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; use attributes; use common::{self, CrateContext}; -use monomorphize; use consts; use declare; -use monomorphize::Instance; +use llvm::{self, ValueRef}; +use monomorphize::{self, Instance}; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, TypeFoldable}; +use rustc::ty::subst::Substs; +use syntax_pos::DUMMY_SP; use trans_item::TransItem; use type_of; -use rustc::ty::TypeFoldable; /// Translates a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -102,15 +102,17 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let attrs = instance.def.attrs(ccx.tcx()); attributes::from_fn_attrs(ccx, &attrs, llfn); - let is_local_def = ccx.shared().translation_items().borrow() - .contains(&TransItem::Fn(instance)); - if is_local_def { - // FIXME(eddyb) Doubt all extern fn should allow unwinding. + // 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 !ty::queries::is_foreign_item::get(tcx, DUMMY_SP, instance.def_id()) { attributes::unwind(llfn, true); unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); } } + if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(instance.def_id()) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index af0ef279e4f0..855d156f6f26 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -99,6 +99,7 @@ pub fn provide(providers: &mut Providers) { trait_def, adt_def, impl_trait_ref, + is_foreign_item, ..*providers }; } @@ -1530,3 +1531,13 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs, fty) } + +fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + match tcx.hir.get_if_local(def_id) { + Some(hir_map::NodeForeignItem(..)) => true, + Some(_) => false, + _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id) + } +} From 4c31750cd9afc64b0b7c9157b7044eb3e5703054 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Apr 2017 13:27:39 -0400 Subject: [PATCH 630/905] remove `translation_items` from `SharedCrateContext` If we are going to hash `SharedCrateContext`, we don't want a list of things that pertain to **every CGU** in there. --- src/librustc_trans/base.rs | 21 ++++++++++----------- src/librustc_trans/context.rs | 13 +------------ 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index cb8022efedb8..1420f52819b3 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -802,6 +802,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols<'a, 'tcx>(sess: &Session, scx: &SharedCrateContext<'a, 'tcx>, + translation_items: &FxHashSet>, llvm_modules: &[ModuleLlvm], symbol_map: &SymbolMap<'tcx>, exported_symbols: &ExportedSymbols) { @@ -854,7 +855,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let mut locally_defined_symbols = FxHashSet(); let mut linkage_fixed_explicitly = FxHashSet(); - for trans_item in scx.translation_items().borrow().iter() { + for trans_item in translation_items { let symbol_name = symbol_map.get_or_compute(scx, *trans_item); if trans_item.explicit_linkage(tcx).is_some() { linkage_fixed_explicitly.insert(symbol_name.clone()); @@ -1109,7 +1110,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Run the translation item collector and partition the collected items into // codegen units. - let (codegen_units, symbol_map) = collect_and_partition_translation_items(&shared_ccx); + let (translation_items, codegen_units, symbol_map) = + collect_and_partition_translation_items(&shared_ccx); let symbol_map = Rc::new(symbol_map); @@ -1289,6 +1291,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(shared_ccx.sess().time_passes(), "internalize symbols", || { internalize_symbols(sess, &shared_ccx, + &translation_items, &llvm_modules, &symbol_map, &exported_symbols); @@ -1517,7 +1520,9 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) - -> (Vec>, SymbolMap<'tcx>) { + -> (FxHashSet>, + Vec>, + SymbolMap<'tcx>) { let time_passes = scx.sess().time_passes(); let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items { @@ -1563,13 +1568,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() || scx.tcx().sess.opts.debugging_opts.incremental.is_some()); - { - let mut ccx_map = scx.translation_items().borrow_mut(); - - for trans_item in items.iter().cloned() { - ccx_map.insert(trans_item); - } - } + let translation_items: FxHashSet> = items.iter().cloned().collect(); if scx.sess().opts.debugging_opts.print_trans_items.is_some() { let mut item_to_cgus = FxHashMap(); @@ -1624,5 +1623,5 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a } } - (codegen_units, symbol_map) + (translation_items, codegen_units, symbol_map) } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1d1921bf7b96..5fd36ecb767c 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -21,7 +21,6 @@ use declare; use monomorphize::Instance; use partitioning::CodegenUnit; -use trans_item::TransItem; use type_::Type; use rustc_data_structures::base_n; use rustc::ty::subst::Substs; @@ -31,7 +30,7 @@ use session::config::NoDebugInfo; use session::Session; use session::config; use symbol_map::SymbolMap; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -87,7 +86,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { use_dll_storage_attrs: bool, - translation_items: RefCell>>, trait_cache: RefCell>>, project_cache: RefCell>>, } @@ -385,7 +383,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { tcx: tcx, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, - translation_items: RefCell::new(FxHashSet()), trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } @@ -430,10 +427,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } - - pub fn translation_items(&self) -> &RefCell>> { - &self.translation_items - } } impl<'tcx> LocalCrateContext<'tcx> { @@ -720,10 +713,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &*self.local().symbol_map } - pub fn translation_items(&self) -> &RefCell>> { - &self.shared.translation_items - } - /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { From 39a58c38a0b9ac9e822a1732f073abe8ddf65cfb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Apr 2017 15:10:53 -0400 Subject: [PATCH 631/905] introduce the rather simpler symbol-cache in place of symbol-map The symbol map is not good for incremental: it has inputs from every fn in existence, and it will change if anything changes. One could imagine cheating with the symbol-map and exempting it from the usual dependency tracking, since the results are fully deterministic. Instead, I opted to just add a per-CGU cache, on the premise that recomputing some symbol names is not going to be so very expensive. --- src/librustc_trans/base.rs | 17 ++++++------ src/librustc_trans/callee.rs | 3 +-- src/librustc_trans/consts.rs | 9 +++---- src/librustc_trans/context.rs | 39 ++++++++++++++------------- src/librustc_trans/lib.rs | 1 + src/librustc_trans/partitioning.rs | 39 ++++++++++++++------------- src/librustc_trans/symbol_cache.rs | 42 ++++++++++++++++++++++++++++++ src/librustc_trans/trans_item.rs | 3 +-- 8 files changed, 95 insertions(+), 58 deletions(-) create mode 100644 src/librustc_trans/symbol_cache.rs diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1420f52819b3..c6fd87b68a0a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -65,6 +65,7 @@ use meth; use mir; use monomorphize::{self, Instance}; use partitioning::{self, PartitioningStrategy, CodegenUnit}; +use symbol_cache::SymbolCache; use symbol_map::SymbolMap; use symbol_names_test; use trans_item::{TransItem, DefPathBasedNames}; @@ -75,7 +76,6 @@ use util::nodemap::{NodeSet, FxHashMap, FxHashSet}; use libc::c_uint; use std::ffi::{CStr, CString}; -use std::rc::Rc; use std::str; use std::i32; use syntax_pos::Span; @@ -1113,8 +1113,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (translation_items, codegen_units, symbol_map) = collect_and_partition_translation_items(&shared_ccx); - let symbol_map = Rc::new(symbol_map); - let mut all_stats = Stats::default(); let modules: Vec = codegen_units .into_iter() @@ -1123,7 +1121,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (stats, module) = tcx.dep_graph.with_task(dep_node, AssertDepGraphSafe(&shared_ccx), - AssertDepGraphSafe((cgu, symbol_map.clone())), + AssertDepGraphSafe(cgu), module_translation); all_stats.extend(stats); module @@ -1132,16 +1130,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn module_translation<'a, 'tcx>( scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, - args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc>)>) + args: AssertDepGraphSafe>) -> (Stats, ModuleTranslation) { // FIXME(#40304): We ought to be using the id as a key and some queries, I think. let AssertDepGraphSafe(scx) = scx; - let AssertDepGraphSafe((cgu, symbol_map)) = args; + let AssertDepGraphSafe(cgu) = args; let cgu_name = String::from(cgu.name()); let cgu_id = cgu.work_product_id(); - let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_map); + let symbol_cache = SymbolCache::new(scx); + let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_cache); // Check whether there is a previous work-product we can // re-use. Not only must the file exist, and the inputs not @@ -1176,11 +1175,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone()); + let lcx = LocalCrateContext::new(scx, cgu, &symbol_cache); let module = { let ccx = CrateContext::new(scx, &lcx); let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(ccx.tcx(), &symbol_map); + .items_in_deterministic_order(ccx.tcx(), &symbol_cache); for &(trans_item, linkage) in &trans_items { trans_item.predefine(&ccx, linkage); } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index d4d9015d08fc..264e26e4594c 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -51,8 +51,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let sym = ccx.symbol_map().get_or_compute(ccx.shared(), - TransItem::Fn(instance)); + let sym = ccx.symbol_cache().get(TransItem::Fn(instance)); debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); // This is subtle and surprising, but sometimes we have to bitcast diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index eb3ac309be16..0105111fe6cc 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -93,20 +93,19 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { hir_map::NodeItem(&hir::Item { ref attrs, span, node: hir::ItemStatic(..), .. }) => { - let sym = ccx.symbol_map() - .get(TransItem::Static(id)) - .expect("Local statics should always be in the SymbolMap"); + let sym = ccx.symbol_cache() + .get(TransItem::Static(id)); let defined_in_current_codegen_unit = ccx.codegen_unit() .items() .contains_key(&TransItem::Static(id)); assert!(!defined_in_current_codegen_unit); - if declare::get_declared_value(ccx, sym).is_some() { + if declare::get_declared_value(ccx, &sym[..]).is_some() { span_bug!(span, "trans: Conflicting symbol names for static?"); } - let g = declare::define_global(ccx, sym, llty).unwrap(); + let g = declare::define_global(ccx, &sym[..], llty).unwrap(); (g, attrs) } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 5fd36ecb767c..3769c8b026d3 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -29,7 +29,7 @@ use rustc::ty::layout::{LayoutTyper, TyLayout}; use session::config::NoDebugInfo; use session::Session; use session::config; -use symbol_map::SymbolMap; +use symbol_cache::SymbolCache; use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; @@ -37,7 +37,6 @@ use std::cell::{Cell, RefCell}; use std::marker::PhantomData; use std::ptr; use std::iter; -use std::rc::Rc; use std::str; use syntax::ast; use syntax::symbol::InternedString; @@ -94,7 +93,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { /// 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 `LocalCrateContext` are tied to that `ContextRef`. -pub struct LocalCrateContext<'tcx> { +pub struct LocalCrateContext<'a, 'tcx: 'a> { llmod: ModuleRef, llcx: ContextRef, stats: Stats, @@ -166,10 +165,10 @@ pub struct LocalCrateContext<'tcx> { /// Depth of the current type-of computation - used to bail out type_of_depth: Cell, - symbol_map: Rc>, - /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, + + symbol_cache: &'a SymbolCache<'a, 'tcx>, } // Implement DepTrackingMapConfig for `trait_cache` @@ -227,12 +226,12 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans. pub struct CrateContext<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccx: &'a LocalCrateContext<'tcx>, + local_ccx: &'a LocalCrateContext<'a, 'tcx>, } impl<'a, 'tcx> CrateContext<'a, 'tcx> { pub fn new(shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccx: &'a LocalCrateContext<'tcx>) + local_ccx: &'a LocalCrateContext<'a, 'tcx>) -> Self { CrateContext { shared, local_ccx } } @@ -429,11 +428,11 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { } } -impl<'tcx> LocalCrateContext<'tcx> { - pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: CodegenUnit<'tcx>, - symbol_map: Rc>) - -> LocalCrateContext<'tcx> { +impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { + pub fn new(shared: &SharedCrateContext<'a, 'tcx>, + codegen_unit: CodegenUnit<'tcx>, + symbol_cache: &'a SymbolCache<'a, 'tcx>) + -> LocalCrateContext<'a, 'tcx> { unsafe { // Append ".rs" to LLVM module identifier. // @@ -487,8 +486,8 @@ impl<'tcx> LocalCrateContext<'tcx> { rust_try_fn: Cell::new(None), intrinsics: RefCell::new(FxHashMap()), type_of_depth: Cell::new(0), - symbol_map: symbol_map, local_gen_sym_counter: Cell::new(0), + symbol_cache: symbol_cache, }; let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { @@ -522,9 +521,9 @@ impl<'tcx> LocalCrateContext<'tcx> { /// This is used in the `LocalCrateContext` constructor to allow calling /// functions that expect a complete `CrateContext`, even before the local /// portion is fully initialized and attached to the `SharedCrateContext`. - fn dummy_ccx<'a>(shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccxs: &'a [LocalCrateContext<'tcx>]) - -> CrateContext<'a, 'tcx> { + fn dummy_ccx(shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccxs: &'a [LocalCrateContext<'a, 'tcx>]) + -> CrateContext<'a, 'tcx> { assert!(local_ccxs.len() == 1); CrateContext { shared: shared, @@ -542,7 +541,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared } - fn local(&self) -> &'b LocalCrateContext<'tcx> { + fn local(&self) -> &'b LocalCrateContext<'b, 'tcx> { self.local_ccx } @@ -709,8 +708,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared.use_dll_storage_attrs() } - pub fn symbol_map(&self) -> &SymbolMap<'tcx> { - &*self.local().symbol_map + pub fn symbol_cache(&self) -> &'b SymbolCache<'b, 'tcx> { + self.local().symbol_cache } /// Given the def-id of some item that has no type parameters, make @@ -856,7 +855,7 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { } } -pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); +pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'a, 'tcx>); impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> { fn drop(&mut self) { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index be214a0f6143..117d8568500b 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -124,6 +124,7 @@ mod meth; mod mir; mod monomorphize; mod partitioning; +mod symbol_cache; mod symbol_map; mod symbol_names_test; mod trans_item; diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 4973181202ee..cc207b58fbc5 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -116,7 +116,7 @@ use rustc_incremental::IchHasher; use std::cmp::Ordering; use std::hash::Hash; use std::sync::Arc; -use symbol_map::SymbolMap; +use symbol_cache::SymbolCache; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; use trans_item::{TransItem, InstantiationMode}; @@ -174,14 +174,15 @@ impl<'tcx> CodegenUnit<'tcx> { DepNode::WorkProduct(self.work_product_id()) } - pub fn compute_symbol_name_hash(&self, - scx: &SharedCrateContext, - symbol_map: &SymbolMap) -> u64 { + pub fn compute_symbol_name_hash<'a>(&self, + scx: &SharedCrateContext<'a, 'tcx>, + symbol_cache: &SymbolCache<'a, 'tcx>) + -> u64 { let mut state = IchHasher::new(); let exported_symbols = scx.exported_symbols(); - let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_map); + let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_cache); for (item, _) in all_items { - let symbol_name = symbol_map.get(item).unwrap(); + let symbol_name = symbol_cache.get(item); symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); let exported = match item { @@ -201,10 +202,10 @@ impl<'tcx> CodegenUnit<'tcx> { state.finish().to_smaller_hash() } - pub fn items_in_deterministic_order(&self, - tcx: TyCtxt, - symbol_map: &SymbolMap) - -> Vec<(TransItem<'tcx>, llvm::Linkage)> { + pub fn items_in_deterministic_order<'a>(&self, + tcx: TyCtxt, + symbol_cache: &SymbolCache<'a, 'tcx>) + -> Vec<(TransItem<'tcx>, llvm::Linkage)> { let mut items: Vec<(TransItem<'tcx>, llvm::Linkage)> = self.items.iter().map(|(item, linkage)| (*item, *linkage)).collect(); @@ -216,9 +217,9 @@ impl<'tcx> CodegenUnit<'tcx> { match (node_id1, node_id2) { (None, None) => { - let symbol_name1 = symbol_map.get(trans_item1).unwrap(); - let symbol_name2 = symbol_map.get(trans_item2).unwrap(); - symbol_name1.cmp(symbol_name2) + let symbol_name1 = symbol_cache.get(trans_item1); + let symbol_name2 = symbol_cache.get(trans_item2); + symbol_name1.cmp(&symbol_name2) } // In the following two cases we can avoid looking up the symbol (None, Some(_)) => Ordering::Less, @@ -230,9 +231,9 @@ impl<'tcx> CodegenUnit<'tcx> { return ordering; } - let symbol_name1 = symbol_map.get(trans_item1).unwrap(); - let symbol_name2 = symbol_map.get(trans_item2).unwrap(); - symbol_name1.cmp(symbol_name2) + let symbol_name1 = symbol_cache.get(trans_item1); + let symbol_name2 = symbol_cache.get(trans_item2); + symbol_name1.cmp(&symbol_name2) } } }); @@ -536,14 +537,12 @@ fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, { if cfg!(debug_assertions) { debug!("{}", label); + let symbol_cache = SymbolCache::new(scx); for cgu in cgus { - let symbol_map = SymbolMap::build(scx, cgu.items - .iter() - .map(|(&trans_item, _)| trans_item)); debug!("CodegenUnit {}:", cgu.name); for (trans_item, linkage) in &cgu.items { - let symbol_name = symbol_map.get_or_compute(scx, *trans_item); + let symbol_name = symbol_cache.get(*trans_item); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) .unwrap_or(""); diff --git a/src/librustc_trans/symbol_cache.rs b/src/librustc_trans/symbol_cache.rs new file mode 100644 index 000000000000..bf96bf9542ab --- /dev/null +++ b/src/librustc_trans/symbol_cache.rs @@ -0,0 +1,42 @@ +// 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 context::SharedCrateContext; +use std::cell::RefCell; +use std::rc::Rc; +use trans_item::TransItem; +use util::nodemap::FxHashMap; + +// In the SymbolCache we collect the symbol names of translation items +// and cache them for later reference. This is just a performance +// optimization and the cache is populated lazilly; symbol names of +// translation items are deterministic and fully defined by the item. +// Thus they can always be recomputed if needed. + +pub struct SymbolCache<'a, 'tcx: 'a> { + scx: &'a SharedCrateContext<'a, 'tcx>, + index: RefCell, Rc>>, +} + +impl<'a, 'tcx> SymbolCache<'a, 'tcx> { + pub fn new(scx: &'a SharedCrateContext<'a, 'tcx>) -> Self { + SymbolCache { + scx, + index: RefCell::new(FxHashMap()) + } + } + + pub fn get(&self, trans_item: TransItem<'tcx>) -> Rc { + let mut index = self.index.borrow_mut(); + index.entry(trans_item) + .or_insert_with(|| Rc::new(trans_item.compute_symbol_name(self.scx))) + .clone() + } +} diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 4d908f3c94fa..3a4f73e0eb3b 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -118,8 +118,7 @@ impl<'a, 'tcx> TransItem<'tcx> { self.to_raw_string(), ccx.codegen_unit().name()); - let symbol_name = ccx.symbol_map() - .get_or_compute(ccx.shared(), *self); + let symbol_name = ccx.symbol_cache().get(*self); debug!("symbol {}", &symbol_name); From c446cb086bfaf098730b310d386853adf7f5240a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Apr 2017 15:30:06 -0400 Subject: [PATCH 632/905] just take `tcx` where we can The more we can things dependent on just tcx, the easier it will be to make queries etc later on. --- src/librustc_trans/back/symbol_export.rs | 12 +++--- src/librustc_trans/back/symbol_names.rs | 53 +++++++++++------------- src/librustc_trans/base.rs | 4 +- src/librustc_trans/consts.rs | 4 +- src/librustc_trans/partitioning.rs | 14 +++---- src/librustc_trans/symbol_cache.rs | 10 ++--- src/librustc_trans/symbol_map.rs | 5 ++- src/librustc_trans/symbol_names_test.rs | 13 +++--- src/librustc_trans/trans_item.rs | 13 +++--- 9 files changed, 62 insertions(+), 66 deletions(-) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 5d6717272fdf..221c52141a83 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -53,7 +53,7 @@ impl ExportedSymbols { scx.tcx().hir.local_def_id(node_id) }) .map(|def_id| { - let name = symbol_for_def_id(scx, def_id, symbol_map); + let name = symbol_for_def_id(scx.tcx(), def_id, symbol_map); let export_level = export_level(scx, def_id); debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); (name, export_level) @@ -108,7 +108,7 @@ impl ExportedSymbols { .exported_symbols(cnum) .iter() .map(|&def_id| { - let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx); + let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx.tcx()); let export_level = if special_runtime_crate { // We can probably do better here by just ensuring that // it has hidden visibility rather than public @@ -214,21 +214,21 @@ pub fn is_below_threshold(level: SymbolExportLevel, } } -fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn symbol_for_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, symbol_map: &SymbolMap<'tcx>) -> String { // Just try to look things up in the symbol map. If nothing's there, we // recompute. - if let Some(node_id) = scx.tcx().hir.as_local_node_id(def_id) { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { return sym.to_owned(); } } - let instance = Instance::mono(scx.tcx(), def_id); + let instance = Instance::mono(tcx, def_id); symbol_map.get(TransItem::Fn(instance)) .map(str::to_owned) - .unwrap_or_else(|| symbol_name(instance, scx)) + .unwrap_or_else(|| symbol_name(instance, tcx)) } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 8facbd6cc278..61b95f098adb 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -97,13 +97,12 @@ //! 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 common::SharedCrateContext; use monomorphize::Instance; use rustc::middle::weak_lang_items; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; -use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::fold::TypeVisitor; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; @@ -113,7 +112,7 @@ use rustc::util::common::record_time; use syntax::attr; use syntax::symbol::{Symbol, InternedString}; -fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the DefId of the item this name is for def_id: Option, @@ -130,8 +129,6 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, -> String { debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); - let tcx = scx.tcx(); - let mut hasher = ty::util::TypeIdHasher::::new(tcx); record_time(&tcx.sess.perf_stats.symbol_hash_time, || { @@ -157,8 +154,8 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // in case the same instances is emitted in two crates of the same // project. if substs.types().next().is_some() { - hasher.hash(scx.tcx().crate_name.as_str()); - hasher.hash(scx.sess().local_crate_disambiguator().as_str()); + hasher.hash(tcx.crate_name.as_str()); + hasher.hash(tcx.sess.local_crate_disambiguator().as_str()); } } }); @@ -168,37 +165,37 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, - scx: &SharedCrateContext<'a, 'tcx>) -> String { + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { let def_id = instance.def_id(); let substs = instance.substs; debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs); - let node_id = scx.tcx().hir.as_local_node_id(def_id); + let node_id = tcx.hir.as_local_node_id(def_id); if let Some(id) = node_id { - if scx.sess().plugin_registrar_fn.get() == Some(id) { + if tcx.sess.plugin_registrar_fn.get() == Some(id) { let idx = def_id.index; - let disambiguator = scx.sess().local_crate_disambiguator(); - return scx.sess().generate_plugin_registrar_symbol(disambiguator, idx); + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_plugin_registrar_symbol(disambiguator, idx); } - if scx.sess().derive_registrar_fn.get() == Some(id) { + if tcx.sess.derive_registrar_fn.get() == Some(id) { let idx = def_id.index; - let disambiguator = scx.sess().local_crate_disambiguator(); - return scx.sess().generate_derive_registrar_symbol(disambiguator, idx); + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); } } // FIXME(eddyb) Precompute a custom symbol name based on attributes. - let attrs = scx.tcx().get_attrs(def_id); + let attrs = tcx.get_attrs(def_id); let is_foreign = if let Some(id) = node_id { - match scx.tcx().hir.get(id) { + match tcx.hir.get(id) { hir_map::NodeForeignItem(_) => true, _ => false } } else { - scx.sess().cstore.is_foreign_item(def_id) + tcx.sess.cstore.is_foreign_item(def_id) }; if let Some(name) = weak_lang_items::link_name(&attrs) { @@ -210,17 +207,17 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, return name.to_string(); } // Don't mangle foreign items. - return scx.tcx().item_name(def_id).as_str().to_string(); + return tcx.item_name(def_id).as_str().to_string(); } - if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) { + if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) { // Use provided name return name.to_string(); } if attr::contains_name(&attrs, "no_mangle") { // Don't mangle - return scx.tcx().item_name(def_id).as_str().to_string(); + return tcx.item_name(def_id).as_str().to_string(); } // We want to compute the "type" of this item. Unfortunately, some @@ -230,11 +227,11 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, let mut ty_def_id = def_id; let instance_ty; loop { - let key = scx.tcx().def_key(ty_def_id); + let key = tcx.def_key(ty_def_id); match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = scx.tcx().item_type(ty_def_id); + instance_ty = tcx.item_type(ty_def_id); break; } _ => { @@ -251,16 +248,16 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = scx.tcx().erase_regions(&instance_ty); + let instance_ty = tcx.erase_regions(&instance_ty); - let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs)); + let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); let mut buffer = SymbolPathBuffer { names: Vec::new() }; item_path::with_forced_absolute_paths(|| { - scx.tcx().push_item_path(&mut buffer, def_id); + tcx.push_item_path(&mut buffer, def_id); }); mangle(buffer.names.into_iter(), &hash) @@ -281,11 +278,11 @@ impl ItemPathBuffer for SymbolPathBuffer { } } -pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, t: Ty<'tcx>, prefix: &str) -> String { - let hash = get_symbol_hash(scx, None, t, None); + let hash = get_symbol_hash(tcx, None, t, None); let path = [Symbol::intern(prefix).as_str()]; mangle(path.iter().cloned(), &hash) } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c6fd87b68a0a..8ee5627e6893 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1139,7 +1139,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let cgu_name = String::from(cgu.name()); let cgu_id = cgu.work_product_id(); - let symbol_cache = SymbolCache::new(scx); + let symbol_cache = SymbolCache::new(scx.tcx()); let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_cache); // Check whether there is a previous work-product we can @@ -1239,7 +1239,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert_module_sources::assert_module_sources(tcx, &modules); - symbol_names_test::report_symbol_names(&shared_ccx); + symbol_names_test::report_symbol_names(tcx); if shared_ccx.sess().trans_stats() { println!("--- trans stats ---"); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 0105111fe6cc..3d614cfbcbf3 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -113,7 +113,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { hir_map::NodeForeignItem(&hir::ForeignItem { ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let sym = symbol_names::symbol_name(instance, ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.tcx()); let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -173,7 +173,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { g } else { - let sym = symbol_names::symbol_name(instance, ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.tcx()); // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index cc207b58fbc5..6b89d11cfb68 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -177,7 +177,7 @@ impl<'tcx> CodegenUnit<'tcx> { pub fn compute_symbol_name_hash<'a>(&self, scx: &SharedCrateContext<'a, 'tcx>, symbol_cache: &SymbolCache<'a, 'tcx>) - -> u64 { + -> u64 { let mut state = IchHasher::new(); let exported_symbols = scx.exported_symbols(); let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_cache); @@ -272,14 +272,14 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let mut initial_partitioning = place_root_translation_items(scx, trans_items); - debug_dump(scx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); // If the partitioning should produce a fixed count of codegen units, merge // until that count is reached. if let PartitioningStrategy::FixedUnitCount(count) = strategy { merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str()); - debug_dump(scx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } // In the next step, we use the inlining map to determine which addtional @@ -289,7 +289,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let post_inlining = place_inlined_translation_items(initial_partitioning, inlining_map); - debug_dump(scx, "POST INLINING:", post_inlining.0.iter()); + debug_dump(tcx, "POST INLINING:", post_inlining.0.iter()); // Finally, sort by codegen unit name, so that we get deterministic results let mut result = post_inlining.0; @@ -529,7 +529,7 @@ fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString Symbol::intern(&format!("{}{}{}", crate_name, NUMBERED_CODEGEN_UNIT_MARKER, index)).as_str() } -fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, +fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, label: &str, cgus: I) where I: Iterator>, @@ -537,7 +537,7 @@ fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, { if cfg!(debug_assertions) { debug!("{}", label); - let symbol_cache = SymbolCache::new(scx); + let symbol_cache = SymbolCache::new(tcx); for cgu in cgus { debug!("CodegenUnit {}:", cgu.name); @@ -548,7 +548,7 @@ fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, .unwrap_or(""); debug!(" - {} [{:?}] [{}]", - trans_item.to_string(scx.tcx()), + trans_item.to_string(tcx), linkage, symbol_hash); } diff --git a/src/librustc_trans/symbol_cache.rs b/src/librustc_trans/symbol_cache.rs index bf96bf9542ab..a838c3a2c4cb 100644 --- a/src/librustc_trans/symbol_cache.rs +++ b/src/librustc_trans/symbol_cache.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use context::SharedCrateContext; use std::cell::RefCell; use std::rc::Rc; +use rustc::ty::TyCtxt; use trans_item::TransItem; use util::nodemap::FxHashMap; @@ -21,14 +21,14 @@ use util::nodemap::FxHashMap; // Thus they can always be recomputed if needed. pub struct SymbolCache<'a, 'tcx: 'a> { - scx: &'a SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, index: RefCell, Rc>>, } impl<'a, 'tcx> SymbolCache<'a, 'tcx> { - pub fn new(scx: &'a SharedCrateContext<'a, 'tcx>) -> Self { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { SymbolCache { - scx, + tcx: tcx, index: RefCell::new(FxHashMap()) } } @@ -36,7 +36,7 @@ impl<'a, 'tcx> SymbolCache<'a, 'tcx> { pub fn get(&self, trans_item: TransItem<'tcx>) -> Rc { let mut index = self.index.borrow_mut(); index.entry(trans_item) - .or_insert_with(|| Rc::new(trans_item.compute_symbol_name(self.scx))) + .or_insert_with(|| Rc::new(trans_item.compute_symbol_name(self.tcx))) .clone() } } diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 36c3981e3a6f..9d3e62888a2d 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -34,8 +34,9 @@ impl<'tcx> SymbolMap<'tcx> { where I: Iterator> { // Check for duplicate symbol names + let tcx = scx.tcx(); let mut symbols: Vec<_> = trans_items.map(|trans_item| { - (trans_item, trans_item.compute_symbol_name(scx)) + (trans_item, trans_item.compute_symbol_name(tcx)) }).collect(); (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{ @@ -124,7 +125,7 @@ impl<'tcx> SymbolMap<'tcx> { if let Some(sym) = self.get(trans_item) { Cow::from(sym) } else { - Cow::from(trans_item.compute_symbol_name(scx)) + Cow::from(trans_item.compute_symbol_name(scx.tcx())) } } } diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index fe551b06b3d9..fd817cb94c1c 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -17,43 +17,42 @@ use back::symbol_names; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::ty::TyCtxt; use syntax::ast; -use common::SharedCrateContext; use monomorphize::Instance; const SYMBOL_NAME: &'static str = "rustc_symbol_name"; const ITEM_PATH: &'static str = "rustc_item_path"; -pub fn report_symbol_names(scx: &SharedCrateContext) { +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. - let tcx = scx.tcx(); if !tcx.sess.features.borrow().rustc_attrs { return; } let _ignore = tcx.dep_graph.in_ignore(); - let mut visitor = SymbolNamesTest { scx: scx }; + let mut visitor = SymbolNamesTest { tcx: tcx }; // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct SymbolNamesTest<'a, 'tcx:'a> { - scx: &'a SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, } impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { fn process_attrs(&mut self, node_id: ast::NodeId) { - let tcx = self.scx.tcx(); + 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 = symbol_names::symbol_name(instance, self.scx); + let name = symbol_names::symbol_name(instance, self.tcx); 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); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 3a4f73e0eb3b..de35d1b7dd4c 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -18,7 +18,7 @@ use asm; use attributes; use base; use consts; -use context::{CrateContext, SharedCrateContext}; +use context::CrateContext; use common; use declare; use llvm; @@ -184,16 +184,15 @@ impl<'a, 'tcx> TransItem<'tcx> { ccx.instances().borrow_mut().insert(instance, lldecl); } - pub fn compute_symbol_name(&self, - scx: &SharedCrateContext<'a, 'tcx>) -> String { + pub fn compute_symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { match *self { - TransItem::Fn(instance) => symbol_names::symbol_name(instance, scx), + TransItem::Fn(instance) => symbol_names::symbol_name(instance, tcx), TransItem::Static(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); - symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) + let def_id = tcx.hir.local_def_id(node_id); + symbol_names::symbol_name(Instance::mono(tcx, def_id), tcx) } TransItem::GlobalAsm(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); + let def_id = tcx.hir.local_def_id(node_id); format!("global_asm_{:?}", def_id) } } From 264f237f98a8c1e0fc1e25b7d75a7711bd427e84 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Apr 2017 15:33:52 -0400 Subject: [PATCH 633/905] make `reachable_set` ref-counted Once it is computed, no need to deep clone the set. --- src/librustc/middle/reachable.rs | 7 ++++--- src/librustc/ty/maps.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc_driver/driver.rs | 2 +- src/librustc_trans/base.rs | 6 +++--- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 63455f94cedf..be4ec16cd63a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -18,6 +18,7 @@ use hir::map as hir_map; use hir::def::Def; use hir::def_id::{DefId, CrateNum}; +use std::rc::Rc; use ty::{self, TyCtxt}; use ty::maps::Providers; use middle::privacy; @@ -362,11 +363,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { +pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) } -fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet { +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc { debug_assert!(crate_num == LOCAL_CRATE); let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); @@ -411,7 +412,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> reachable_context.propagate(); // Return the set of reachable symbols. - reachable_context.reachable_symbols + Rc::new(reachable_context.reachable_symbols) } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 1cb3de3fa01e..648923d6f04e 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -451,7 +451,7 @@ define_maps! { <'tcx> /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, - pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet, + pub reachable_set: reachability_dep_node(CrateNum) -> Rc, pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5c0889976c21..2507941aacaf 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -114,7 +114,7 @@ mod sty; #[derive(Clone)] pub struct CrateAnalysis { pub access_levels: Rc, - pub reachable: NodeSet, + pub reachable: Rc, pub name: String, pub glob_map: Option, } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 7632b40ab4f9..6c0f6049e502 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -810,7 +810,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, defs: resolver.definitions, analysis: ty::CrateAnalysis { access_levels: Rc::new(AccessLevels::default()), - reachable: NodeSet(), + reachable: Rc::new(NodeSet()), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, }, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 8ee5627e6893..ba119bd9ef06 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1012,8 +1012,8 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { - reachable.into_iter().filter(|&id| { +pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { + reachable.iter().cloned().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -1065,7 +1065,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.hir.krate(); let ty::CrateAnalysis { reachable, .. } = analysis; - let exported_symbols = find_exported_symbols(tcx, reachable); + let exported_symbols = find_exported_symbols(tcx, &reachable); let check_overflow = tcx.sess.overflow_checks(); From e48a759f51ae23f817339eda1485fa3afe6d8d04 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 17 Apr 2017 09:08:34 -0400 Subject: [PATCH 634/905] sort `provide` --- src/librustc_driver/driver.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6c0f6049e502..ac4e2bd5c103 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -889,9 +889,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let index = stability::Index::new(&hir_map); let mut local_providers = ty::maps::Providers::default(); - mir::provide(&mut local_providers); - rustc_privacy::provide(&mut local_providers); borrowck::provide(&mut local_providers); + mir::provide(&mut local_providers); + reachable::provide(&mut local_providers); + rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); reachable::provide(&mut local_providers); From f4c183b742cf08c5d06d50b4fbada3561722af81 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 17 Apr 2017 12:35:53 -0400 Subject: [PATCH 635/905] move the trans trait caches into tcx Arguably these could become custom queries, but I chose not to do that because the relationship of queries and trait system is not yet fleshed out enough. For now it seems fine to have them be `DepTrackingMap` using the memoize pattern. --- src/librustc/traits/mod.rs | 1 + src/librustc/traits/trans/mod.rs | 73 ++++++++++++++++++++++++++++++ src/librustc/ty/context.rs | 3 ++ src/librustc_trans/context.rs | 66 +-------------------------- src/librustc_trans/monomorphize.rs | 24 +++++----- 5 files changed, 89 insertions(+), 78 deletions(-) create mode 100644 src/librustc/traits/trans/mod.rs diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 0ff379b30ffd..18f0a749f701 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -55,6 +55,7 @@ mod object_safety; mod select; mod specialize; mod structural_impls; +pub mod trans; mod util; /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs new file mode 100644 index 000000000000..8517f573e602 --- /dev/null +++ b/src/librustc/traits/trans/mod.rs @@ -0,0 +1,73 @@ +use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use hir::def_id::DefId; +use std::cell::RefCell; +use std::marker::PhantomData; +use traits::Vtable; +use ty::{self, Ty}; + +/// Specializes caches used in trans -- in particular, they assume all +/// types are fully monomorphized and that free regions can be erased. +pub struct TransTraitCaches<'tcx> { + pub trait_cache: RefCell>>, + pub project_cache: RefCell>>, +} + +impl<'tcx> TransTraitCaches<'tcx> { + pub fn new(graph: DepGraph) -> Self { + TransTraitCaches { + trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())), + project_cache: RefCell::new(DepTrackingMap::new(graph)), + } + } +} + +// Implement DepTrackingMapConfig for `trait_cache` +pub struct TraitSelectionCache<'tcx> { + data: PhantomData<&'tcx ()> +} + +impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { + type Key = ty::PolyTraitRef<'tcx>; + type Value = Vtable<'tcx, ()>; + fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { + key.to_poly_trait_predicate().dep_node() + } +} + +// # 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_node(key: &Self::Key) -> DepNode { + // Ideally, we'd just put `key` into the dep-node, but we + // can't put full types in there. So just collect up all the + // def-ids of structs/enums as well as any traits that we + // project out of. It doesn't matter so much what we do here, + // except that if we are too coarse, we'll create overly + // coarse edges between impls and the trans. For example, if + // we just used the def-id of things we are projecting out of, + // then the key for `::T` and `::T` would both share a dep-node + // (`TraitSelect(SomeTrait)`), and hence the impls for both + // `Foo` and `Bar` would be considered inputs. So a change to + // `Bar` would affect things that just normalized `Foo`. + // Anyway, this heuristic is not ideal, but better than + // nothing. + let def_ids: Vec = + key.walk() + .filter_map(|t| match t.sty { + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, + }) + .collect(); + + DepNode::ProjectionCache { def_ids: def_ids } + } +} + diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a41629258716..e836bf23a5a8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -407,6 +407,8 @@ pub struct GlobalCtxt<'tcx> { pub specializes_cache: RefCell, + pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>, + pub dep_graph: DepGraph, /// Common types, pre-interned for your convenience. @@ -689,6 +691,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { providers[LOCAL_CRATE] = local_providers; tls::enter_global(GlobalCtxt { sess: s, + trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()), specializes_cache: RefCell::new(traits::SpecializesCache::new()), global_arenas: arenas, global_interners: interners, diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 3769c8b026d3..ceb292c13c12 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use rustc::dep_graph::{DepGraph, DepGraphSafe}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::traits; @@ -34,7 +34,6 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; -use std::marker::PhantomData; use std::ptr; use std::iter; use std::str; @@ -84,9 +83,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { check_overflow: bool, use_dll_storage_attrs: bool, - - trait_cache: RefCell>>, - project_cache: RefCell>>, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -171,56 +167,6 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> { symbol_cache: &'a SymbolCache<'a, 'tcx>, } -// Implement DepTrackingMapConfig for `trait_cache` -pub struct TraitSelectionCache<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { - type Key = ty::PolyTraitRef<'tcx>; - type Value = traits::Vtable<'tcx, ()>; - fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { - key.to_poly_trait_predicate().dep_node() - } -} - -// # 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_node(key: &Self::Key) -> DepNode { - // Ideally, we'd just put `key` into the dep-node, but we - // can't put full types in there. So just collect up all the - // def-ids of structs/enums as well as any traits that we - // project out of. It doesn't matter so much what we do here, - // except that if we are too coarse, we'll create overly - // coarse edges between impls and the trans. For example, if - // we just used the def-id of things we are projecting out of, - // then the key for `::T` and `::T` would both share a dep-node - // (`TraitSelect(SomeTrait)`), and hence the impls for both - // `Foo` and `Bar` would be considered inputs. So a change to - // `Bar` would affect things that just normalized `Foo`. - // Anyway, this heuristic is not ideal, but better than - // nothing. - let def_ids: Vec = - key.walk() - .filter_map(|t| match t.sty { - ty::TyAdt(adt_def, _) => Some(adt_def.did), - ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), - _ => None, - }) - .collect(); - - DepNode::ProjectionCache { def_ids: def_ids } - } -} - /// A CrateContext value binds together one LocalCrateContext with the /// SharedCrateContext. It exists as a convenience wrapper, so we don't have to /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans. @@ -382,8 +328,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { tcx: tcx, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, - trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), - project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } } @@ -403,14 +347,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.exported_symbols } - pub fn trait_cache(&self) -> &RefCell>> { - &self.trait_cache - } - - pub fn project_cache(&self) -> &RefCell>> { - &self.project_cache - } - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 382ca8ef0100..33626e7c39fc 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -117,7 +117,7 @@ fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Remove any references to regions; this helps improve caching. let trait_ref = tcx.erase_regions(&trait_ref); - scx.trait_cache().memoize(trait_ref, || { + tcx.trans_trait_caches.trait_cache.memoize(trait_ref, || { debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", trait_ref, trait_ref.def_id()); @@ -307,7 +307,7 @@ pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(tcx, param_substs); let substituted = scx.tcx().erase_regions(&substituted); - AssociatedTypeNormalizer::new(scx).fold(&substituted) + AssociatedTypeNormalizer::new(tcx).fold(&substituted) } /// Returns the normalized type of a struct field @@ -319,15 +319,13 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } -struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> { - shared: &'a SharedCrateContext<'b, 'gcx>, +struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'gcx>, } -impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> { - fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self { - AssociatedTypeNormalizer { - shared: shared, - } +impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { + fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { + AssociatedTypeNormalizer { tcx } } fn fold>(&mut self, value: &T) -> T { @@ -339,18 +337,18 @@ impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> { } } -impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> { +impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { - self.shared.tcx() + self.tcx } fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { if !ty.has_projection_types() { ty } else { - self.shared.project_cache().memoize(ty, || { + self.tcx.trans_trait_caches.project_cache.memoize(ty, || { debug!("AssociatedTypeNormalizer: ty={:?}", ty); - self.shared.tcx().normalize_associated_type(&ty) + self.tcx.normalize_associated_type(&ty) }) } } From 85527456e8375e9a2236c2cd7b3a7e043b70f75e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 21 Apr 2017 17:26:25 -0400 Subject: [PATCH 636/905] use Symbol/InternedString in the cache --- src/librustc_trans/symbol_cache.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/symbol_cache.rs b/src/librustc_trans/symbol_cache.rs index a838c3a2c4cb..ddc1ef537a55 100644 --- a/src/librustc_trans/symbol_cache.rs +++ b/src/librustc_trans/symbol_cache.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::RefCell; -use std::rc::Rc; use rustc::ty::TyCtxt; +use std::cell::RefCell; +use syntax_pos::symbol::{InternedString, Symbol}; use trans_item::TransItem; use util::nodemap::FxHashMap; @@ -22,7 +22,7 @@ use util::nodemap::FxHashMap; pub struct SymbolCache<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - index: RefCell, Rc>>, + index: RefCell, Symbol>>, } impl<'a, 'tcx> SymbolCache<'a, 'tcx> { @@ -33,10 +33,10 @@ impl<'a, 'tcx> SymbolCache<'a, 'tcx> { } } - pub fn get(&self, trans_item: TransItem<'tcx>) -> Rc { + pub fn get(&self, trans_item: TransItem<'tcx>) -> InternedString { let mut index = self.index.borrow_mut(); index.entry(trans_item) - .or_insert_with(|| Rc::new(trans_item.compute_symbol_name(self.tcx))) - .clone() + .or_insert_with(|| Symbol::intern(&trans_item.compute_symbol_name(self.tcx))) + .as_str() } } From 946f8e6a59242a8112c6983d1336fef54bc55b9a Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Sat, 22 Apr 2017 09:38:23 +1000 Subject: [PATCH 637/905] Use primitive align for tagged enum fill. Hopefully will fix assert on ARM where vector types are being used as the fill type for enums containing repr aligned types greater than the largest possible native type, thus don't match the Layout's alignment and triggers an assert. --- src/librustc_trans/adt.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 5326e9344c89..d1c1dd7436a5 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -185,7 +185,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } - layout::General { discr, size, align, .. } => { + layout::General { discr, size, align, primitive_align, .. } => { // We need a representation that has: // * The alignment of the most-aligned field // * The size of the largest variant (rounded up to that alignment) @@ -198,14 +198,15 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // of the size. let size = size.bytes(); let align = align.abi(); + let primitive_align = primitive_align.abi(); assert!(align <= std::u32::MAX as u64); let discr_ty = Type::from_integer(cx, discr); let discr_size = discr.size().bytes(); let padded_discr_size = roundup(discr_size, align as u32); let variant_part_size = size-padded_discr_size; - let variant_fill = union_fill(cx, variant_part_size, align); + let variant_fill = union_fill(cx, variant_part_size, primitive_align); - assert_eq!(machine::llalign_of_min(cx, variant_fill), align as u32); + assert_eq!(machine::llalign_of_min(cx, variant_fill), primitive_align as u32); assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly let fields: Vec = [discr_ty, From 6d86f81eb1bd2d36d1e75958fd1f53648e82f407 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 21 Apr 2017 21:02:14 -0400 Subject: [PATCH 638/905] move the uses of the trans caches into rustc::traits This makes these routines more readily available for other bits of code. It also will help when refactoring. --- src/librustc/traits/trans/mod.rs | 147 ++++++++++++++++++++++++++++- src/librustc_trans/collector.rs | 28 ++---- src/librustc_trans/common.rs | 4 +- src/librustc_trans/mir/constant.rs | 4 +- src/librustc_trans/mir/mod.rs | 7 +- src/librustc_trans/monomorphize.rs | 128 +------------------------ 6 files changed, 164 insertions(+), 154 deletions(-) diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 8517f573e602..e38306aed2a9 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -1,15 +1,154 @@ +// 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::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::DefId; +use infer::TransNormalize; use std::cell::RefCell; use std::marker::PhantomData; -use traits::Vtable; -use ty::{self, Ty}; +use syntax::ast; +use syntax_pos::Span; +use traits::{FulfillmentContext, Obligation, ObligationCause, Reveal, SelectionContext, Vtable}; +use ty::{self, Ty, TyCtxt}; +use ty::subst::{Subst, Substs}; +use ty::fold::{TypeFoldable, TypeFolder}; +use util::common::MemoizationMap; + +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// 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. + pub fn trans_fulfill_obligation(self, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>) + -> Vtable<'tcx, ()> + { + // Remove any references to regions; this helps improve caching. + let trait_ref = self.erase_regions(&trait_ref); + + self.trans_trait_caches.trait_cache.memoize(trait_ref, || { + debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", + 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. + self.infer_ctxt((), Reveal::All).enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::misc(span, + ast::DUMMY_NODE_ID); + let obligation = Obligation::new(obligation_cause, + 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. + debug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref); + self.sess.span_fatal(span, + "reached the recursion limit during monomorphization \ + (selection ambiguity)"); + } + Err(e) => { + span_bug!(span, "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(span, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) + }) + } + + /// Monomorphizes a type from the AST by first applying the in-scope + /// substitutions and then normalizing any associated types. + pub fn trans_apply_param_substs(self, + param_substs: &Substs<'tcx>, + value: &T) + -> T + where T: TransNormalize<'tcx> + { + debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); + let substituted = value.subst(self, param_substs); + let substituted = self.erase_regions(&substituted); + AssociatedTypeNormalizer::new(self).fold(&substituted) + } +} + +struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'gcx>, +} + +impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { + fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { + AssociatedTypeNormalizer { tcx } + } + + fn fold>(&mut self, value: &T) -> T { + if !value.has_projection_types() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + ty + } else { + self.tcx.trans_trait_caches.project_cache.memoize(ty, || { + debug!("AssociatedTypeNormalizer: ty={:?}", ty); + self.tcx.normalize_associated_type(&ty) + }) + } + } +} /// Specializes caches used in trans -- in particular, they assume all /// types are fully monomorphized and that free regions can be erased. pub struct TransTraitCaches<'tcx> { - pub trait_cache: RefCell>>, - pub project_cache: RefCell>>, + trait_cache: RefCell>>, + project_cache: RefCell>>, } impl<'tcx> TransTraitCaches<'tcx> { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ba2b807d5a01..13bb0d371250 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -467,13 +467,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &target_ty); + let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &target_ty); let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &source_ty); + let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &source_ty); let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, source_ty, target_ty); @@ -489,10 +487,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { let fn_ty = operand.ty(self.mir, self.scx.tcx()); - let fn_ty = monomorphize::apply_param_substs( - self.scx, - self.param_substs, - &fn_ty); + let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &fn_ty); visit_fn_use(self.scx, fn_ty, false, &mut self.output); } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { @@ -534,9 +530,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } if let mir::Literal::Item { def_id, substs } = constant.literal { - let substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs); + let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &substs); let instance = monomorphize::resolve(self.scx, def_id, substs); collect_neighbours(self.scx, instance, self.output); } @@ -552,17 +547,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { match *kind { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.mir, tcx); - let callee_ty = monomorphize::apply_param_substs( - self.scx, self.param_substs, &callee_ty); + let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty); visit_fn_use(self.scx, callee_ty, true, &mut self.output); } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { let ty = location.ty(self.mir, self.scx.tcx()) .to_ty(self.scx.tcx()); - let ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &ty); + let ty = tcx.trans_apply_param_substs(self.param_substs, &ty); visit_drop_use(self.scx, ty, true, self.output); } mir::TerminatorKind::Goto { .. } | diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5d58c9353892..648ea92c8437 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -564,7 +564,7 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, -> Ty<'tcx> { let ty = shared.tcx().item_type(def_id); - monomorphize::apply_param_substs(shared, substs, &ty) + shared.tcx().trans_apply_param_substs(substs, &ty) } /// Return the substituted type of an instance. @@ -573,5 +573,5 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, -> Ty<'tcx> { let ty = instance.def.def_ty(shared.tcx()); - monomorphize::apply_param_substs(shared, instance.substs, &ty) + shared.tcx().trans_apply_param_substs(instance.substs, &ty) } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 8bce0cf85c08..dbae79e034da 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -260,9 +260,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.shared(), - self.substs, - value) + self.ccx.tcx().trans_apply_param_substs(self.substs, value) } fn trans(&mut self) -> Result, ConstEvalErr<'tcx>> { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 3d8c5085462a..2669f722f9c1 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -22,7 +22,7 @@ use base; use builder::Builder; use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; -use monomorphize::{self, Instance}; +use monomorphize::Instance; use abi::FnType; use type_of; @@ -102,8 +102,9 @@ pub struct MirContext<'a, 'tcx:'a> { impl<'a, 'tcx> MirContext<'a, 'tcx> { pub fn monomorphize(&self, value: &T) -> T - where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value) + where T: TransNormalize<'tcx> + { + self.ccx.tcx().trans_apply_param_substs(self.param_substs, value) } pub fn set_debug_loc(&mut self, bcx: &Builder, source_info: mir::SourceInfo) { diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 33626e7c39fc..d27eeb2b6466 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -13,17 +13,13 @@ use common::*; use glue; use rustc::hir::def_id::DefId; -use rustc::infer::TransNormalize; use rustc::middle::lang_items::DropInPlaceFnLangItem; -use rustc::traits::{self, SelectionContext, Reveal}; +use rustc::traits; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::common::MemoizationMap; -use syntax::ast; -use syntax::codemap::{Span, DUMMY_SP}; +use syntax::codemap::DUMMY_SP; pub use rustc::ty::Instance; @@ -104,73 +100,6 @@ pub fn resolve_closure<'a, 'tcx> ( } } -/// Attempts to resolve an obligation. 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. -fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>) - -> traits::Vtable<'tcx, ()> -{ - let tcx = scx.tcx(); - - // Remove any references to regions; this helps improve caching. - let trait_ref = tcx.erase_regions(&trait_ref); - - tcx.trans_trait_caches.trait_cache.memoize(trait_ref, || { - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - 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. - tcx.infer_ctxt((), Reveal::All).enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = traits::ObligationCause::misc(span, - ast::DUMMY_NODE_ID); - let obligation = traits::Obligation::new(obligation_cause, - 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. - debug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref); - tcx.sess.span_fatal(span, - "reached the recursion limit during monomorphization \ - (selection ambiguity)"); - } - Err(e) => { - span_bug!(span, "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 = traits::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(span, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) - }) -} - fn resolve_associated_item<'a, 'tcx>( scx: &SharedCrateContext<'a, 'tcx>, trait_item: &ty::AssociatedItem, @@ -185,7 +114,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 = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref)); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -285,7 +214,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) }); - match fulfill_obligation(scx, DUMMY_SP, trait_ref) { + match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap() } @@ -295,21 +224,6 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx } } -/// Monomorphizes a type from the AST by first applying the in-scope -/// substitutions and then normalizing any associated types. -pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, - param_substs: &Substs<'tcx>, - value: &T) - -> T - where T: TransNormalize<'tcx> -{ - let tcx = scx.tcx(); - debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); - let substituted = value.subst(tcx, param_substs); - let substituted = scx.tcx().erase_regions(&substituted); - AssociatedTypeNormalizer::new(tcx).fold(&substituted) -} - /// Returns the normalized type of a struct field pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_substs: &Substs<'tcx>, @@ -319,37 +233,3 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } -struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'gcx>, -} - -impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { - AssociatedTypeNormalizer { tcx } - } - - fn fold>(&mut self, value: &T) -> T { - if !value.has_projection_types() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projection_types() { - ty - } else { - self.tcx.trans_trait_caches.project_cache.memoize(ty, || { - debug!("AssociatedTypeNormalizer: ty={:?}", ty); - self.tcx.normalize_associated_type(&ty) - }) - } - } -} From e1afddc29c7a056f855c0523e598c3bda42f4aea Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Sat, 22 Apr 2017 13:47:36 +1200 Subject: [PATCH 639/905] Haiku: fix initial platform support --- src/librustc_back/target/haiku_base.rs | 3 ++- src/librustc_data_structures/flock.rs | 1 + src/libunwind/build.rs | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs index bfdc9faaa8a7..8e7f463563c3 100644 --- a/src/librustc_back/target/haiku_base.rs +++ b/src/librustc_back/target/haiku_base.rs @@ -16,9 +16,10 @@ pub fn opts() -> TargetOptions { linker: "cc".to_string(), dynamic_linking: true, executables: true, - has_rpath: true, + has_rpath: false, target_family: Some("unix".to_string()), linker_is_gnu: true, + no_integrated_as: true, .. Default::default() } } diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 26417e3ba7cd..32f0fd419977 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -113,6 +113,7 @@ mod imp { pub l_sysid: libc::c_int, } + pub const F_RDLCK: libc::c_short = 0x0040; pub const F_UNLCK: libc::c_short = 0x0200; pub const F_WRLCK: libc::c_short = 0x0400; pub const F_SETLK: libc::c_int = 0x0080; diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index 9b8099d55a02..be9aa6c5d40b 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -39,5 +39,7 @@ fn main() { println!("cargo:rustc-link-lib=static-nobundle=pthread"); } else if target.contains("fuchsia") { println!("cargo:rustc-link-lib=unwind"); + } else if target.contains("haiku") { + println!("cargo:rustc-link-lib=gcc_s"); } } From 80a2a94d5a646859239cb8acab3ecc3c508e741e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Apr 2017 00:32:23 +0200 Subject: [PATCH 640/905] Re-enable hoedown by default --- src/librustdoc/html/markdown.rs | 335 +++++++++++++++--- src/librustdoc/html/render.rs | 44 ++- src/librustdoc/lib.rs | 20 +- src/librustdoc/markdown.rs | 14 +- src/librustdoc/test.rs | 55 +-- src/test/rustdoc/check-hard-break.rs | 20 -- src/test/rustdoc/check-rule-image-footnote.rs | 44 --- 7 files changed, 382 insertions(+), 150 deletions(-) delete mode 100644 src/test/rustdoc/check-hard-break.rs delete mode 100644 src/test/rustdoc/check-rule-image-footnote.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4bf856240f66..614d59c512da 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -32,6 +32,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; use std::collections::{HashMap, VecDeque}; use std::default::Default; +use std::ffi::CString; use std::fmt::{self, Write}; use std::str; use syntax::feature_gate::UnstableFeatures; @@ -40,21 +41,28 @@ use syntax::codemap::Span; use html::render::derive_id; use html::toc::TocBuilder; use html::highlight; +use html::escape::Escape; use test; use pulldown_cmark::{html, Event, Tag, Parser}; use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES}; +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum RenderType { + Hoedown, + Pulldown, +} + /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str); +pub struct Markdown<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. -pub struct MarkdownWithToc<'a>(pub &'a str); +pub struct MarkdownWithToc<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. -pub struct MarkdownHtml<'a>(pub &'a str); +pub struct MarkdownHtml<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders only the first paragraph. pub struct MarkdownSummaryLine<'a>(pub &'a str); @@ -73,6 +81,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } +/// Returns a new string with all consecutive whitespace collapsed into +/// single spaces. +/// +/// Any leading or trailing whitespace will be trimmed. +fn collapse_whitespace(s: &str) -> String { + s.split_whitespace().collect::>().join(" ") +} + /// Convert chars from a title for an id. /// /// "Hello, world!" -> "hello-world" @@ -368,6 +384,7 @@ const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3; const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; +const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1; const HOEDOWN_EXTENSIONS: libc::c_uint = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | @@ -462,6 +479,13 @@ struct hoedown_buffer { unit: libc::size_t, } +struct MyOpaque { + dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_buffer, *const hoedown_renderer_data, + libc::size_t), + toc_builder: Option, +} + extern { fn hoedown_html_renderer_new(render_flags: libc::c_uint, nesting_level: libc::c_int) @@ -478,6 +502,7 @@ extern { fn hoedown_document_free(md: *mut hoedown_document); fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; + fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); fn hoedown_buffer_free(b: *mut hoedown_buffer); } @@ -487,6 +512,208 @@ impl hoedown_buffer { } } +pub fn render(w: &mut fmt::Formatter, + s: &str, + print_toc: bool, + html_flags: libc::c_uint) -> fmt::Result { + extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, + lang: *const hoedown_buffer, data: *const hoedown_renderer_data, + line: libc::size_t) { + unsafe { + if orig_text.is_null() { return } + + let opaque = (*data).opaque as *mut hoedown_html_renderer_state; + let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque); + let text = (*orig_text).as_bytes(); + let origtext = str::from_utf8(text).unwrap(); + let origtext = origtext.trim_left(); + debug!("docblock: ==============\n{:?}\n=======", text); + let rendered = if lang.is_null() || origtext.is_empty() { + false + } else { + let rlang = (*lang).as_bytes(); + let rlang = str::from_utf8(rlang).unwrap(); + if !LangString::parse(rlang).rust { + (my_opaque.dfltblk)(ob, orig_text, lang, + opaque as *const hoedown_renderer_data, + line); + true + } else { + false + } + }; + + let lines = origtext.lines().filter(|l| { + stripped_filtered_line(*l).is_none() + }); + let text = lines.collect::>().join("\n"); + if rendered { return } + PLAYGROUND.with(|play| { + // insert newline to clearly separate it from the + // previous block so we can shorten the html output + let mut s = String::from("\n"); + let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { + if url.is_empty() { + return None; + } + let test = origtext.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }).collect::>().join("\n"); + let krate = krate.as_ref().map(|s| &**s); + let test = test::maketest(&test, krate, false, + &Default::default()); + let channel = if test.contains("#![feature(") { + "&version=nightly" + } else { + "" + }; + // These characters don't need to be escaped in a URI. + // FIXME: use a library function for percent encoding. + fn dont_escape(c: u8) -> bool { + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z') || + (b'0' <= c && c <= b'9') || + c == b'-' || c == b'_' || c == b'.' || + c == b'~' || c == b'!' || c == b'\'' || + c == b'(' || c == b')' || c == b'*' + } + let mut test_escaped = String::new(); + for b in test.bytes() { + if dont_escape(b) { + test_escaped.push(char::from(b)); + } else { + write!(test_escaped, "%{:02X}", b).unwrap(); + } + } + Some(format!( + r#"Run"#, + url, test_escaped, channel + )) + }); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + let output = CString::new(s).unwrap(); + hoedown_buffer_puts(ob, output.as_ptr()); + }) + } + } + + extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, + level: libc::c_int, data: *const hoedown_renderer_data, + _: libc::size_t) { + // hoedown does this, we may as well too + unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } + + // Extract the text provided + let s = if text.is_null() { + "".to_owned() + } else { + let s = unsafe { (*text).as_bytes() }; + str::from_utf8(&s).unwrap().to_owned() + }; + + // Discard '', '' tags and some escaped characters, + // transform the contents of the header into a hyphenated string + // without non-alphanumeric characters other than '-' and '_'. + // + // This is a terrible hack working around how hoedown gives us rendered + // html for text rather than the raw text. + let mut id = s.clone(); + let repl_sub = vec!["", "", "", "", + "", "", + "<", ">", "&", "'", """]; + for sub in repl_sub { + id = id.replace(sub, ""); + } + let id = id.chars().filter_map(|c| { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); + + let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state }; + let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; + + let id = derive_id(id); + + let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, s.clone(), id.clone())) + }); + + // Render the HTML + let text = format!("\ + {sec}{}", + s, lvl = level, id = id, sec = sec); + + let text = CString::new(text).unwrap(); + unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } + } + + extern fn codespan( + ob: *mut hoedown_buffer, + text: *const hoedown_buffer, + _: *const hoedown_renderer_data, + _: libc::size_t + ) -> libc::c_int { + let content = if text.is_null() { + "".to_owned() + } else { + let bytes = unsafe { (*text).as_bytes() }; + let s = str::from_utf8(bytes).unwrap(); + collapse_whitespace(s) + }; + + let content = format!("{}", Escape(&content)); + let element = CString::new(content).unwrap(); + unsafe { hoedown_buffer_puts(ob, element.as_ptr()); } + // Return anything except 0, which would mean "also print the code span verbatim". + 1 + } + + unsafe { + let ob = hoedown_buffer_new(DEF_OUNIT); + let renderer = hoedown_html_renderer_new(html_flags, 0); + let mut opaque = MyOpaque { + dfltblk: (*renderer).blockcode.unwrap(), + toc_builder: if print_toc {Some(TocBuilder::new())} else {None} + }; + (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque + = &mut opaque as *mut _ as *mut libc::c_void; + (*renderer).blockcode = Some(block); + (*renderer).header = Some(header); + (*renderer).codespan = Some(codespan); + + let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); + hoedown_document_render(document, ob, s.as_ptr(), + s.len() as libc::size_t); + hoedown_document_free(document); + + hoedown_html_renderer_free(renderer); + + let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); + + if ret.is_ok() { + let buf = (*ob).as_bytes(); + ret = w.write_str(str::from_utf8(buf).unwrap()); + } + hoedown_buffer_free(ob); + ret + } +} + pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { extern fn block(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, @@ -511,7 +738,22 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position stripped_filtered_line(l).unwrap_or(l) }); let filename = tests.get_filename(); - tests.add_old_test(lines.collect::>().join("\n"), filename); + + if tests.render_type == RenderType::Hoedown { + let text = (*text).as_bytes(); + let text = str::from_utf8(text).unwrap(); + let lines = text.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); + let text = lines.collect::>().join("\n"); + tests.add_test(text.to_owned(), + block_info.should_panic, block_info.no_run, + block_info.ignore, block_info.test_harness, + block_info.compile_fail, block_info.error_codes, + line, filename); + } else { + tests.add_old_test(lines.collect::>().join("\n"), filename); + } } } @@ -533,7 +775,6 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position } tests.set_position(position); - unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); let renderer = hoedown_html_renderer_new(0, 0); @@ -702,72 +943,84 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md) = *self; + let Markdown(md, render_type) = *self; + // This is actually common enough to special-case if md.is_empty() { return Ok(()) } + if render_type == RenderType::Hoedown { + render(fmt, md, false, 0) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); + let p = Parser::new_ext(md, opts); - let p = Parser::new_ext(md, opts); + let mut s = String::with_capacity(md.len() * 3 / 2); - let mut s = String::with_capacity(md.len() * 3 / 2); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - - fmt.write_str(&s) + fmt.write_str(&s) + } } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let MarkdownWithToc(md) = *self; + let MarkdownWithToc(md, render_type) = *self; - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); + if render_type == RenderType::Hoedown { + render(fmt, md, true, 0) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let p = Parser::new_ext(md, opts); + let p = Parser::new_ext(md, opts); - let mut s = String::with_capacity(md.len() * 3 / 2); + let mut s = String::with_capacity(md.len() * 3 / 2); - let mut toc = TocBuilder::new(); + let mut toc = TocBuilder::new(); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); - write!(fmt, "", toc.into_toc())?; + write!(fmt, "", toc.into_toc())?; - fmt.write_str(&s) + fmt.write_str(&s) + } } } impl<'a> fmt::Display for MarkdownHtml<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let MarkdownHtml(md) = *self; + let MarkdownHtml(md, render_type) = *self; + // This is actually common enough to special-case if md.is_empty() { return Ok(()) } + if render_type == RenderType::Hoedown { + render(fmt, md, false, HOEDOWN_HTML_ESCAPE) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); + let p = Parser::new_ext(md, opts); - let p = Parser::new_ext(md, opts); + // Treat inline HTML as plain text. + let p = p.map(|event| match event { + Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), + _ => event + }); - // Treat inline HTML as plain text. - let p = p.map(|event| match event { - Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), - _ => event - }); + let mut s = String::with_capacity(md.len() * 3 / 2); - let mut s = String::with_capacity(md.len() * 3 / 2); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - - fmt.write_str(&s) + fmt.write_str(&s) + } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d55a0640562a..57d71e6c4e00 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -98,6 +98,7 @@ pub struct Context { /// publicly reused items to redirect to the right location. pub render_redirect_pages: bool, pub shared: Arc, + pub render_type: RenderType, } pub struct SharedContext { @@ -433,7 +434,8 @@ pub fn run(mut krate: clean::Crate, dst: PathBuf, passes: FxHashSet, css_file_extension: Option, - renderinfo: RenderInfo) -> Result<(), Error> { + renderinfo: RenderInfo, + render_type: RenderType) -> Result<(), Error> { let src_root = match krate.src.parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), @@ -495,6 +497,7 @@ pub fn run(mut krate: clean::Crate, dst: dst, render_redirect_pages: false, shared: Arc::new(scx), + render_type: render_type, }; // Crawl the crate to build various caches used for the output @@ -1638,11 +1641,12 @@ fn plain_summary_line(s: Option<&str>) -> String { fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result { document_stability(w, cx, item)?; - document_full(w, item)?; + document_full(w, item, cx.render_type)?; Ok(()) } -fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink) -> fmt::Result { +fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink, + render_type: RenderType) -> fmt::Result { if let Some(s) = item.doc_value() { let markdown = if s.contains('\n') { format!("{} [Read more]({})", @@ -1651,7 +1655,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin format!("{}", &plain_summary_line(Some(s))) }; write!(w, "
    {}
    ", - Markdown(&markdown))?; + Markdown(&markdown, render_type))?; } Ok(()) } @@ -1681,10 +1685,11 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { } } -fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { +fn document_full(w: &mut fmt::Formatter, item: &clean::Item, + render_type: RenderType) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
    {}
    ", - Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), render_type))?; } Ok(()) } @@ -1872,7 +1877,13 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = MarkdownSummaryLine(doc_value), + docs = if cx.render_type == RenderType::Hoedown { + format!("{}", + shorter(Some(&Markdown(doc_value, + RenderType::Hoedown).to_string()))) + } else { + format!("{}", MarkdownSummaryLine(doc_value)) + }, class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -1915,7 +1926,9 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}
    ", text)) }; @@ -1944,7 +1957,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> VecπŸ”¬ \ This is a nightly-only experimental API. {}\ {}", - unstable_extra, MarkdownHtml(&stab.unstable_reason)); + unstable_extra, + MarkdownHtml(&stab.unstable_reason, cx.render_type)); stability.push(format!("
    {}
    ", text)); } @@ -1964,7 +1978,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}
    ", text)) } @@ -2900,7 +2914,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
    {}
    ", Markdown(dox))?; + write!(w, "
    {}
    ", Markdown(dox, cx.render_type))?; } } @@ -2999,11 +3013,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi // because impls can't have a stability. document_stability(w, cx, it)?; if get_doc_value(item).is_some() { - document_full(w, item)?; + document_full(w, item, cx.render_type)?; } else { // In case the item isn't documented, // provide short documentation from the trait. - document_short(w, it, link)?; + document_short(w, it, link, cx.render_type)?; } } } else { @@ -3011,7 +3025,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } } else { document_stability(w, cx, item)?; - document_short(w, item, link)?; + document_short(w, item, link, cx.render_type)?; } } Ok(()) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0ca267bb82d2..2a6134fde5c3 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -93,6 +93,8 @@ pub mod test; use clean::AttributesExt; +use html::markdown::RenderType; + struct Output { krate: clean::Crate, renderinfo: html::render::RenderInfo, @@ -169,6 +171,7 @@ pub fn opts() -> Vec { "URL to send code snippets to, may be reset by --markdown-playground-url \ or `#![doc(html_playground_url=...)]`", "URL")), + unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")), ] } @@ -250,6 +253,12 @@ pub fn main_args(args: &[String]) -> isize { let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s)); let cfgs = matches.opt_strs("cfg"); + let render_type = if matches.opt_present("enable-commonmark") { + RenderType::Pulldown + } else { + RenderType::Hoedown + }; + if let Some(ref p) = css_file_extension { if !p.is_file() { writeln!( @@ -273,15 +282,17 @@ pub fn main_args(args: &[String]) -> isize { match (should_test, markdown_input) { (true, true) => { - return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot) + return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type) } (true, false) => { - return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot) + return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot, + render_type) } (false, true) => return markdown::render(input, output.unwrap_or(PathBuf::from("doc")), &matches, &external_html, - !matches.opt_present("markdown-no-toc")), + !matches.opt_present("markdown-no-toc"), + render_type), (false, false) => {} } @@ -295,7 +306,8 @@ pub fn main_args(args: &[String]) -> isize { output.unwrap_or(PathBuf::from("doc")), passes.into_iter().collect(), css_file_extension, - renderinfo) + renderinfo, + render_type) .expect("failed to generate documentation"); 0 } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index f75144c23aca..b9ed0eeaef73 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -26,6 +26,7 @@ use html::render::reset_ids; use html::escape::Escape; use html::markdown; use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code}; +use html::markdown::RenderType; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -50,7 +51,8 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// Render `input` (e.g. "foo.md") into an HTML file in `output` /// (e.g. output = "bar" => "bar/foo.html"). pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, - external_html: &ExternalHtml, include_toc: bool) -> isize { + external_html: &ExternalHtml, include_toc: bool, + render_type: RenderType) -> isize { let input_p = Path::new(input); output.push(input_p.file_stem().unwrap()); output.set_extension("html"); @@ -94,9 +96,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, reset_ids(false); let rendered = if include_toc { - format!("{}", MarkdownWithToc(text)) + format!("{}", MarkdownWithToc(text, render_type)) } else { - format!("{}", Markdown(text)) + format!("{}", Markdown(text, render_type)) }; let err = write!( @@ -147,7 +149,8 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, - mut test_args: Vec, maybe_sysroot: Option) -> isize { + mut test_args: Vec, maybe_sysroot: Option, + render_type: RenderType) -> isize { let input_str = match load_string(input) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, @@ -158,7 +161,8 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, opts.no_crate_inject = true; let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts, maybe_sysroot, None, - Some(input.to_owned())); + Some(input.to_owned()), + render_type); old_find_testable_code(&input_str, &mut collector, DUMMY_SP); find_testable_code(&input_str, &mut collector, DUMMY_SP); test_args.insert(0, "rustdoctest".to_string()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 3206b5021075..a30ec25de60d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -43,7 +43,7 @@ use errors; use errors::emitter::ColorConfig; use clean::Attributes; -use html::markdown; +use html::markdown::{self, RenderType}; #[derive(Clone, Default)] pub struct TestOptions { @@ -57,7 +57,8 @@ pub fn run(input: &str, externs: Externs, mut test_args: Vec, crate_name: Option, - maybe_sysroot: Option) + maybe_sysroot: Option, + render_type: RenderType) -> isize { let input_path = PathBuf::from(input); let input = config::Input::File(input_path.clone()); @@ -106,7 +107,8 @@ pub fn run(input: &str, opts, maybe_sysroot, Some(codemap), - None); + None, + render_type); { let dep_graph = DepGraph::new(false); @@ -396,12 +398,15 @@ pub struct Collector { position: Span, codemap: Option>, filename: Option, + // to be removed when hoedown will be removed as well + pub render_type: RenderType, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, - codemap: Option>, filename: Option) -> Collector { + codemap: Option>, filename: Option, + render_type: RenderType) -> Collector { Collector { tests: Vec::new(), old_tests: HashMap::new(), @@ -418,6 +423,7 @@ impl Collector { position: DUMMY_SP, codemap: codemap, filename: filename, + render_type: render_type, } } @@ -458,20 +464,22 @@ impl Collector { as_test_harness: bool, compile_fail: bool, error_codes: Vec, line: usize, filename: String) { let name = self.generate_name(line, &filename); - let name_beg = self.generate_name_beginning(&filename); - let mut found = false; - // to be removed when hoedown is removed - let test = test.trim().to_owned(); - if let Some(entry) = self.old_tests.get_mut(&name_beg) { - found = entry.remove_item(&test).is_some(); - } - if !found { - let _ = writeln!(&mut io::stderr(), - "WARNING: {} Code block is not currently run as a test, but will in \ - future versions of rustdoc. Please ensure this code block is a \ - runnable test, or use the `ignore` directive.", - name); - return + if self.render_type == RenderType::Pulldown { + let name_beg = self.generate_name_beginning(&filename); + let mut found = false; + // to be removed when hoedown is removed + let test = test.trim().to_owned(); + if let Some(entry) = self.old_tests.get_mut(&name_beg) { + found = entry.remove_item(&test).is_some(); + } + if !found { + let _ = writeln!(&mut io::stderr(), + "WARNING: {} Code block is not currently run as a test, but will in \ + future versions of rustdoc. Please ensure this code block is a \ + runnable test, or use the `ignore` directive.", + name); + return + } } let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); @@ -587,10 +595,15 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { attrs.unindent_doc_comments(); if let Some(doc) = attrs.doc_value() { self.collector.cnt = 0; - markdown::old_find_testable_code(doc, self.collector, + if self.collector.render_type == RenderType::Pulldown { + markdown::old_find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP)); + markdown::find_testable_code(doc, self.collector, attrs.span.unwrap_or(DUMMY_SP)); - markdown::find_testable_code(doc, self.collector, - attrs.span.unwrap_or(DUMMY_SP)); + } else { + markdown::old_find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP)); + } } nested(self); diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs deleted file mode 100644 index f048b64d104a..000000000000 --- a/src/test/rustdoc/check-hard-break.rs +++ /dev/null @@ -1,20 +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. - -#![crate_name = "foo"] - -// ignore-tidy-end-whitespace - -// @has foo/fn.f.html -// @has - '

    hard break:
    ' -// @has - 'after hard break

    ' -/// hard break: -/// after hard break -pub fn f() {} diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs deleted file mode 100644 index 46542677857f..000000000000 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ /dev/null @@ -1,44 +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. - -#![crate_name = "foo"] - -// ignore-tidy-linelength - -// @has foo/fn.f.html -// @has - '

    markdown test

    ' -// @has - '

    this is a link.

    ' -// @has - '
    ' -// @has - '

    a footnote1.

    ' -// @has - '

    another footnote2.

    ' -// @has - '

    Rust

    ' -// @has - '

    1. ' -// @has - '

      Thing β†©

    2. ' -// @has - '

      Another Thing β†©

    ' -/// markdown test -/// -/// this is a [link]. -/// -/// [link]: https://example.com "this is a title" -/// -/// ----------- -/// -/// a footnote[^footnote]. -/// -/// another footnote[^footnotebis]. -/// -/// [^footnote]: Thing -/// -/// -/// [^footnotebis]: Another Thing -/// -/// -/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) -pub fn f() {} From 295f25b19862eed40ed12e13db1afae1b4f41d35 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Apr 2017 12:27:48 +0200 Subject: [PATCH 641/905] Set hoedown to generate error index --- src/tools/error_index_generator/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index efadde992277..ca383b5add01 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, PLAYGROUND, RenderType}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, RenderType::Hoedown))?, None => write!(output, "

    No description.

    \n")?, } From d79b511f5c0eb6092c1cc4c3fd41a673cf5e1d56 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Apr 2017 16:09:28 +0200 Subject: [PATCH 642/905] Fix invalid linkage --- src/libcollections/binary_heap.rs | 2 +- src/libcollections/btree/map.rs | 2 +- src/libcollections/btree/set.rs | 2 +- src/libcollections/linked_list.rs | 2 +- src/libcollections/vec_deque.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- src/libstd/collections/hash/set.rs | 2 +- src/libstd/path.rs | 2 +- src/libstd/sync/mpsc/mod.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 149c285a72a9..b10a655c205b 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -1042,7 +1042,7 @@ impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] +/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.BinaryHeap.html#method.into_iter diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index fb0b852d1027..c5e4c7652524 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -298,7 +298,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// An owning iterator over the entries of a `BTreeMap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] +/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.BTreeMap.html#method.into_iter diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index e05533aa50e3..d32460da9392 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -97,7 +97,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { /// An owning iterator over the items of a `BTreeSet`. /// -/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] +/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 1cc5e10418f2..adfd91bec489 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -115,7 +115,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { /// An owning iterator over the elements of a `LinkedList`. /// -/// This `struct` is created by the [`into_iter`] method on [`LinkedList`] +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.LinkedList.html#method.into_iter diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index a9e795f9378a..079d3acf3764 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -2070,7 +2070,7 @@ impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. /// -/// This `struct` is created by the [`into_iter`] method on [`VecDeque`] +/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.VecDeque.html#method.into_iter diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index eacb59d375a5..e7102115caf5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1377,7 +1377,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// An owning iterator over the entries of a `HashMap`. /// -/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.HashMap.html#method.into_iter diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e3fad2850257..7215e1bde850 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -890,7 +890,7 @@ pub struct Iter<'a, K: 'a> { /// An owning iterator over the items of a `HashSet`. /// -/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`HashSet`]: struct.HashSet.html diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 15bc74a83401..9d66430bc930 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -10,7 +10,7 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] +//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] //! and [`str`]), for working with paths abstractly. These types are thin wrappers //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 852675edc023..6c8839224f77 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -452,7 +452,7 @@ pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); /// An error returned from the [`recv`] function on a [`Receiver`]. /// /// The [`recv`] operation can only fail if the sending half of a -/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further +/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further /// messages will ever be received. /// /// [`recv`]: struct.Receiver.html#method.recv From 91fb6bc1eb9874096e30cdac5152cdbd9d25dbf4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Apr 2017 18:41:47 +0200 Subject: [PATCH 643/905] Fix tests --- src/librustdoc/html/markdown.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 614d59c512da..0dc7ae2873b7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1094,6 +1094,7 @@ pub fn plain_summary_line(md: &str) -> String { mod tests { use super::{LangString, Markdown, MarkdownHtml}; use super::plain_summary_line; + use super::RenderType; use html::render::reset_ids; #[test] @@ -1134,14 +1135,14 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown)); + format!("{}", Markdown(markdown, RenderType::Pulldown)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -1163,7 +1164,7 @@ mod tests { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); } @@ -1204,7 +1205,7 @@ mod tests { #[test] fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { - let output = format!("{}", MarkdownHtml(input)); + let output = format!("{}", MarkdownHtml(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); } From 9c978820550994809940fa91436b6fbab9e6db49 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 22 Apr 2017 14:56:36 +0200 Subject: [PATCH 644/905] Fix line display --- src/librustdoc/html/markdown.rs | 12 ++++-------- src/librustdoc/test.rs | 8 ++++---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 0dc7ae2873b7..85a28bbfbc6d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -719,7 +719,7 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position text: *const hoedown_buffer, lang: *const hoedown_buffer, data: *const hoedown_renderer_data, - _line: libc::size_t) { + line: libc::size_t) { unsafe { if text.is_null() { return } let block_info = if lang.is_null() { @@ -737,22 +737,18 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position let lines = text.lines().map(|l| { stripped_filtered_line(l).unwrap_or(l) }); + let text = lines.collect::>().join("\n"); let filename = tests.get_filename(); if tests.render_type == RenderType::Hoedown { - let text = (*text).as_bytes(); - let text = str::from_utf8(text).unwrap(); - let lines = text.lines().map(|l| { - stripped_filtered_line(l).unwrap_or(l) - }); - let text = lines.collect::>().join("\n"); + let line = tests.get_line() + line; tests.add_test(text.to_owned(), block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness, block_info.compile_fail, block_info.error_codes, line, filename); } else { - tests.add_old_test(lines.collect::>().join("\n"), filename); + tests.add_old_test(text, filename); } } } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index a30ec25de60d..5b9ab304db0a 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -464,19 +464,19 @@ impl Collector { as_test_harness: bool, compile_fail: bool, error_codes: Vec, line: usize, filename: String) { let name = self.generate_name(line, &filename); + // to be removed when hoedown is removed if self.render_type == RenderType::Pulldown { let name_beg = self.generate_name_beginning(&filename); let mut found = false; - // to be removed when hoedown is removed let test = test.trim().to_owned(); if let Some(entry) = self.old_tests.get_mut(&name_beg) { found = entry.remove_item(&test).is_some(); } if !found { let _ = writeln!(&mut io::stderr(), - "WARNING: {} Code block is not currently run as a test, but will in \ - future versions of rustdoc. Please ensure this code block is a \ - runnable test, or use the `ignore` directive.", + "WARNING: {} Code block is not currently run as a test, but will \ + in future versions of rustdoc. Please ensure this code block is \ + a runnable test, or use the `ignore` directive.", name); return } From 3bf00450cb9413b3c8e1e52fb7dfeaf31eb93b83 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Apr 2017 01:20:50 +0300 Subject: [PATCH 645/905] remove cleanup branches to the resume block This improves LLVM performance by 10% lost during the shimmir transition. --- src/librustc_mir/transform/simplify.rs | 34 +++++++++++++++++++++++ src/test/codegen/drop.rs | 2 +- src/test/codegen/personality_lifetimes.rs | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 0a8f147b2141..ef7990653ba9 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -124,6 +124,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { self.collapse_goto_chain(successor, &mut changed); } + changed |= self.simplify_unwind(&mut terminator); + let mut new_stmts = vec![]; let mut inner_changed = true; while inner_changed { @@ -238,6 +240,38 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { true } + // turn an unwind branch to a resume block into a None + fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool { + let unwind = match terminator.kind { + TerminatorKind::Drop { ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut unwind, .. } | + TerminatorKind::Call { cleanup: ref mut unwind, .. } | + TerminatorKind::Assert { cleanup: ref mut unwind, .. } => + unwind, + _ => return false + }; + + if let &mut Some(unwind_block) = unwind { + let is_resume_block = match self.basic_blocks[unwind_block] { + BasicBlockData { + ref statements, + terminator: Some(Terminator { + kind: TerminatorKind::Resume, .. + }), .. + } if statements.is_empty() => true, + _ => false + }; + if is_resume_block { + debug!("simplifying unwind to {:?} from {:?}", + unwind_block, terminator.source_info); + *unwind = None; + } + return is_resume_block; + } + + false + } + fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs index a4bd5cf2c158..d7e2cb6d9a50 100644 --- a/src/test/codegen/drop.rs +++ b/src/test/codegen/drop.rs @@ -36,7 +36,7 @@ pub fn droppy() { // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName -// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName +// CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName // The next line checks for the } that ends the function definition // CHECK-LABEL: {{^[}]}} diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs index e0de64b26df4..9fd600b32e6c 100644 --- a/src/test/codegen/personality_lifetimes.rs +++ b/src/test/codegen/personality_lifetimes.rs @@ -37,5 +37,6 @@ pub fn test() { // CHECK: bitcast{{.*}}personalityslot // CHECK-NEXT: call void @llvm.lifetime.start might_unwind(); + let _t = S; might_unwind(); } From e1377a4f474fc76abc798110b7fb4f53d54c2e2b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Apr 2017 01:58:12 +0300 Subject: [PATCH 646/905] avoid calling `mk_region` unnecessarily this improves typeck & trans performance by 1%. This looked hotter on callgrind than it is on a CPU. --- src/librustc/infer/freshen.rs | 2 +- src/librustc/infer/region_inference/mod.rs | 8 +++---- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 4 ++-- src/librustc/traits/fulfill.rs | 2 +- src/librustc/traits/mod.rs | 2 +- src/librustc/ty/context.rs | 18 ++++++++++++++- src/librustc/ty/fold.rs | 22 ++++++++++++++++--- src/librustc/ty/mod.rs | 11 ++++------ src/librustc/ty/subst.rs | 3 +++ src/librustc/ty/util.rs | 2 +- .../borrowck/gather_loans/lifetime.rs | 2 +- src/librustc_driver/test.rs | 4 ++-- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/shim.rs | 5 ++--- src/librustc_mir/transform/erase_regions.rs | 4 ++-- src/librustc_mir/transform/inline.rs | 4 ++-- src/librustc_mir/util/elaborate_drops.rs | 5 ++--- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_typeck/astconv.rs | 10 ++++----- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 6 ++--- src/librustc_typeck/check/mod.rs | 4 ++-- src/librustc_typeck/check/writeback.rs | 8 +++---- 27 files changed, 85 insertions(+), 55 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 697a1ecadc45..922842136dc9 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::ReEmpty | ty::ReErased => { // replace all free regions with 'erased - self.tcx().mk_region(ty::ReErased) + self.tcx().types.re_erased } } } diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 0bb9e2c7fa15..fa6775737b57 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -948,7 +948,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } else { // otherwise, we don't know what the free region is, // so we must conservatively say the LUB is static: - self.tcx.mk_region(ReStatic) + self.tcx.types.re_static } } @@ -971,7 +971,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { if a == b { a } else { - self.tcx.mk_region(ReStatic) + self.tcx.types.re_static } } } @@ -1018,7 +1018,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn construct_var_data(&self) -> Vec> { (0..self.num_vars() as usize) - .map(|_| Value(self.tcx.mk_region(ty::ReEmpty))) + .map(|_| Value(self.tcx.types.re_empty)) .collect() } @@ -1493,7 +1493,7 @@ fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> &'tcx ty::Region { match values[rid.index as usize] { Value(r) => r, - ErrorValue => tcx.mk_region(ReStatic), // Previously reported error. + ErrorValue => tcx.types.re_static, // Previously reported error. } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a10f52e2d4cc..8b2631591582 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -426,7 +426,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { hir::ExprMatch(ref discr, ref arms, _) => { let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); - let r = self.tcx().mk_region(ty::ReEmpty); + let r = self.tcx().types.re_empty; self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); // treatment of the discriminant is handled while walking the arms. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7d3c17a04891..188fcc914149 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -871,8 +871,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // we can promote to a constant, otherwise equal to enclosing temp // lifetime. let (re, old_re) = if promotable { - (self.tcx().mk_region(ty::ReStatic), - self.tcx().mk_region(ty::ReStatic)) + (self.tcx().types.re_static, + self.tcx().types.re_static) } else { self.temporary_scope(id) }; diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index d49affa3e872..908bb337fa18 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -443,7 +443,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( // Otherwise, we have something of the form // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. Some(t_a) => { - let r_static = selcx.tcx().mk_region(ty::ReStatic); + let r_static = selcx.tcx().types.re_static; register_region_obligation(t_a, r_static, obligation.cause.clone(), region_obligations); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 18f0a749f701..281c1e253798 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -629,7 +629,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.mk_region(ty::ReErased), + |_, _| tcx.types.re_erased, |def, _| trait_ref.substs().type_for_def(def)); // the trait type may have higher-ranked lifetimes in it; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e836bf23a5a8..b20ac8ddbfc8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -190,6 +190,10 @@ pub struct CommonTypes<'tcx> { pub f64: Ty<'tcx>, pub never: Ty<'tcx>, pub err: Ty<'tcx>, + + pub re_empty: &'tcx Region, + pub re_static: &'tcx Region, + pub re_erased: &'tcx Region, } #[derive(RustcEncodable, RustcDecodable)] @@ -360,6 +364,14 @@ impl<'tcx> TypeckTables<'tcx> { impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { let mk = |sty| interners.intern_ty(sty, None); + let mk_region = |r| { + if let Some(r) = interners.region.borrow().get(&r) { + return r.0; + } + let r = interners.arena.alloc(r); + interners.region.borrow_mut().insert(Interned(r)); + &*r + }; CommonTypes { bool: mk(TyBool), char: mk(TyChar), @@ -379,6 +391,10 @@ impl<'tcx> CommonTypes<'tcx> { u128: mk(TyUint(ast::UintTy::U128)), f32: mk(TyFloat(ast::FloatTy::F32)), f64: mk(TyFloat(ast::FloatTy::F64)), + + re_empty: mk_region(Region::ReEmpty), + re_static: mk_region(Region::ReStatic), + re_erased: mk_region(Region::ReErased), } } } @@ -1232,7 +1248,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) + self.mk_imm_ref(self.types.re_static, self.mk_str()) } pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index e29653c9e88a..969d040e7a6e 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -410,7 +410,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> { - self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0 + self.replace_late_bound_regions(value, |_| self.types.re_erased).0 } /// Rewrite any late-bound regions so that they are anonymous. Region numbers are @@ -538,7 +538,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // whenever a substitution occurs. match *r { ty::ReLateBound(..) => r, - _ => self.tcx().mk_region(ty::ReErased) + _ => self.tcx().types.re_erased } } } @@ -565,6 +565,22 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region { } } +pub fn shift_region_ref<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + region: &'tcx ty::Region, + amount: u32) + -> &'tcx ty::Region +{ + match region { + &ty::ReLateBound(debruijn, br) if amount > 0 => { + tcx.mk_region(ty::ReLateBound(debruijn.shifted(amount), br)) + } + _ => { + region + } + } +} + pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32, value: &T) -> T where T: TypeFoldable<'tcx> @@ -573,7 +589,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, value, amount); value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - tcx.mk_region(shift_region(*region, amount)) + shift_region_ref(tcx, region, amount) })) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 649298abed51..e355b69d6e61 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2499,15 +2499,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { - - // for an empty parameter environment, there ARE no free - // regions, so it shouldn't matter what we use for the free id - let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); ty::ParameterEnvironment { free_substs: self.intern_substs(&[]), caller_bounds: Vec::new(), - implicit_region_bound: self.mk_region(ty::ReEmpty), - free_id_outlive: free_id_outlive, + implicit_region_bound: self.types.re_empty, + // for an empty parameter environment, there ARE no free + // regions, so it shouldn't matter what we use for the free id + free_id_outlive: ROOT_CODE_EXTENT, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), is_freeze_cache: RefCell::new(FxHashMap()), @@ -2760,4 +2758,3 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) { pub struct CrateInherentImpls { pub inherent_impls: DefIdMap>>, } - diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0a2cc1c30f40..14aebdf8418f 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -539,6 +539,9 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { } fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region { + if self.region_binders_passed == 0 || !region.has_escaping_regions() { + return region; + } self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 49d79f6545e2..cdf3cf00b24e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -412,7 +412,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { ty::Substs::for_item(self, item_def_id, - |_, _| self.mk_region(ty::ReErased), + |_, _| self.types.re_erased, |_, _| { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) }) diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index bbfb7e5874ea..b921678b495c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } Categorization::StaticItem | Categorization::Deref(.., mc::UnsafePtr(..)) => { - self.bccx.tcx.mk_region(ty::ReStatic) + self.bccx.tcx.types.re_static } Categorization::Deref(.., mc::BorrowedPtr(_, r)) | Categorization::Deref(.., mc::Implicit(_, r)) => { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 7447fba3038e..147d6558e19c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -343,12 +343,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_rptr_static(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static, self.tcx().types.isize) } pub fn t_rptr_empty(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty, self.tcx().types.isize) } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 5fece4d6a5d2..0833342927fe 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(ty.is_slice()); let array_ty = tcx.mk_array(tcx.types.u8, bytes.len()); - let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty); + 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: value.clone() }); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 4d70540a7c68..7f7377e5ffe3 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -308,10 +308,9 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, Adjustment::Deref => Operand::Consume(rcvr_l.deref()), Adjustment::RefMut => { // let rcvr = &mut rcvr; - let re_erased = tcx.mk_region(ty::ReErased); let ref_rcvr = local_decls.push(temp_decl( Mutability::Not, - tcx.mk_ref(re_erased, ty::TypeAndMut { + tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::MutMutable }), @@ -321,7 +320,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, source_info: source_info, kind: StatementKind::Assign( Lvalue::Local(ref_rcvr), - Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l) + Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l) ) }); Operand::Consume(Lvalue::Local(ref_rcvr)) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 0f869e7ed02f..5cc5cf297936 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -13,7 +13,7 @@ //! care erasing regions all over the place. use rustc::ty::subst::Substs; -use rustc::ty::{Ty, TyCtxt, ReErased, ClosureSubsts}; +use rustc::ty::{Ty, TyCtxt, ClosureSubsts}; use rustc::mir::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{MirPass, MirSource, Pass}; @@ -43,7 +43,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { match *rvalue { Rvalue::Ref(ref mut r, _, _) => { - *r = self.tcx.mk_region(ReErased); + *r = self.tcx.types.re_erased; } Rvalue::Use(..) | Rvalue::Repeat(..) | diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 892d67ac2372..45bdff9195c4 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let dest = if dest_needs_borrow(&destination.0) { debug!("Creating temp for return destination"); let dest = Rvalue::Ref( - self.tcx.mk_region(ty::ReErased), + self.tcx.types.re_erased, BorrowKind::Mut, destination.0); @@ -582,7 +582,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>, callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> { let arg = Rvalue::Ref( - self.tcx.mk_region(ty::ReErased), + self.tcx.types.re_erased, BorrowKind::Mut, arg.deref()); diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 07025fcfdb94..9d7c7ec63cfc 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -506,8 +506,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let ty = self.lvalue_ty(self.lvalue); let substs = tcx.mk_substs(iter::once(Kind::from(ty))); - let re_erased = tcx.mk_region(ty::ReErased); - let ref_ty = tcx.mk_ref(re_erased, ty::TypeAndMut { + let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: ty, mutbl: hir::Mutability::MutMutable }); @@ -519,7 +518,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> source_info: self.source_info, kind: StatementKind::Assign( Lvalue::Local(ref_lvalue), - Rvalue::Ref(re_erased, BorrowKind::Mut, self.lvalue.clone()) + Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone()) ) }], terminator: Some(Terminator { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index dbae79e034da..e938913a3f11 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -708,7 +708,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let tr_lvalue = self.const_lvalue(lvalue, span)?; let ty = tr_lvalue.ty; - let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased), + let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }); let base = match tr_lvalue.base { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index de1c1e492f39..b8e9a490b0e7 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -329,7 +329,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let ty = tr_lvalue.ty.to_ty(bcx.tcx()); let ref_ty = bcx.tcx().mk_ref( - bcx.tcx().mk_region(ty::ReErased), + bcx.tcx().types.re_erased, ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() } ); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9426d601dfcc..5137ae6ff422 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -109,7 +109,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let tcx = self.tcx(); let r = match tcx.named_region_map.defs.get(&lifetime.id) { Some(&rl::Region::Static) => { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static } Some(&rl::Region::LateBound(debruijn, id)) => { @@ -171,7 +171,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); return Substs::for_item(tcx, def_id, |_, _| { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static }, |_, _| { tcx.types.err }); @@ -254,7 +254,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if let Some(lifetime) = lifetimes.get(i) { self.ast_region_to_region(lifetime, Some(def)) } else { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static } }, |def, substs| { let i = def.index as usize; @@ -715,7 +715,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span_err!(tcx.sess, span, E0228, "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound"); - tcx.mk_region(ty::ReStatic) + tcx.types.re_static }) } }) @@ -1357,7 +1357,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // If any of the derived region bounds are 'static, that is always // the best choice. if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { - return Some(tcx.mk_region(ty::ReStatic)); + return Some(tcx.types.re_static); } // Determine whether there is exactly one unique region in the set diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 4a0446424444..1086773041c9 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); if let ty::TyRef(_, mt) = expected_ty.sty { if let ty::TySlice(_) = mt.ty.sty { - pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + pat_ty = tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_slice(tcx.types.u8)) } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index b71ff58ccec3..09bfe45f5404 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -626,7 +626,7 @@ fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, let impl_self_orig = self_substs.region_for_def(def); let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig { if impl_bindings.region_param(ebr).pure_wrt_drop { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static } else { r_orig } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index cd58fcd4806d..bf7649242fa7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -36,7 +36,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let def_id = tcx.hir.local_def_id(it.id); let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.mk_region(ty::ReErased), + |_, _| tcx.types.re_erased, |def, _| tcx.mk_param_from_def(def)); let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig( diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 59dbbfe49f0a..80f9372eb54c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1063,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // In general, during probing we erase regions. See // `impl_self_ty()` for an explanation. - let region = tcx.mk_region(ty::ReErased); + let region = tcx.types.re_erased; // Search through mutabilities in order to find one where pick works: [hir::MutImmutable, hir::MutMutable] @@ -1325,7 +1325,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } else { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. - self.tcx.mk_region(ty::ReErased) + self.tcx.types.re_erased } }, |def, cur_substs| { let i = def.index as usize; @@ -1345,7 +1345,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let substs = Substs::for_item(self.tcx, impl_def_id, - |_, _| self.tcx.mk_region(ty::ReErased), + |_, _| self.tcx.types.re_erased, |_, _| self.next_ty_var( TypeVariableOrigin::SubstitutionPlaceholder( self.tcx.def_span(impl_def_id)))); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 839af0fa6706..098e8c53a52c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1954,7 +1954,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause); + self.register_region_obligation(ty, self.tcx.types.re_empty, cause); } /// Registers obligations that all types appearing in `substs` are well-formed. @@ -2513,7 +2513,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match lit.node { ast::LitKind::Str(..) => tcx.mk_static_str(), ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_array(tcx.types.u8, v.len())) } ast::LitKind::Byte(_) => tcx.types.u8, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f196aa82b1ef..35b2e8f8afcb 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -288,8 +288,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| { match *r { // 'static is valid everywhere. - ty::ReStatic | - ty::ReEmpty => gcx.mk_region(*r), + ty::ReStatic => gcx.types.re_static, + ty::ReEmpty => gcx.types.re_empty, // Free regions that come from early-bound regions are valid. ty::ReFree(ty::FreeRegion { @@ -307,7 +307,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { span_err!(self.tcx().sess, span, E0564, "only named lifetimes are allowed in `impl Trait`, \ but `{}` was found in the type `{}`", r, inside_ty); - gcx.mk_region(ty::ReStatic) + gcx.types.re_static } ty::ReVar(_) | @@ -526,7 +526,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(_) => { - self.tcx.mk_region(ty::ReStatic) + self.tcx.types.re_static } } } From acd0e40b86d718d339b13f594242575c28e966f7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Apr 2017 03:14:39 +0300 Subject: [PATCH 647/905] short-cut SharedCrateContext::layout_of That method is *incredibly* hot, so this ends up saving 10% of trans time. BTW, we really should be doing dependency tracking there - and possibly be taking the respective perf hit (got to find a way to make DTMs fast), but `layout_cache` is a non-dep-tracking map. --- src/librustc/ty/layout.rs | 54 +++++++++++++++++------------------ src/librustc_trans/context.rs | 12 ++++++++ 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6a206640b3ba..49cc4e7c993a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -822,7 +822,7 @@ impl<'a, 'gcx, 'tcx> Struct { } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Ok(None); } @@ -1067,28 +1067,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -/// Helper function for normalizing associated types in an inference context. -fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'gcx>) - -> Ty<'gcx> { - if !ty.has_projection_types() { - return ty; - } - - let mut selcx = traits::SelectionContext::new(infcx); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, &ty); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(infcx, obligation); - } - - infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) -} - impl<'a, 'gcx, 'tcx> Layout { pub fn compute_uncached(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) @@ -1100,7 +1078,7 @@ impl<'a, 'gcx, 'tcx> Layout { let ptr_layout = |pointee: Ty<'gcx>| { let non_zero = !ty.is_unsafe_ptr(); - let pointee = normalize_associated_type(infcx, pointee); + let pointee = infcx.normalize_projections(pointee); if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { @@ -1494,7 +1472,7 @@ impl<'a, 'gcx, 'tcx> Layout { // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Err(LayoutError::Unknown(ty)); } @@ -1812,7 +1790,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { Err(err) } else { @@ -1882,13 +1860,14 @@ pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { type TyLayout; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; } impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { type TyLayout = Result, LayoutError<'gcx>>; fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { - let ty = normalize_associated_type(self, ty); + let ty = self.normalize_projections(ty); Ok(TyLayout { ty: ty, @@ -1896,6 +1875,25 @@ impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { variant_index: None }) } + + fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + return ty; + } + + let mut selcx = traits::SelectionContext::new(self); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { value: result, obligations } = + traits::normalize(&mut selcx, cause, &ty); + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(self, obligation); + } + + self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) + } } impl<'a, 'tcx> TyLayout<'tcx> { @@ -2019,6 +2017,6 @@ impl<'a, 'tcx> TyLayout<'tcx> { } pub fn field>(&self, cx: C, i: usize) -> C::TyLayout { - cx.layout_of(self.field_type(cx, i)) + cx.layout_of(cx.normalize_projections(self.field_type(cx, i))) } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index ceb292c13c12..bef22cf304dc 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -771,6 +771,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) { + return TyLayout { ty: ty, layout: layout, variant_index: None }; + } + self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { infcx.layout_of(ty).unwrap_or_else(|e| { match e { @@ -781,6 +785,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { }) }) } + + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.tcx().normalize_associated_type(&ty) + } } impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { @@ -789,6 +797,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { self.shared.layout_of(ty) } + + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.shared.normalize_projections(ty) + } } pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'a, 'tcx>); From ece6c8434bc4eba1d3addfa4d5900264e55395fc Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Apr 2017 15:08:41 +0300 Subject: [PATCH 648/905] cache attributes of items from foreign crates this avoids parsing item attributes on each call to `item_attrs`, which takes off 33% (!) of translation time and 50% (!) of trans-item collection time. --- src/liballoc/heap.rs | 6 ++--- src/liballoc/lib.rs | 1 + src/liballoc/rc.rs | 35 ++++++++++++++++++++++++++-- src/librustc/middle/cstore.rs | 4 ++-- src/librustc/ty/instance.rs | 5 +--- src/librustc/ty/mod.rs | 24 +++++++++++++++---- src/librustc_driver/driver.rs | 2 ++ src/librustc_metadata/creader.rs | 1 + src/librustc_metadata/cstore.rs | 3 ++- src/librustc_metadata/cstore_impl.rs | 6 ++--- src/librustc_metadata/decoder.rs | 21 ++++++++++++++--- 11 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 08a0b2a6d008..056af13016cf 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -16,7 +16,6 @@ issue = "27700")] use core::{isize, usize}; -#[cfg(not(test))] use core::intrinsics::{min_align_of_val, size_of_val}; #[allow(improper_ctypes)] @@ -158,10 +157,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg(not(test))] -#[lang = "box_free"] +#[cfg_attr(not(test), lang = "box_free")] #[inline] -unsafe fn box_free(ptr: *mut T) { +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. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0c01eabd593f..c70d82392f91 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -87,6 +87,7 @@ #![feature(needs_allocator)] #![feature(optin_builtin_traits)] #![feature(placement_in_syntax)] +#![cfg_attr(stage0, feature(pub_restricted))] #![feature(shared)] #![feature(staged_api)] #![feature(unboxed_closures)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index fed718e9be4c..69e5351cad53 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -239,7 +239,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, Shared}; use core::convert::From; -use heap::deallocate; +use heap::{allocate, deallocate, box_free}; use raw_vec::RawVec; struct RcBox { @@ -248,7 +248,6 @@ struct RcBox { value: T, } - /// A single-threaded reference-counting pointer. /// /// See the [module-level documentation](./index.html) for more details. @@ -438,6 +437,38 @@ impl Rc { } } +impl Rc<[T]> { + /// Constructs a new `Rc<[T]>` from a `Box<[T]>`. + #[doc(hidden)] + #[unstable(feature = "rustc_private", + reason = "for internal use in rustc", + issue = "0")] + pub fn __from_array(value: Box<[T]>) -> Rc<[T]> { + unsafe { + let ptr: *mut RcBox<[T]> = + mem::transmute([mem::align_of::>(), value.len()]); + // FIXME(custom-DST): creating this invalid &[T] is dubiously defined, + // we should have a better way of getting the size/align + // of a DST from its unsized part. + let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr)); + let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]); + + // Initialize the new RcBox. + ptr::write(&mut (*ptr).strong, Cell::new(1)); + ptr::write(&mut (*ptr).weak, Cell::new(1)); + ptr::copy_nonoverlapping( + value.as_ptr(), + &mut (*ptr).value as *mut [T] as *mut T, + value.len()); + + // Free the original allocation without freeing its (moved) contents. + box_free(Box::into_raw(value)); + + Rc { ptr: Shared::new(ptr as *const _) } + } + } +} + impl Rc { /// Creates a new [`Weak`][weak] pointer to this value. /// diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index cbbfeacadb40..16b31bdb074f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -188,7 +188,7 @@ pub trait CrateStore { fn visibility(&self, def: DefId) -> ty::Visibility; fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; fn item_generics_cloned(&self, def: DefId) -> ty::Generics; - fn item_attrs(&self, def_id: DefId) -> Vec; + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>; fn fn_arg_names(&self, did: DefId) -> Vec; // trait info @@ -323,7 +323,7 @@ impl CrateStore for DummyCrateStore { } fn item_generics_cloned(&self, def: DefId) -> ty::Generics { bug!("item_generics_cloned") } - fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") } fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } // trait info diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 67287f1b4ff7..cfff3d0e5736 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -13,10 +13,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs}; use util::ppaux; -use std::borrow::Cow; use std::fmt; -use syntax::ast; - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Instance<'tcx> { @@ -59,7 +56,7 @@ impl<'tcx> InstanceDef<'tcx> { } #[inline] - pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Cow<'tcx, [ast::Attribute]> { + pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> { tcx.get_attrs(self.def_id()) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e355b69d6e61..7aa12429e5d7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -34,7 +34,6 @@ use ty::walk::TypeWalker; use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use serialize::{self, Encodable, Encoder}; -use std::borrow::Cow; use std::cell::{Cell, RefCell, Ref}; use std::collections::BTreeMap; use std::cmp; @@ -2036,6 +2035,23 @@ impl BorrowKind { } } +#[derive(Debug, Clone)] +pub enum Attributes<'gcx> { + Owned(Rc<[ast::Attribute]>), + Borrowed(&'gcx [ast::Attribute]) +} + +impl<'gcx> ::std::ops::Deref for Attributes<'gcx> { + type Target = [ast::Attribute]; + + fn deref(&self) -> &[ast::Attribute] { + match self { + &Attributes::Owned(ref data) => &data, + &Attributes::Borrowed(data) => data + } + } +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> { self.item_tables(self.hir.body_owner_def_id(body)) @@ -2389,11 +2405,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Get the attributes of a definition. - pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> { + pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> { if let Some(id) = self.hir.as_local_node_id(did) { - Cow::Borrowed(self.hir.attrs(id)) + Attributes::Borrowed(self.hir.attrs(id)) } else { - Cow::Owned(self.sess.cstore.item_attrs(did)) + Attributes::Owned(self.sess.cstore.item_attrs(did)) } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ac4e2bd5c103..438f482fa55c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -225,6 +225,8 @@ pub fn compile_input(sess: &Session, sess.code_stats.borrow().print_type_sizes(); } + if ::std::env::var("SKIP_LLVM").is_ok() { ::std::process::exit(0); } + let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); controller_entry_point!(after_llvm, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index a8ee999505e2..7bc0e8a512be 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -326,6 +326,7 @@ impl<'a> CrateLoader<'a> { cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), + attribute_cache: RefCell::new([Vec::new(), Vec::new()]), dep_kind: Cell::new(dep_kind), source: cstore::CrateSource { dylib: dylib, diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 17a6a706e0aa..72ad1d75a561 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -72,6 +72,7 @@ pub struct CrateMetadata { pub cnum_map: RefCell, pub cnum: CrateNum, pub codemap_import_info: RefCell>, + pub attribute_cache: RefCell<[Vec>>; 2]>, pub root: schema::CrateRoot, @@ -269,7 +270,7 @@ impl CrateMetadata { } pub fn is_staged_api(&self) -> bool { - for attr in self.get_item_attrs(CRATE_DEF_INDEX) { + for attr in self.get_item_attrs(CRATE_DEF_INDEX).iter() { if attr.path == "stable" || attr.path == "unstable" { return true; } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3cff063a8f56..e02c61f36464 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -149,7 +149,7 @@ impl CrateStore for cstore::CStore { self.get_crate_data(def.krate).get_generics(def.index) } - fn item_attrs(&self, def_id: DefId) -> Vec + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { self.dep_graph.read(DepNode::MetaData(def_id)); self.get_crate_data(def_id.krate).get_item_attrs(def_id.index) @@ -406,7 +406,7 @@ impl CrateStore for cstore::CStore { // Mark the attrs as used let attrs = data.get_item_attrs(id.index); - for attr in &attrs { + for attr in attrs.iter() { attr::mark_used(attr); } @@ -419,7 +419,7 @@ impl CrateStore for cstore::CStore { ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, - attrs: attrs, + attrs: attrs.iter().cloned().collect(), node: ast::ItemKind::MacroDef(body.into()), vis: ast::Visibility::Inherited, }) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index fac6079529e3..2d562aceb65c 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -31,6 +31,7 @@ use std::cell::Ref; use std::collections::BTreeMap; use std::io; use std::mem; +use std::rc::Rc; use std::str; use std::u32; @@ -859,10 +860,18 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { + pub fn get_item_attrs(&self, node_id: DefIndex) -> Rc<[ast::Attribute]> { + let (node_as, node_index) = + (node_id.address_space().index(), node_id.as_array_index()); if self.is_proc_macro(node_id) { - return Vec::new(); + return Rc::new([]); } + + if let Some(&Some(ref val)) = + self.attribute_cache.borrow()[node_as].get(node_index) { + return val.clone(); + } + // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition @@ -871,7 +880,13 @@ impl<'a, 'tcx> CrateMetadata { if def_key.disambiguated_data.data == DefPathData::StructCtor { item = self.entry(def_key.parent.unwrap()); } - self.get_attributes(&item) + let result = Rc::__from_array(self.get_attributes(&item).into_boxed_slice()); + let vec_ = &mut self.attribute_cache.borrow_mut()[node_as]; + if vec_.len() < node_index + 1 { + vec_.resize(node_index + 1, None); + } + vec_[node_index] = Some(result.clone()); + result } pub fn get_struct_field_names(&self, id: DefIndex) -> Vec { From 266d36f3b1d6231e53d1f13659e980b48d3b506f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Apr 2017 17:17:13 +0300 Subject: [PATCH 649/905] weak_lang_items: check for `lang` attribute before calling `value_str` improves trans performance by *another* 10%. --- src/librustc/middle/lang_items.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 32dfb63d6150..3b506d748ef7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -223,9 +223,10 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { pub fn extract(attrs: &[ast::Attribute]) -> Option { for attribute in attrs { - match attribute.value_str() { - Some(value) if attribute.check_name("lang") => return Some(value), - _ => {} + if attribute.check_name("lang") { + if let Some(value) = attribute.value_str() { + return Some(value) + } } } From 81af6fb67ce9efe989031d629ed414ed85ee3767 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Apr 2017 18:38:35 +0300 Subject: [PATCH 650/905] allocate less strings in `symbol_names` this improves trans performance by *another* 10%. --- src/librustc_trans/back/symbol_names.rs | 104 ++++++++++++------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 61b95f098adb..f21864764ddf 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -110,7 +110,8 @@ use rustc::hir::map::definitions::DefPathData; use rustc::util::common::record_time; use syntax::attr; -use syntax::symbol::{Symbol, InternedString}; + +use std::fmt::Write; fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -252,19 +253,47 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); - let mut buffer = SymbolPathBuffer { - names: Vec::new() - }; - + let mut buffer = SymbolPathBuffer::new(); item_path::with_forced_absolute_paths(|| { tcx.push_item_path(&mut buffer, def_id); }); - - mangle(buffer.names.into_iter(), &hash) + buffer.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 { - names: Vec, + 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 finish(mut self, hash: &str) -> String { + // end name-sequence + self.push(hash); + self.result.push('E'); + self.result + } } impl ItemPathBuffer for SymbolPathBuffer { @@ -274,7 +303,13 @@ impl ItemPathBuffer for SymbolPathBuffer { } fn push(&mut self, text: &str) { - self.names.push(Symbol::intern(text).as_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); } } @@ -283,15 +318,17 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, prefix: &str) -> String { let hash = get_symbol_hash(tcx, None, t, None); - let path = [Symbol::intern(prefix).as_str()]; - mangle(path.iter().cloned(), &hash) + let mut buffer = SymbolPathBuffer::new(); + buffer.push(prefix); + buffer.finish(&hash) } // 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, ., _, $ -pub fn sanitize(s: &str) -> String { - let mut result = String::new(); +// +// 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 @@ -328,44 +365,7 @@ pub fn sanitize(s: &str) -> String { } // Underscore-qualify anything that didn't start as an ident. - if !result.is_empty() && + !result.is_empty() && result.as_bytes()[0] != '_' as u8 && - ! (result.as_bytes()[0] as char).is_xid_start() { - return format!("_{}", result); - } - - return result; -} - -fn mangle>(path: PI, hash: &str) -> String { - // 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. - - let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested - - fn push(n: &mut String, s: &str) { - let sani = sanitize(s); - n.push_str(&format!("{}{}", sani.len(), sani)); - } - - // First, connect each component with pairs. - for data in path { - push(&mut n, &data); - } - - push(&mut n, hash); - - n.push('E'); // End name-sequence. - n + ! (result.as_bytes()[0] as char).is_xid_start() } From a0f145ba8c96feb25ae059e0917c55ef6dae01e8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 20 Apr 2017 20:37:02 +0300 Subject: [PATCH 651/905] add a cache to impl_polarity this is another one of these things that looks *much* worse on valgrind. --- src/librustc/middle/cstore.rs | 2 -- src/librustc/ty/maps.rs | 2 ++ src/librustc/ty/mod.rs | 9 +-------- src/librustc_metadata/cstore_impl.rs | 7 +------ src/librustc_typeck/collect.rs | 11 +++++++++++ 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 16b31bdb074f..20ed2244e864 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -195,7 +195,6 @@ pub trait CrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -330,7 +329,6 @@ impl CrateStore for DummyCrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 648923d6f04e..add8db850e4f 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,6 +10,7 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use hir; use middle::const_val; use middle::privacy::AccessLevels; use mir; @@ -394,6 +395,7 @@ define_maps! { <'tcx> pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, pub impl_trait_ref: ItemSignature(DefId) -> Option>, + pub impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity, /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7aa12429e5d7..1305b0d93037 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2149,14 +2149,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { - if let Some(id) = self.hir.as_local_node_id(id) { - match self.hir.expect_item(id).node { - hir::ItemImpl(_, polarity, ..) => polarity, - ref item => bug!("trait_impl_polarity: {:?} not an impl", item) - } - } else { - self.sess.cstore.impl_polarity(id) - } + queries::impl_polarity::get(self, DUMMY_SP, id) } pub fn trait_relevant_for_never(self, did: DefId) -> bool { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index e02c61f36464..cb1b0c4c0b78 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -89,6 +89,7 @@ provide! { <'tcx> tcx, def_id, cdata } associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } + impl_polarity => { cdata.get_impl_polarity(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); @@ -177,12 +178,6 @@ impl CrateStore for cstore::CStore { result } - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity - { - self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).get_impl_polarity(def.index) - } - fn impl_parent(&self, impl_def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(impl_def)); self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 855d156f6f26..1f2310c49e3a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -99,6 +99,7 @@ pub fn provide(providers: &mut Providers) { trait_def, adt_def, impl_trait_ref, + impl_polarity, is_foreign_item, ..*providers }; @@ -1133,6 +1134,16 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> hir::ImplPolarity { + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + match tcx.hir.expect_item(node_id).node { + hir::ItemImpl(_, polarity, ..) => polarity, + ref item => bug!("trait_impl_polarity: {:?} not an impl", item) + } +} + // Is it marked with ?Sized fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, ast_bounds: &[hir::TyParamBound], From a660ad84b3c27de5c0abfb683fb178ba4e4ca87e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 22 Apr 2017 15:05:18 +0300 Subject: [PATCH 652/905] bail out of selection when there are multiple surviving candidates In some cases (e.g. <[int-var] as Add<[int-var]>>), selection can turn up a large number of candidates. Bailing out early avoids O(n^2) performance. This improves item-type checking time by quite a bit, resulting in ~2% of total time-to-typeck. --- src/librustc/traits/select.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 70ddcff5181b..6442487ead95 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -943,17 +943,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } } } } - // If there are *STILL* multiple candidates, give up and - // report ambiguity. - if candidates.len() > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - // If there are *NO* candidates, then there are no impls -- // that we know of, anyway. Note that in the case where there // are unbound type variables within the obligation, it might From 13d2534fd3040520622a2b2a262ed9e7079c9fd8 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 22 Apr 2017 22:13:22 -0400 Subject: [PATCH 653/905] Remove unused import. --- src/libstd/f32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 4ed0afcfc235..4abad7e24f81 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -80,7 +80,7 @@ mod cmath { pub use self::shims::*; #[cfg(target_env = "msvc")] mod shims { - use libc::{c_float, c_int}; + use libc::c_float; #[inline] pub unsafe fn acosf(n: c_float) -> c_float { From e22873d91206e11349da713017bd67d43d8d535d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 18 Apr 2017 23:38:15 +0300 Subject: [PATCH 654/905] rustc: make the const-eval cache polymorphic. --- src/librustc/dep_graph/dep_node.rs | 4 +- src/librustc/middle/const_val.rs | 3 +- src/librustc/middle/cstore.rs | 10 +- src/librustc/ty/maps.rs | 32 ++++- src/librustc/ty/mod.rs | 6 +- src/librustc_const_eval/eval.rs | 185 ++++++++++++--------------- src/librustc_const_eval/pattern.rs | 11 +- src/librustc_metadata/cstore_impl.rs | 15 +-- src/librustc_metadata/decoder.rs | 19 ++- src/librustc_mir/hair/cx/expr.rs | 3 +- src/librustc_typeck/collect.rs | 3 +- src/librustdoc/clean/inline.rs | 2 +- src/test/compile-fail/const-call.rs | 2 - src/test/compile-fail/issue-39559.rs | 4 - 14 files changed, 150 insertions(+), 149 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 224e9751e73d..9a6574385222 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -97,7 +97,7 @@ pub enum DepNode { TypeckBodiesKrate, TypeckTables(D), UsedTraitImports(D), - MonomorphicConstEval(D), + ConstEval(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -233,7 +233,7 @@ impl DepNode { InherentImpls(ref d) => op(d).map(InherentImpls), TypeckTables(ref d) => op(d).map(TypeckTables), UsedTraitImports(ref d) => op(d).map(UsedTraitImports), - MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval), + ConstEval(ref d) => op(d).map(ConstEval), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), ReprHints(ref d) => op(d).map(ReprHints), diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index b4c5af940194..50f34723d501 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -227,7 +227,8 @@ pub fn eval_length(tcx: TyCtxt, { let count_expr = &tcx.hir.body(count).value; let count_def_id = tcx.hir.body_owner_def_id(count); - match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) { + let substs = Substs::empty(); + match ty::queries::const_eval::get(tcx, count_expr.span, (count_def_id, substs)) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 20ed2244e864..3251addcb328 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -249,8 +249,8 @@ pub trait CrateStore { fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body>; + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body; fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap; fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool; @@ -399,9 +399,9 @@ impl CrateStore for DummyCrateStore { fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body> { - bug!("maybe_get_item_body") + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body { + bug!("item_body") } fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap { bug!("item_body_nested_bodies") diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index add8db850e4f..4247bff0f502 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -16,6 +16,7 @@ use middle::privacy::AccessLevels; use mir; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use ty::subst::Substs; use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; @@ -74,6 +75,15 @@ impl Key for (CrateNum, DefId) { } } +impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { + fn map_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.0.default_span(tcx) + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -217,6 +227,13 @@ impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { } } +impl<'tcx> QueryDescription for queries::const_eval<'tcx> { + fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String { + format!("const-evaluating `{}`", + tcx.item_path_str(def_id)) + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -446,16 +463,17 @@ define_maps! { <'tcx> /// (Defined only for LOCAL_CRATE) pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (), - /// Results of evaluating monomorphic constants embedded in - /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>, + /// Results of evaluating const items or constants embedded in + /// other items (such as enum variant explicit discriminants). + pub const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>)) + -> const_val::EvalResult<'tcx>, /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, pub reachable_set: reachability_dep_node(CrateNum) -> Rc, - pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> + pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { @@ -470,10 +488,14 @@ fn reachability_dep_node(_: CrateNum) -> DepNode { DepNode::Reachability } -fn mir_shim(instance: ty::InstanceDef) -> DepNode { +fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode { DepNode::TypeckBodiesKrate } + +fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { + DepNode::ConstEval(def_id) +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1305b0d93037..1588773479c5 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1701,7 +1701,8 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.variants.iter().map(move |v| { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { - match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + let substs = Substs::empty(); + match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) { Ok(ConstVal::Integral(v)) => { discr = v; } @@ -1733,7 +1734,8 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_index -= distance; } ty::VariantDiscr::Explicit(expr_did) => { - match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + let substs = Substs::empty(); + match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) { Ok(ConstVal::Integral(v)) => { explicit_value = v; break; diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 9c5a669bef0d..37395ca78714 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -75,83 +75,34 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// /// `substs` is optional and is used for associated constants. /// This generally happens in late/trans const evaluation. -pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) - -> Option<(&'tcx Expr, - &'a ty::TypeckTables<'tcx>)> { +pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { match tcx.hir.find(node_id) { - None => None, - Some(hir_map::NodeItem(&hir::Item { - node: hir::ItemConst(_, body), .. - })) | - Some(hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Const(_, body), .. - })) => { - Some((&tcx.hir.body(body).value, - tcx.item_tables(def_id))) + Some(hir_map::NodeTraitItem(_)) => { + // If we have a trait item and the substitutions for it, + // `resolve_trait_associated_const` will select an impl + // or the default. + resolve_trait_associated_const(tcx, def_id, substs) } - Some(hir_map::NodeTraitItem(ti)) => match ti.node { - hir::TraitItemKind::Const(_, default) => { - // If we have a trait item and the substitutions for it, - // `resolve_trait_associated_const` will select an impl - // or the default. - let trait_id = tcx.hir.get_parent(node_id); - let trait_id = tcx.hir.local_def_id(trait_id); - let default_value = default.map(|body| { - (&tcx.hir.body(body).value, - tcx.item_tables(def_id)) - }); - resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs) - } - _ => None - }, - Some(_) => None + _ => Some((def_id, substs)) } } else { - let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (&body.value, tcx.item_tables(def_id)) - }); match tcx.sess.cstore.describe_def(def_id) { Some(Def::AssociatedConst(_)) => { - let trait_id = tcx.sess.cstore.trait_of_item(def_id); // As mentioned in the comments above for in-crate // constants, we only try to find the expression for a // trait-associated const if the caller gives us the // substitutions for the reference to it. - if let Some(trait_id) = trait_id { - resolve_trait_associated_const(tcx, def_id, expr_and_tables, - trait_id, substs) + if tcx.sess.cstore.trait_of_item(def_id).is_some() { + resolve_trait_associated_const(tcx, def_id, substs) } else { - expr_and_tables + Some((def_id, substs)) } - }, - Some(Def::Const(..)) => expr_and_tables, - _ => None - } - } -} - -fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)> -{ - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| { - if fn_like.constness() == hir::Constness::Const { - Some((tcx.hir.body(fn_like.body()), - tcx.item_tables(def_id))) - } else { - None } - }) - } else { - if tcx.sess.cstore.is_const_fn(def_id) { - tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (body, tcx.item_tables(def_id)) - }) - } else { - None + _ => Some((def_id, substs)) } } } @@ -357,21 +308,15 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, match cx.tables.qpath_def(qpath, e.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, TypeckError); - } + match ty::queries::const_eval::get(tcx, e.span, (def_id, substs)) { + Ok(val) => val, + Err(ConstEvalErr { kind: TypeckError, .. }) => { + signal!(e, TypeckError); + } + Err(err) => { + debug!("bad reference: {:?}, {:?}", err.description(), err.span); + signal!(e, ErroneousReferencedConstant(box err)) + }, }, Def::VariantCtor(variant_def, ..) => { if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) { @@ -407,14 +352,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprCall(ref callee, ref args) => { - let (did, substs) = match cx.eval(callee)? { - Function(did, substs) => (did, substs), - Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), + let (def_id, substs) = match cx.eval(callee)? { + Function(def_id, substs) => (def_id, substs), callee => signal!(e, CallOn(callee)), }; - let (body, tables) = match lookup_const_fn_by_id(tcx, did) { - Some(x) => x, - None => signal!(e, NonConstPath), + + let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { + if fn_like.constness() == hir::Constness::Const { + tcx.hir.body(fn_like.body()) + } else { + signal!(e, TypeckError) + } + } else { + signal!(e, TypeckError) + } + } else { + if tcx.sess.cstore.is_const_fn(def_id) { + tcx.sess.cstore.item_body(tcx, def_id) + } else { + signal!(e, TypeckError) + } }; let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node { @@ -434,7 +392,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, debug!("const call({:?})", call_args); let callee_cx = ConstContext { tcx: tcx, - tables: tables, + tables: tcx.item_tables(def_id), substs: substs, fn_args: Some(call_args) }; @@ -532,19 +490,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, Ok(result) } -fn resolve_trait_associated_const<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_item_id: DefId, - default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx> -) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> -{ - let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); +fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { + let trait_item = tcx.associated_item(def_id); + let trait_id = trait_item.container.id(); + let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs)); debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.populate_implementations_for_trait_if_necessary(trait_id); tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), @@ -569,12 +524,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - let name = tcx.associated_item(trait_item_id).name; + let name = trait_item.name; let ac = tcx.associated_items(impl_data.impl_def_id) .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); match ac { - Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()), - None => default_value, + // FIXME(eddyb) Use proper Instance resolution to + // get the correct Substs returned from here. + Some(ic) => Some((ic.def_id, Substs::empty())), + None => { + if trait_item.defaultness.has_value() { + Some((def_id, substs)) + } else { + None + } + } } } _ => { @@ -796,21 +759,35 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn provide(providers: &mut Providers) { *providers = Providers { - monomorphic_const_eval, + const_eval, ..*providers }; } -fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> EvalResult<'tcx> { - let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id)); +fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (def_id, substs): (DefId, &'tcx Substs<'tcx>)) + -> EvalResult<'tcx> { + let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) { + resolved + } else { + return Err(ConstEvalErr { + span: tcx.def_span(def_id), + kind: TypeckError + }); + }; + + let cx = ConstContext { + tcx, + tables: tcx.item_tables(def_id), + substs: substs, + fn_args: None + }; let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); tcx.hir.body(tcx.hir.body_owned_by(id)) } else { - tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap() + tcx.sess.cstore.item_body(tcx, def_id) }; cx.eval(&body.value) } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index f20fa27dc225..a470d549d05e 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -587,11 +587,16 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let substs = self.tables.node_id_item_substs(id) .unwrap_or_else(|| tcx.intern_substs(&[])); match eval::lookup_const_by_id(tcx, def_id, substs) { - Some((const_expr, const_tables)) => { + Some((def_id, _substs)) => { // Enter the inlined constant's tables temporarily. let old_tables = self.tables; - self.tables = const_tables; - let pat = self.lower_const_expr(const_expr, pat_id, span); + self.tables = tcx.item_tables(def_id); + let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { + tcx.hir.body(tcx.hir.body_owned_by(id)) + } else { + tcx.sess.cstore.item_body(tcx, def_id) + }; + let pat = self.lower_const_expr(&body.value, pat_id, span); self.tables = old_tables; return pat; } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cb1b0c4c0b78..9e6a45e7f8b7 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -420,19 +420,18 @@ impl CrateStore for cstore::CStore { }) } - fn maybe_get_item_body<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Option<&'tcx hir::Body> - { + fn item_body<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx hir::Body { if let Some(cached) = tcx.hir.get_inlined_body(def_id) { - return Some(cached); + return cached; } self.dep_graph.read(DepNode::MetaData(def_id)); - debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id)); + debug!("item_body({}): inlining item", tcx.item_path_str(def_id)); - self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index) + self.get_crate_data(def_id.krate).item_body(tcx, def_id.index) } fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 2d562aceb65c..a9eae5281b24 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -750,16 +750,15 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn maybe_get_item_body(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefIndex) - -> Option<&'tcx hir::Body> { - if self.is_proc_macro(id) { return None; } - self.entry(id).ast.map(|ast| { - let def_id = self.local_def_id(id); - let body = ast.decode(self).body.decode(self); - tcx.hir.intern_inlined_body(def_id, body) - }) + pub fn item_body(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) + -> &'tcx hir::Body { + assert!(!self.is_proc_macro(id)); + let ast = self.entry(id).ast.unwrap(); + let def_id = self.local_def_id(id); + let body = ast.decode(self).body.decode(self); + tcx.hir.intern_inlined_body(def_id, body) } pub fn item_body_tables(&self, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index b7de50efe344..736c076ea154 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -593,7 +593,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprRepeat(ref v, count) => { let c = &cx.tcx.hir.body(count).value; let def_id = cx.tcx.hir.body_owner_def_id(count); - let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) { + let substs = Substs::empty(); + let count = match ty::queries::const_eval::get(cx.tcx, c.span, (def_id, substs)) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1f2310c49e3a..660ce837043c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -555,7 +555,8 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); - let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did); + let substs = Substs::empty(); + let result = ty::queries::const_eval::get(tcx, variant.span, (expr_did, substs)); // enum variant evaluation happens before the global constant check // so we need to report the real error diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc30fdf56fc3..6016fd488f56 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -487,7 +487,7 @@ impl hir::print::PpAnn for InlinedConst { } fn print_inlined_const(cx: &DocContext, did: DefId) -> String { - let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap(); + let body = cx.tcx.sess.cstore.item_body(cx.tcx, did); let inlined = InlinedConst { nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did) }; diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index ff83dd004a25..0745ac02d072 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -17,6 +17,4 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error [E0080] - //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs index 06e8406cbc0b..b7f767f109c0 100644 --- a/src/test/compile-fail/issue-39559.rs +++ b/src/test/compile-fail/issue-39559.rs @@ -28,10 +28,6 @@ pub struct Vector { fn main() { let array: [usize; Dim3::dim()] //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error - //~| non-constant path in constant expression = [0; Dim3::dim()]; //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error - //~| non-constant path in constant expression } From 0ff828baa06504c91e38dfda53ead61cc44ad171 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 19 Apr 2017 15:15:12 +0300 Subject: [PATCH 655/905] rustc_const_eval: CallOn isn't needed, typeck/const-qualif handle those cases. --- src/librustc/middle/const_val.rs | 2 -- src/librustc_const_eval/eval.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 50f34723d501..b65dbdbbcc25 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -85,7 +85,6 @@ pub enum ErrKind<'tcx> { MissingStructField, NegateOn(ConstVal<'tcx>), NotOn(ConstVal<'tcx>), - CallOn(ConstVal<'tcx>), NonConstPath, UnimplementedConstVal(&'static str), @@ -145,7 +144,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { CannotCast => simple!("can't cast this type"), NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), NotOn(ref const_val) => simple!("not on {}", const_val.description()), - CallOn(ref const_val) => simple!("call on {}", const_val.description()), MissingStructField => simple!("nonexistent struct field"), NonConstPath => simple!("non-constant path in constant expression"), diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 37395ca78714..5c421df92c7e 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -354,7 +354,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::ExprCall(ref callee, ref args) => { let (def_id, substs) = match cx.eval(callee)? { Function(def_id, substs) => (def_id, substs), - callee => signal!(e, CallOn(callee)), + _ => signal!(e, TypeckError), }; let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { From 8054377f8f4dfaf766bcff40e7a720c90c5e33be Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 19 Apr 2017 15:16:19 +0300 Subject: [PATCH 656/905] rustc_const_eval: support all unit enum variants. --- src/librustc/ich/impls_ty.rs | 9 ++- src/librustc/middle/const_val.rs | 6 +- src/librustc/mir/mod.rs | 3 +- src/librustc/ty/mod.rs | 19 ++++- src/librustc_const_eval/eval.rs | 77 ++++++++----------- src/librustc_const_eval/pattern.rs | 8 +- src/librustc_trans/mir/constant.rs | 8 +- .../const-pattern-not-const-evaluable.rs | 11 +-- src/test/compile-fail/issue-41394.rs | 20 +++++ src/test/run-pass/auxiliary/issue-41394.rs | 26 +++++++ src/test/run-pass/const-pattern-variant.rs | 38 +++++++++ .../issue-23898.rs} | 5 +- src/test/run-pass/issue-41394.rs | 17 ++++ 13 files changed, 180 insertions(+), 67 deletions(-) create mode 100644 src/test/compile-fail/issue-41394.rs create mode 100644 src/test/run-pass/auxiliary/issue-41394.rs create mode 100644 src/test/run-pass/const-pattern-variant.rs rename src/test/{compile-fail/non-constant-enum-for-vec-repeat.rs => run-pass/issue-23898.rs} (73%) create mode 100644 src/test/run-pass/issue-41394.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f55462fb5deb..16af98c20354 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -273,6 +273,12 @@ for ::middle::const_val::ConstVal<'tcx> { ConstVal::Bool(value) => { value.hash_stable(hcx, hasher); } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Variant(def_id) => { + def_id.hash_stable(hcx, hasher); + } ConstVal::Function(def_id, substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); @@ -296,9 +302,6 @@ for ::middle::const_val::ConstVal<'tcx> { value.hash_stable(hcx, hasher); times.hash_stable(hcx, hasher); } - ConstVal::Char(value) => { - value.hash_stable(hcx, hasher); - } } } } diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index b65dbdbbcc25..ec7b3c4dd8df 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> { Str(InternedString), ByteStr(Rc>), Bool(bool), + Char(char), + Variant(DefId), Function(DefId, &'tcx Substs<'tcx>), Struct(BTreeMap>), Tuple(Vec>), Array(Vec>), Repeat(Box>, u64), - Char(char), } impl<'tcx> ConstVal<'tcx> { @@ -54,12 +55,13 @@ impl<'tcx> ConstVal<'tcx> { Str(_) => "string literal", ByteStr(_) => "byte string literal", Bool(_) => "boolean", + Char(..) => "char", + Variant(_) => "enum variant", Struct(_) => "struct", Tuple(_) => "tuple", Function(..) => "function definition", Array(..) => "array", Repeat(..) => "repeat", - Char(..) => "char", } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9ff64b295b76..bfb72b5df7b2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1307,10 +1307,11 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { write!(fmt, "b\"{}\"", escaped) } Bool(b) => write!(fmt, "{:?}", b), + Char(c) => write!(fmt, "{:?}", c), + Variant(def_id) | Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Struct(_) | Tuple(_) | Array(_) | Repeat(..) => bug!("ConstVal `{:?}` should not be in MIR", const_val), - Char(c) => write!(fmt, "{:?}", c), } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1588773479c5..cc5eb768d9b3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1693,6 +1693,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + #[inline] pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator + 'a { let repr_type = self.repr.discr_type(); @@ -1706,7 +1707,13 @@ impl<'a, 'gcx, 'tcx> AdtDef { Ok(ConstVal::Integral(v)) => { discr = v; } - _ => {} + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + } } } prev_discr = Some(discr); @@ -1740,7 +1747,15 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_value = v; break; } - _ => { + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + if explicit_index == 0 { + break; + } explicit_index -= 1; } } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 5c421df92c7e..e9352f53c92d 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -15,7 +15,7 @@ use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind}; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::traits; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; @@ -48,28 +48,6 @@ macro_rules! math { } } -fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - variant_def: DefId) - -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> { - if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) { - let enum_node_id = tcx.hir.get_parent(variant_node_id); - if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) { - if let hir::ItemEnum(ref edef, _) = it.node { - for variant in &edef.variants { - if variant.node.data.id() == variant_node_id { - return variant.node.disr_expr.map(|e| { - let def_id = tcx.hir.body_owner_def_id(e); - (&tcx.hir.body(e).value, - tcx.item_tables(def_id)) - }); - } - } - } - } - } - None -} - /// * `def_id` is the id of the constant. /// * `substs` is the monomorphized substitutions for the expression. /// @@ -289,9 +267,22 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprCast(ref base, _) => { - match cast_const(tcx, cx.eval(base)?, ety) { - Ok(val) => val, - Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), + let base_val = cx.eval(base)?; + let base_ty = cx.tables.expr_ty(base); + + // Avoid applying substitutions if they're empty, that'd ICE. + let base_ty = if cx.substs.is_empty() { + base_ty + } else { + base_ty.subst(tcx, cx.substs) + }; + if ety == base_ty { + base_val + } else { + match cast_const(tcx, base_val, ety) { + Ok(val) => val, + Err(kind) => signal!(e, kind), + } } } hir::ExprPath(ref qpath) => { @@ -317,27 +308,20 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, debug!("bad reference: {:?}, {:?}", err.description(), err.span); signal!(e, ErroneousReferencedConstant(box err)) }, + } }, - Def::VariantCtor(variant_def, ..) => { - if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, UnimplementedConstVal("enum variants")); - } + Def::VariantCtor(variant_def, CtorKind::Const) => { + Variant(variant_def) } - Def::StructCtor(..) => { + Def::VariantCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("enum variants")); + } + Def::StructCtor(_, CtorKind::Const) => { ConstVal::Struct(Default::default()) } + Def::StructCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("tuple struct constructors")) + } Def::Local(def_id) => { debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args); if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) { @@ -578,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, U8(u) => Ok(Char(u as char)), _ => bug!(), }, - _ => bug!(), + _ => Err(CannotCast), } } @@ -622,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Bool(b) => cast_const_int(tcx, U8(b as u8), ty), Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, U32(c as u32), ty), + Variant(v) => { + let adt = tcx.lookup_adt_def(tcx.parent_def_id(v).unwrap()); + let idx = adt.variant_index_with_id(v); + cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty) + } Function(..) => Err(UnimplementedConstVal("casting fn pointers")), ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a470d549d05e..0dfafeb6fb83 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Variant(_) | ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Function(..) | @@ -620,7 +621,12 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables); match const_cx.eval(expr) { Ok(value) => { - PatternKind::Constant { value: value } + if let ConstVal::Variant(def_id) = value { + let ty = self.tables.expr_ty(expr); + self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![]) + } else { + PatternKind::Constant { value: value } + } } Err(e) => { self.errors.push(PatternError::ConstEval(e)); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index e938913a3f11..040194e63d07 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -100,15 +100,13 @@ impl<'tcx> Const<'tcx> { ConstVal::Integral(ref i) => return Const::from_constint(ccx, i), ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()), ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"), + ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), + ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)), + ConstVal::Variant(_) | ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Array(..) | ConstVal::Repeat(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } - ConstVal::Function(..) => { - let llty = type_of::type_of(ccx, ty); - return Const::new(C_null(llty), ty); - } - ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), }; assert!(!ty.has_erasable_regions()); diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index b40aa2a8e27d..71cac3edbc18 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -10,21 +10,22 @@ #![feature(const_fn)] +#[derive(PartialEq, Eq)] enum Cake { BlackForest, Marmor, } use Cake::*; -const BOO: (Cake, Cake) = (Marmor, BlackForest); +struct Pair(A, B); + +const BOO: Pair = Pair(Marmor, BlackForest); //~^ ERROR: constant evaluation error [E0080] -//~| unimplemented constant expression: enum variants +//~| unimplemented constant expression: tuple struct constructors const FOO: Cake = BOO.1; const fn foo() -> Cake { Marmor - //~^ ERROR: constant evaluation error [E0080] - //~| unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; @@ -34,7 +35,7 @@ const GOO: Cake = foo(); fn main() { match BlackForest { FOO => println!("hi"), //~ NOTE: for pattern here - GOO => println!("meh"), //~ NOTE: for pattern here + GOO => println!("meh"), WORKS => println!("mΓΆp"), _ => println!("bye"), } diff --git a/src/test/compile-fail/issue-41394.rs b/src/test/compile-fail/issue-41394.rs new file mode 100644 index 000000000000..1fb3b7c4ee12 --- /dev/null +++ b/src/test/compile-fail/issue-41394.rs @@ -0,0 +1,20 @@ +// 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. + +enum Foo { + A = "" + 1 + //~^ ERROR binary operation `+` cannot be applied to type `&'static str` +} + +enum Bar { + A = Foo::A as isize +} + +fn main() {} diff --git a/src/test/run-pass/auxiliary/issue-41394.rs b/src/test/run-pass/auxiliary/issue-41394.rs new file mode 100644 index 000000000000..f06b81279ac4 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-41394.rs @@ -0,0 +1,26 @@ +// 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. + +#![crate_type = "lib"] + +#[repr(u32)] +pub enum Foo { + Foo = Private::Variant as u32 +} + +#[repr(u8)] +enum Private { + Variant = 42 +} + +#[inline(always)] +pub fn foo() -> Foo { + Foo::Foo +} diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs new file mode 100644 index 000000000000..104ab6e19db6 --- /dev/null +++ b/src/test/run-pass/const-pattern-variant.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. + +#![feature(const_fn)] + +#[derive(PartialEq, Eq)] +enum Cake { + BlackForest, + Marmor, +} +use Cake::*; + +const BOO: (Cake, Cake) = (Marmor, BlackForest); +const FOO: Cake = BOO.1; + +const fn foo() -> Cake { + Marmor +} + +const WORKS: Cake = Marmor; + +const GOO: Cake = foo(); + +fn main() { + match BlackForest { + FOO => println!("hi"), + GOO => println!("meh"), + WORKS => println!("mΓΆp"), + _ => println!("bye"), + } +} diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/run-pass/issue-23898.rs similarity index 73% rename from src/test/compile-fail/non-constant-enum-for-vec-repeat.rs rename to src/test/run-pass/issue-23898.rs index cadfec5a38d3..3f5546ce83dd 100644 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ b/src/test/run-pass/issue-23898.rs @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Note: This test is checking that we forbid a coding pattern that -// Issue #5873 explicitly wants to allow. +// Note: This test was used to demonstrate #5873 (now #23898). enum State { ST_NULL, ST_WHITESPACE } fn main() { [State::ST_NULL; (State::ST_WHITESPACE as usize)]; - //~^ ERROR constant evaluation error - //~| unimplemented constant expression: enum variants } diff --git a/src/test/run-pass/issue-41394.rs b/src/test/run-pass/issue-41394.rs new file mode 100644 index 000000000000..798905599a85 --- /dev/null +++ b/src/test/run-pass/issue-41394.rs @@ -0,0 +1,17 @@ +// 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. + +// aux-build:issue-41394.rs + +extern crate issue_41394 as lib; + +fn main() { + assert_eq!(lib::foo() as u32, 42); +} From 5412587910f573c5d522b79a4808a1289ebea51c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 21 Apr 2017 20:24:32 +0300 Subject: [PATCH 657/905] clean-up adt_sized_constraint now that it uses on-demand --- src/librustc/traits/select.rs | 8 ++--- src/librustc/ty/maps.rs | 2 +- src/librustc/ty/mod.rs | 60 ++++++++++------------------------- 3 files changed, 21 insertions(+), 49 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6442487ead95..e61e57437906 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1790,11 +1790,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(ty::Binder(match sized_crit.sty { - ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs), - ty::TyBool => vec![], - _ => vec![sized_crit.subst(self.tcx(), substs)] - })) + Where(ty::Binder( + sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() + )) } ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4247bff0f502..693dd00574fe 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -396,7 +396,7 @@ define_maps! { <'tcx> pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef, pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef, pub adt_destructor: AdtDestructor(DefId) -> Option, - pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>, + pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], /// True if this is a foreign item (i.e., linked via `extern { ... }`). pub is_foreign_item: IsForeignItem(DefId) -> bool, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index cc5eb768d9b3..946c55f94060 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1780,16 +1780,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { queries::adt_destructor::get(tcx, DUMMY_SP, self.did) } - /// Returns a simpler type such that `Self: Sized` if and only + /// Returns a list of types such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. /// - /// HACK: instead of returning a list of types, this function can - /// return a tuple. In that case, the result is Sized only if - /// all elements of the tuple are Sized. - /// - /// This is generally the `struct_tail` if this is a struct, or a - /// tuple of them if this is an enum. - /// /// Oddly enough, checking that the sized-constraint is Sized is /// actually more expressive than checking all members: /// the Sized trait is inductive, so an associated type that references @@ -1797,16 +1790,16 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. - pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) { - Ok(ty) => ty, + Ok(tys) => tys, Err(_) => { debug!("adt_sized_constraint: {:?} is recursive", self); // This should be reported as an error by `check_representable`. // // Consider the type as Sized in the meanwhile to avoid // further errors. - tcx.types.err + tcx.intern_type_list(&[tcx.types.err]) } } } @@ -1836,18 +1829,13 @@ impl<'a, 'gcx, 'tcx> AdtDef { TyAdt(adt, substs) => { // recursive case - let adt_ty = - adt.sized_constraint(tcx) - .subst(tcx, substs); + let adt_tys = adt.sized_constraint(tcx); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", - ty, adt_ty); - if let ty::TyTuple(ref tys, _) = adt_ty.sty { - tys.iter().flat_map(|ty| { - self.sized_constraint_for_ty(tcx, ty) - }).collect() - } else { - self.sized_constraint_for_ty(tcx, adt_ty) - } + ty, adt_tys); + adt_tys.iter() + .map(|ty| ty.subst(tcx, substs)) + .flat_map(|ty| self.sized_constraint_for_ty(tcx, ty)) + .collect() } TyProjection(..) | TyAnon(..) => { @@ -2697,13 +2685,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) /// Calculates the Sized-constraint. /// -/// As the Sized-constraint of enums can be a *set* of types, -/// the Sized-constraint may need to be a set also. Because introducing -/// a new type of IVar is currently a complex affair, the Sized-constraint -/// may be a tuple. -/// -/// In fact, there are only a few options for the constraint: -/// - `bool`, if the type is always Sized +/// In fact, there are only a few options for the types in the constraint: /// - an obviously-unsized type /// - a type parameter or projection whose Sizedness can't be known /// - a tuple of type parameters or projections, if there are multiple @@ -2712,26 +2694,18 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) /// check should catch this case. fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Ty<'tcx> { + -> &'tcx [Ty<'tcx>] { let def = tcx.lookup_adt_def(def_id); - let tys: Vec<_> = def.variants.iter().flat_map(|v| { + let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { v.fields.last() }).flat_map(|f| { - let ty = tcx.item_type(f.did); - def.sized_constraint_for_ty(tcx, ty) - }).collect(); + def.sized_constraint_for_ty(tcx, tcx.item_type(f.did)) + }).collect::>()); - let ty = match tys.len() { - _ if tys.references_error() => tcx.types.err, - 0 => tcx.types.bool, - 1 => tys[0], - _ => tcx.intern_tup(&tys[..], false) - }; + debug!("adt_sized_constraint: {:?} => {:?}", def, result); - debug!("adt_sized_constraint: {:?} => {:?}", def, ty); - - ty + result } fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, From 167b7eb8b518e32c11aaae9678f8b095f834045c Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Mon, 20 Mar 2017 17:35:57 +0100 Subject: [PATCH 658/905] FIN: update to upstream (llvm 4.0.1 + fastcomp 1.37.10) & compiler-rt 4.0 --- src/compiler-rt | 2 +- src/llvm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler-rt b/src/compiler-rt index d30da544a8af..1fdc27db84c9 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 +Subproject commit 1fdc27db84c9d0d9ae4ae60185629e8c43b4a11c diff --git a/src/llvm b/src/llvm index 2e951c3ae354..c9bf6e3f9855 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 2e951c3ae354bcbd2e50b30798e232949a926b75 +Subproject commit c9bf6e3f98557937df93b24c48b2564c6963e788 From 4fcfab16d340f61c37b9e2ffc5233ed1eb4ad00f Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 23 Apr 2017 20:21:02 +0200 Subject: [PATCH 659/905] FIN/LLVM: adopt all applicable rust llvm patches --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index c9bf6e3f9855..fb3c57828dc9 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit c9bf6e3f98557937df93b24c48b2564c6963e788 +Subproject commit fb3c57828dc9df51f84967292cc551b7a3564465 From aaa307ce47742375f41f1b5bb112ab9f5881e150 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 23 Apr 2017 20:50:28 +0200 Subject: [PATCH 660/905] FIN/LLVM: new rust patches required for 4.0 --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index fb3c57828dc9..a884d21cc5f0 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit fb3c57828dc9df51f84967292cc551b7a3564465 +Subproject commit a884d21cc5f0b23a1693d1e872fd8998a4fdd17f From f622542b6498a9b4a0ab2a5fdcd80e1261ff8208 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 23 Apr 2017 21:58:44 +0200 Subject: [PATCH 661/905] FIN/CRT: adopt all applicable rust compiler-rt patches --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index 1fdc27db84c9..c8a8767c56ad 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit 1fdc27db84c9d0d9ae4ae60185629e8c43b4a11c +Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 From a0ce63be2b5d73411f733509a12702ccec2d173b Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Mon, 20 Mar 2017 17:42:25 +0100 Subject: [PATCH 662/905] FIN: update emscripten builder --- src/ci/docker/emscripten/Dockerfile | 6 +++--- src/ci/docker/emscripten/build-emscripten.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index ffdb1d18a94e..cbbca23f6e3d 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -27,10 +27,10 @@ WORKDIR /tmp COPY build-emscripten.sh /tmp/ RUN ./build-emscripten.sh ENV PATH=$PATH:/tmp/emsdk_portable -ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.1/build_tag-e1.37.1_32/bin +ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.10/build_tag-e1.37.10_32/bin ENV PATH=$PATH:/tmp/emsdk_portable/node/4.1.1_32bit/bin -ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.1 -ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.1 +ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.10 +ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.10 ENV RUST_CONFIGURE_ARGS --target=asmjs-unknown-emscripten diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh index e39767357ad6..8d6a28f418bf 100755 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ b/src/ci/docker/emscripten/build-emscripten.sh @@ -49,5 +49,5 @@ chmod 755 emsdk_portable source emsdk_portable/emsdk_env.sh hide_output emsdk update -hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit -hide_output emsdk activate --build=Release sdk-tag-1.37.1-32bit +hide_output emsdk install --build=Release sdk-tag-1.37.10-32bit +hide_output emsdk activate --build=Release sdk-tag-1.37.10-32bit From a146431e4c8095a3d809517c8abc6b886d5c5b07 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 2 Apr 2017 11:24:22 +0200 Subject: [PATCH 663/905] FIN: disable backtrace printing for panic-runtime/abort* on ARM --- .../panic-runtime/abort-link-to-unwinding-crates.rs | 12 +++++++++++- src/test/run-pass/panic-runtime/abort.rs | 11 ++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs index 1c273fcba02d..ebbb00a4a9f2 100644 --- a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs +++ b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs @@ -27,7 +27,17 @@ fn main() { exit_success_if_unwind::bar(do_panic); } } - let s = Command::new(env::args_os().next().unwrap()).arg("foo").status(); + + let mut cmd = Command::new(env::args_os().next().unwrap()); + cmd.arg("foo"); + + + // ARMv6 hanges while printing the backtrace, see #41004 + if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") { + cmd.env("RUST_BACKTRACE", "0"); + } + + let s = cmd.status(); assert!(s.unwrap().code() != Some(0)); } diff --git a/src/test/run-pass/panic-runtime/abort.rs b/src/test/run-pass/panic-runtime/abort.rs index be38f6ea3643..3ba3bd61c2e8 100644 --- a/src/test/run-pass/panic-runtime/abort.rs +++ b/src/test/run-pass/panic-runtime/abort.rs @@ -35,6 +35,15 @@ fn main() { panic!("try to catch me"); } } - let s = Command::new(env::args_os().next().unwrap()).arg("foo").status(); + + let mut cmd = Command::new(env::args_os().next().unwrap()); + cmd.arg("foo"); + + // ARMv6 hanges while printing the backtrace, see #41004 + if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") { + cmd.env("RUST_BACKTRACE", "0"); + } + + let s = cmd.status(); assert!(s.unwrap().code() != Some(0)); } From 5ae4a58c339a935fd098ba6ea8315af444113276 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 2 Apr 2017 12:36:20 +0200 Subject: [PATCH 664/905] FIN: build comiler-rt wihout Thumb on arm --- src/libcompiler_builtins/build.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index bcd3a92dd430..8fe79057bd81 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -293,6 +293,12 @@ fn main() { } if target.contains("arm") && !target.contains("ios") { + // (At least) udivsi3.S is broken for Thumb 1 which our gcc uses by + // default, we don't want Thumb 2 since it isn't supported on some + // devices, so disable thumb entirely. + // Upstream bug: https://bugs.llvm.org/show_bug.cgi?id=32492 + cfg.define("__ARM_ARCH_ISA_THUMB", Some("0")); + sources.extend(&["arm/aeabi_cdcmp.S", "arm/aeabi_cdcmpeq_check_nan.c", "arm/aeabi_cfcmp.S", From 5bd4e27db235bb857066e43384d483aa9dbdf56e Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 14 Apr 2017 11:27:35 +0200 Subject: [PATCH 665/905] FIN: update appveyor mingw description --- appveyor.yml | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 83cfea0dd834..450a489f0b1e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,28 +20,17 @@ environment: # 32/64-bit MinGW builds. # - # The MinGW builds unfortunately have to both download a custom toolchain and - # avoid the one installed by AppVeyor by default. Interestingly, though, for - # different reasons! + # We are using MinGW with posix threads since LLVM does not compile with + # the win32 threads version due to missing support for C++'s std::thread. # - # For 32-bit the installed gcc toolchain on AppVeyor uses the pthread - # threading model. This is unfortunately not what we want, and if we compile - # with it then there's lots of link errors in the standard library (undefined - # references to pthread symbols). - # - # For 64-bit the installed gcc toolchain is currently 5.3.0 which - # unfortunately segfaults on Windows with --enable-llvm-assertions (segfaults - # in LLVM). See rust-lang/rust#28445 for more information, but to work around - # this we go back in time to 4.9.2 specifically. + # Instead of relying on the MinGW version installed on appveryor we download + # and install one ourselves so we won't be surprised by changes to appveyor's + # build image. # # Finally, note that the downloads below are all in the `rust-lang-ci` S3 # bucket, but they cleraly didn't originate there! The downloads originally # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - # - # And as a final point of note, the 32-bit MinGW build using the makefiles do - # *not* use debug assertions and llvm assertions. This is because they take - # too long on appveyor and this is tested by rustbuild below. - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test From 6723e69a54947f7929e4d30f9f3e549ffd51e7b6 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 14 Apr 2017 11:29:05 +0200 Subject: [PATCH 666/905] FIN: ignore failing test on emscripten, see #41299 --- src/test/run-pass/issue-29663.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-pass/issue-29663.rs b/src/test/run-pass/issue-29663.rs index 9a77be049fee..cf925662fc3f 100644 --- a/src/test/run-pass/issue-29663.rs +++ b/src/test/run-pass/issue-29663.rs @@ -10,6 +10,8 @@ // write_volatile causes an LLVM assert with composite types +// ignore-emscripten See #41299: probably a bad optimization + #![feature(volatile)] use std::ptr::{read_volatile, write_volatile}; From 67560f6fae7c4c6ae7f1f78a9ba17f5e0d9f9037 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Fri, 14 Apr 2017 11:27:56 +0200 Subject: [PATCH 667/905] FIN: switch appveryor to mingw with posix threads --- appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 450a489f0b1e..f8e4a30e152a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,13 +35,13 @@ environment: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.2.0-release-posix-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.2.0-release-posix-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 # 32/64 bit MSVC and GNU deployment @@ -60,14 +60,14 @@ environment: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja SCRIPT: python x.py dist MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.2.0-release-posix-dwarf-rt_v5-rev1.7z MINGW_DIR: mingw32 DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.2.0-release-posix-seh-rt_v5-rev1.7z MINGW_DIR: mingw64 DEPLOY: 1 From f3dda17469bd70feaf6a1d979cdc65dd450f8fcb Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Mon, 17 Apr 2017 10:24:33 +0200 Subject: [PATCH 668/905] FIN: Compile LLVM with -fno-omit-frame-pointer on 32bit MinGW builds to work around an apparently bad optimization. --- src/bootstrap/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84254d7d6ae5..27d4e309a752 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -874,6 +874,13 @@ impl Build { if target.contains("apple-darwin") { base.push("-stdlib=libc++".into()); } + + // Work around an apparently bad MinGW / GCC optimization, + // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html + // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936 + if target == "i686-pc-windows-gnu" { + base.push("-fno-omit-frame-pointer".into()); + } return base } From 899427765760068163c811fbe9e02ff953638698 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 13 Apr 2017 22:27:53 +0200 Subject: [PATCH 669/905] FIN: windows-gnu: statically link gcc_s, pthread with llvm --- src/librustc_llvm/build.rs | 4 ++++ src/librustc_llvm/lib.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 7d5887e699fd..7ef9031734a7 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -265,4 +265,8 @@ fn main() { if target.contains("windows") { println!("cargo:rustc-link-lib=ole32"); } + if target.contains("windows-gnu") { + println!("cargo:rustc-link-lib=static-nobundle=gcc_s"); + println!("cargo:rustc-link-lib=static-nobundle=pthread"); + } } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index f300bf16145a..7c52ceae459c 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,6 +29,7 @@ #![feature(link_args)] #![feature(staged_api)] #![feature(rustc_private)] +#![feature(static_nobundle)] extern crate libc; #[macro_use] From eadb049799162fc5265f404bd4c6671d223e5dd2 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 23 Apr 2017 23:05:25 +0300 Subject: [PATCH 670/905] traits::select: quickly filter out predicates from other traits this improves most pre-trans passes's performance by ~1%. --- src/librustc/traits/select.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6442487ead95..6dbf861d278d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1300,8 +1300,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .iter() .filter_map(|o| o.to_opt_poly_trait_ref()); + // micro-optimization: filter out predicates relating to different + // traits. let matching_bounds = - all_bounds.filter( + all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + + let matching_bounds = + matching_bounds.filter( |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); let param_candidates = From d3476f4b7694b8453cf52268880057a9df938089 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 23 Apr 2017 17:43:23 +0300 Subject: [PATCH 671/905] cache ADT dtorck results This avoids visiting the fields of all structs multiple times, improving item-bodies checking time by 10% (!). --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/diagnostics.rs | 1 + src/librustc/ty/maps.rs | 8 + src/librustc/ty/mod.rs | 100 +++++-- src/librustc/ty/util.rs | 164 +++++++++- src/librustc_typeck/check/dropck.rs | 414 +++----------------------- src/librustc_typeck/check/regionck.rs | 9 +- src/librustc_typeck/diagnostics.rs | 1 - 8 files changed, 300 insertions(+), 399 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 9a6574385222..33133f6834b9 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -91,6 +91,7 @@ pub enum DepNode { IsForeignItem(D), TypeParamPredicates((D, D)), SizedConstraint(D), + DtorckConstraint(D), AdtDestructor(D), AssociatedItemDefIds(D), InherentImpls(D), @@ -228,6 +229,7 @@ impl DepNode { Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param))))) } SizedConstraint(ref d) => op(d).map(SizedConstraint), + DtorckConstraint(ref d) => op(d).map(DtorckConstraint), AdtDestructor(ref d) => op(d).map(AdtDestructor), AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 2851191dc141..30e9f502abc8 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1829,6 +1829,7 @@ register_diagnostics! { E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes + E0320, // recursive overflow during dropck E0473, // dereference of reference outside its lifetime E0474, // captured variable `..` does not outlive the enclosing closure E0475, // index of slice outside its lifetime diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 693dd00574fe..4595a8c4f778 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -107,6 +107,13 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { } } + +impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> { + fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + Self::empty() + } +} + pub struct CycleError<'a, 'tcx: 'a> { span: Span, cycle: RefMut<'a, [(Span, Query<'tcx>)]>, @@ -397,6 +404,7 @@ define_maps! { <'tcx> pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef, pub adt_destructor: AdtDestructor(DefId) -> Option, pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + pub adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, /// True if this is a foreign item (i.e., linked via `extern { ... }`). pub is_foreign_item: IsForeignItem(DefId) -> bool, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 946c55f94060..352b6ab1d356 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -31,13 +31,15 @@ use ty; use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use util::common::ErrorReported; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; use std::cell::{Cell, RefCell, Ref}; use std::collections::BTreeMap; use std::cmp; use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; use std::ops::Deref; use std::rc::Rc; use std::slice; @@ -1332,17 +1334,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { pub struct Destructor { /// The def-id of the destructor method pub did: DefId, - /// Invoking the destructor of a dtorck type during usual cleanup - /// (e.g. the glue emitted for stack unwinding) requires all - /// lifetimes in the type-structure of `adt` to strictly outlive - /// the adt value itself. - /// - /// If `adt` is not dtorck, then the adt's destructor can be - /// invoked even when there are lifetimes in the type-structure of - /// `adt` that do not strictly outlive the adt value itself. - /// (This allows programs to make cyclic structures without - /// resorting to unsafe means; see RFCs 769 and 1238). - pub is_dtorck: bool, } bitflags! { @@ -1609,14 +1600,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } - /// Returns whether this is a dtorck type. If this returns - /// true, this type being safe for destruction requires it to be - /// alive; Otherwise, only the contents are required to be. - #[inline] - pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool { - self.destructor(tcx).map_or(false, |d| d.is_dtorck) - } - /// Returns whether this type is #[fundamental] for the purposes /// of coherence checking. #[inline] @@ -2708,6 +2691,38 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result } +/// Calculates the dtorck constraint for a type. +fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> DtorckConstraint<'tcx> { + let def = tcx.lookup_adt_def(def_id); + let span = tcx.def_span(def_id); + debug!("dtorck_constraint: {:?}", def); + + if def.is_phantom_data() { + let result = DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ + tcx.mk_param_from_def(&tcx.item_generics(def_id).types[0]) + ] + }; + debug!("dtorck_constraint: {:?} => {:?}", def, result); + return result; + } + + let mut result = def.all_fields() + .map(|field| tcx.item_type(field.did)) + .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty)) + .collect::>() + .unwrap_or(DtorckConstraint::empty()); + result.outlives.extend(tcx.destructor_constraints(def)); + result.dedup(); + + debug!("dtorck_constraint: {:?} => {:?}", def, result); + + result +} + fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Rc> { @@ -2736,6 +2751,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { associated_item, associated_item_def_ids, adt_sized_constraint, + adt_dtorck_constraint, ..*providers }; } @@ -2743,6 +2759,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { pub fn provide_extern(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { adt_sized_constraint, + adt_dtorck_constraint, ..*providers }; } @@ -2758,3 +2775,46 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) { pub struct CrateInherentImpls { pub inherent_impls: DefIdMap>>, } + +/// A set of constraints that need to be satisfied in order for +/// a type to be valid for destruction. +#[derive(Clone, Debug)] +pub struct DtorckConstraint<'tcx> { + /// Types that are required to be alive in order for this + /// type to be valid for destruction. + pub outlives: Vec>, + /// Types that could not be resolved: projections and params. + pub dtorck_types: Vec>, +} + +impl<'tcx> FromIterator> for DtorckConstraint<'tcx> +{ + fn from_iter>>(iter: I) -> Self { + let mut result = Self::empty(); + + for constraint in iter { + result.outlives.extend(constraint.outlives); + result.dtorck_types.extend(constraint.dtorck_types); + } + + result + } +} + + +impl<'tcx> DtorckConstraint<'tcx> { + fn empty() -> DtorckConstraint<'tcx> { + DtorckConstraint { + outlives: vec![], + dtorck_types: vec![] + } + } + + fn dedup<'a>(&mut self) { + let mut outlives = FxHashSet(); + let mut dtorck_types = FxHashSet(); + + self.outlives.retain(|&val| outlives.replace(val).is_none()); + self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none()); + } +} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index cdf3cf00b24e..f68cf6f97f85 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -19,6 +19,7 @@ use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; +use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; use util::nodemap::{FxHashMap, FxHashSet}; @@ -385,6 +386,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { None => return None, }; + Some(ty::Destructor { did: dtor_did }) + } + + /// Return the set of types that are required to be alive in + /// order to run the destructor of `def` (see RFCs 769 and + /// 1238). + /// + /// Note that this returns only the constraints for the + /// destructor of `def` itself. For the destructors of the + /// contents, you need `adt_dtorck_constraint`. + pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) + -> Vec> + { + let dtor = match def.destructor(self) { + None => { + debug!("destructor_constraints({:?}) - no dtor", def.did); + return vec![] + } + Some(dtor) => dtor.did + }; + // RFC 1238: if the destructor method is tagged with the // attribute `unsafe_destructor_blind_to_params`, then the // compiler is being instructed to *assume* that the @@ -394,11 +416,147 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Such access can be in plain sight (e.g. dereferencing // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden // (e.g. calling `foo.0.clone()` of `Foo`). - let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params"); - Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck }) + if self.has_attr(dtor, "unsafe_destructor_blind_to_params") { + debug!("destructor_constraint({:?}) - blind", def.did); + return vec![]; + } + + let impl_def_id = self.associated_item(dtor).container.id(); + let impl_generics = self.item_generics(impl_def_id); + + // We have a destructor - all the parameters that are not + // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute) + // must be live. + + // We need to return the list of parameters from the ADTs + // generics/substs that correspond to impure parameters on the + // impl's generics. This is a bit ugly, but conceptually simple: + // + // Suppose our ADT looks like the following + // + // struct S(X, Y, Z); + // + // and the impl is + // + // impl<#[may_dangle] P0, P1, P2> Drop for S + // + // We want to return the parameters (X, Y). For that, we match + // up the item-substs with the substs on the impl ADT, + // , and then look up which of the impl substs refer to + // parameters marked as pure. + + let impl_substs = match self.item_type(impl_def_id).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let item_substs = match self.item_type(def.did).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let result = item_substs.iter().zip(impl_substs.iter()) + .filter(|&(_, &k)| { + if let Some(&ty::Region::ReEarlyBound(ref ebr)) = k.as_region() { + !impl_generics.region_param(ebr).pure_wrt_drop + } else if let Some(&ty::TyS { + sty: ty::TypeVariants::TyParam(ref pt), .. + }) = k.as_type() { + !impl_generics.type_param(pt).pure_wrt_drop + } else { + // not a type or region param - this should be reported + // as an error. + false + } + }).map(|(&item_param, _)| item_param).collect(); + debug!("destructor_constraint({:?}) = {:?}", def.did, result); + result } - pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { + /// Return a set of constraints that needs to be satisfied in + /// order for `ty` to be valid for destruction. + pub fn dtorck_constraint_for_ty(self, + span: Span, + for_ty: Ty<'tcx>, + depth: usize, + ty: Ty<'tcx>) + -> Result, ErrorReported> + { + debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", + span, for_ty, depth, ty); + + if depth >= self.sess.recursion_limit.get() { + let mut err = struct_span_err!( + self.sess, span, E0320, + "overflow while adding drop-check rules for {}", for_ty); + err.note(&format!("overflowed on {}", ty)); + err.emit(); + return Err(ErrorReported); + } + + let result = match ty.sty { + ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | + ty::TyFloat(_) | ty::TyStr | ty::TyNever | + ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { + // these types never have a destructor + Ok(ty::DtorckConstraint::empty()) + } + + ty::TyArray(ety, _) | ty::TySlice(ety) => { + // single-element containers, behave like their element + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety) + } + + ty::TyTuple(tys, _) => { + tys.iter().map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyClosure(def_id, substs) => { + substs.upvar_tys(def_id, self).map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyAdt(def, substs) => { + let ty::DtorckConstraint { + dtorck_types, outlives + } = ty::queries::adt_dtorck_constraint::get(self, span, def.did); + Ok(ty::DtorckConstraint { + // FIXME: we can try to recursively `dtorck_constraint_on_ty` + // there, but that needs some way to handle cycles. + dtorck_types: dtorck_types.subst(self, substs), + outlives: outlives.subst(self, substs) + }) + } + + // Objects must be alive in order for their destructor + // to be called. + ty::TyDynamic(..) => Ok(ty::DtorckConstraint { + outlives: vec![Kind::from(ty)], + dtorck_types: vec![], + }), + + // Types that can't be resolved. Pass them forward. + ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => { + Ok(ty::DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ty], + }) + } + + ty::TyInfer(..) | ty::TyError => { + self.sess.delay_span_bug(span, "unresolved type in dtorck"); + Err(ErrorReported) + } + }; + + debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result); + result + } + + pub fn closure_base_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { def_id = self.parent_def_id(def_id).unwrap_or_else(|| { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 09bfe45f5404..c125d7c02556 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -15,12 +15,11 @@ use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::{self, AdtKind, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, ObligationCause, Reveal}; use util::common::ErrorReported; use util::nodemap::FxHashSet; -use syntax::ast; use syntax_pos::Span; /// check_drop_impl confirms that the Drop implementation identfied by @@ -270,389 +269,64 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( /// pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>, - typ: ty::Ty<'tcx>, + ty: ty::Ty<'tcx>, span: Span, scope: region::CodeExtent) + -> Result<(), ErrorReported> { debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", - typ, scope); + ty, scope); let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) { - Some(parent_scope) => parent_scope, - // If no enclosing scope, then it must be the root scope which cannot be outlived. - None => return + Some(parent_scope) => parent_scope, + // If no enclosing scope, then it must be the root scope + // which cannot be outlived. + None => return Ok(()) }; + let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope)); + let origin = || infer::SubregionOrigin::SafeDestructor(span); - let result = iterate_over_potentially_unsafe_regions_in_type( - &mut DropckContext { - rcx: rcx, - span: span, - parent_scope: parent_scope, - breadcrumbs: FxHashSet() - }, - TypeContext::Root, - typ, - 0); - match result { - Ok(()) => {} - Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => { - let tcx = rcx.tcx; - let mut err = struct_span_err!(tcx.sess, span, E0320, - "overflow while adding drop-check rules for {}", typ); - match *ctxt { - TypeContext::Root => { - // no need for an additional note if the overflow - // was somehow on the root. + let ty = rcx.fcx.resolve_type_vars_if_possible(&ty); + let for_ty = ty; + let mut types = vec![(ty, 0)]; + let mut known = FxHashSet(); + while let Some((ty, depth)) = types.pop() { + let ty::DtorckConstraint { + dtorck_types, outlives + } = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?; + + for ty in dtorck_types { + let ty = rcx.fcx.normalize_associated_types_in(span, &ty); + let ty = rcx.fcx.resolve_type_vars_with_obligations(ty); + let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty); + match ty.sty { + // All parameters live for the duration of the + // function. + ty::TyParam(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::TyProjection(..) | ty::TyAnon(..) => { + rcx.type_must_outlive(origin(), ty, parent_scope); } - TypeContext::ADT { def_id, variant, field } => { - let adt = tcx.lookup_adt_def(def_id); - let variant_name = match adt.adt_kind() { - AdtKind::Enum => format!("enum {} variant {}", - tcx.item_path_str(def_id), - variant), - AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)), - AdtKind::Union => format!("union {}", - tcx.item_path_str(def_id)), - }; - span_note!( - &mut err, - span, - "overflowed on {} field {} type: {}", - variant_name, - field, - detected_on_typ); + + _ => { + if let None = known.replace(ty) { + types.push((ty, depth+1)); + } } } - err.emit(); - } - } -} - -enum Error<'tcx> { - Overflow(TypeContext, ty::Ty<'tcx>), -} - -#[derive(Copy, Clone)] -enum TypeContext { - Root, - ADT { - def_id: DefId, - variant: ast::Name, - field: ast::Name, - } -} - -struct DropckContext<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> { - rcx: &'a mut RegionCtxt<'b, 'gcx, 'tcx>, - /// types that have already been traversed - breadcrumbs: FxHashSet>, - /// span for error reporting - span: Span, - /// the scope reachable dtorck types must outlive - parent_scope: region::CodeExtent -} - -// `context` is used for reporting overflow errors -fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( - cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>, - context: TypeContext, - ty: Ty<'tcx>, - depth: usize) - -> Result<(), Error<'tcx>> -{ - let tcx = cx.rcx.tcx; - // Issue #22443: Watch out for overflow. While we are careful to - // handle regular types properly, non-regular ones cause problems. - let recursion_limit = tcx.sess.recursion_limit.get(); - if depth / 4 >= recursion_limit { - // This can get into rather deep recursion, especially in the - // presence of things like Vec -> Unique -> PhantomData -> T. - // use a higher recursion limit to avoid errors. - return Err(Error::Overflow(context, ty)) - } - - // canoncialize the regions in `ty` before inserting - infinitely many - // region variables can refer to the same region. - let ty = cx.rcx.resolve_type_and_region_vars_if_possible(&ty); - - if !cx.breadcrumbs.insert(ty) { - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - cached", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - return Ok(()); // we already visited this type - } - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?}", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - - // If `typ` has a destructor, then we must ensure that all - // borrowed data reachable via `typ` must outlive the parent - // of `scope`. This is handled below. - // - // However, there is an important special case: for any Drop - // impl that is tagged as "blind" to their parameters, - // we assume that data borrowed via such type parameters - // remains unreachable via that Drop impl. - // - // For example, consider: - // - // ```rust - // #[unsafe_destructor_blind_to_params] - // impl Drop for Vec { ... } - // ``` - // - // which does have to be able to drop instances of `T`, but - // otherwise cannot read data from `T`. - // - // Of course, for the type expression passed in for any such - // unbounded type parameter `T`, we must resume the recursive - // analysis on `T` (since it would be ignored by - // type_must_outlive). - let dropck_kind = has_dtor_of_interest(tcx, ty); - debug!("iterate_over_potentially_unsafe_regions_in_type \ - ty: {:?} dropck_kind: {:?}", ty, dropck_kind); - match dropck_kind { - DropckKind::NoBorrowedDataAccessedInMyDtor => { - // The maximally blind attribute. - } - DropckKind::BorrowedDataMustStrictlyOutliveSelf => { - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - return Ok(()); - } - DropckKind::RevisedSelf(revised_ty) => { - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - // Do not return early from this case; we want - // to recursively process the internal structure of Self - // (because even though the Drop for Self has been asserted - // safe, the types instantiated for the generics of Self - // may themselves carry dropck constraints.) - } - } - - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - checking interior", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - - // We still need to ensure all referenced data is safe. - match ty.sty { - ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr | ty::TyNever => { - // primitive - definitely safe - Ok(()) } - ty::TyArray(ity, _) | ty::TySlice(ity) => { - // single-element containers, behave like their element - iterate_over_potentially_unsafe_regions_in_type( - cx, context, ity, depth+1) - } - - ty::TyAdt(def, substs) if def.is_phantom_data() => { - // PhantomData - behaves identically to T - let ity = substs.type_at(0); - iterate_over_potentially_unsafe_regions_in_type( - cx, context, ity, depth+1) - } - - ty::TyAdt(def, substs) => { - let did = def.did; - for variant in &def.variants { - for field in variant.fields.iter() { - let fty = field.ty(tcx, substs); - let fty = cx.rcx.fcx.resolve_type_vars_with_obligations( - cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty)); - iterate_over_potentially_unsafe_regions_in_type( - cx, - TypeContext::ADT { - def_id: did, - field: field.name, - variant: variant.name, - }, - fty, - depth+1)? - } + for outlive in outlives { + if let Some(r) = outlive.as_region() { + rcx.sub_regions(origin(), parent_scope, r); + } else if let Some(ty) = outlive.as_type() { + rcx.type_must_outlive(origin(), ty, parent_scope); } - Ok(()) - } - - ty::TyClosure(def_id, substs) => { - for ty in substs.upvar_tys(def_id, tcx) { - iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? - } - Ok(()) - } - - ty::TyTuple(tys, _) => { - for ty in tys { - iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? - } - Ok(()) - } - - ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyParam(..) => { - // these always come with a witness of liveness (references - // explicitly, pointers implicitly, parameters by the - // caller). - Ok(()) - } - - ty::TyFnDef(..) | ty::TyFnPtr(_) => { - // FIXME(#26656): this type is always destruction-safe, but - // it implicitly witnesses Self: Fn, which can be false. - Ok(()) - } - - ty::TyInfer(..) | ty::TyError => { - tcx.sess.delay_span_bug(cx.span, "unresolved type in regionck"); - Ok(()) - } - - // these are always dtorck - ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(), - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum DropckKind<'tcx> { - /// The "safe" kind; i.e. conservatively assume any borrow - /// accessed by dtor, and therefore such data must strictly - /// outlive self. - /// - /// Equivalent to RevisedTy with no change to the self type. - BorrowedDataMustStrictlyOutliveSelf, - - /// The nearly completely-unsafe kind. - /// - /// Equivalent to RevisedSelf with *all* parameters remapped to () - /// (maybe...?) - NoBorrowedDataAccessedInMyDtor, - - /// Assume all borrowed data access by dtor occurs as if Self has the - /// type carried by this variant. In practice this means that some - /// of the type parameters are remapped to `()` (and some lifetime - /// parameters remapped to `'static`), because the developer has asserted - /// that the destructor will not access their contents. - RevisedSelf(Ty<'tcx>), -} - -/// Returns the classification of what kind of check should be applied -/// to `ty`, which may include a revised type where some of the type -/// parameters are re-mapped to `()` to reflect the destructor's -/// "purity" with respect to their actual contents. -fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'tcx>) - -> DropckKind<'tcx> { - match ty.sty { - ty::TyAdt(adt_def, substs) => { - if !adt_def.is_dtorck(tcx) { - return DropckKind::NoBorrowedDataAccessedInMyDtor; - } - - // Find the `impl<..> Drop for _` to inspect any - // attributes attached to the impl's generics. - let dtor_method = adt_def.destructor(tcx) - .expect("dtorck type without destructor impossible"); - let method = tcx.associated_item(dtor_method.did); - let impl_def_id = method.container.id(); - let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs); - return DropckKind::RevisedSelf(revised_ty); - } - ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyAnon(..) => { - debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); - return DropckKind::BorrowedDataMustStrictlyOutliveSelf; - }, - _ => { - return DropckKind::NoBorrowedDataAccessedInMyDtor; } } -} - -// Constructs new Ty just like the type defined by `adt_def` coupled -// with `substs`, except each type and lifetime parameter marked as -// `#[may_dangle]` in the Drop impl (identified by `impl_def_id`) is -// respectively mapped to `()` or `'static`. -// -// For example: If the `adt_def` maps to: -// -// enum Foo<'a, X, Y> { ... } -// -// and the `impl_def_id` maps to: -// -// impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... } -// -// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>` -fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - adt_def: &'tcx ty::AdtDef, - impl_def_id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - // Get generics for `impl Drop` to query for `#[may_dangle]` attr. - let impl_bindings = tcx.item_generics(impl_def_id); - - // Get Substs attached to Self on `impl Drop`; process in parallel - // with `substs`, replacing dangling entries as appropriate. - let self_substs = { - let impl_self_ty: Ty<'tcx> = tcx.item_type(impl_def_id); - if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty { - assert_eq!(adt_def, self_adt_def); - self_substs - } else { - bug!("Self in `impl Drop for _` must be an Adt."); - } - }; - - // Walk `substs` + `self_substs`, build new substs appropriate for - // `adt_def`; each non-dangling param reuses entry from `substs`. - // - // Note: The manner we map from a right-hand side (i.e. Region or - // Ty) for a given `def` to generic parameter associated with that - // right-hand side is tightly coupled to `Drop` impl constraints. - // - // E.g. we know such a Ty must be `TyParam`, because a destructor - // for `struct Foo` is defined via `impl Drop for Foo`, - // and never by (for example) `impl Drop for Foo>`. - let substs = Substs::for_item( - tcx, - adt_def.did, - |def, _| { - let r_orig = substs.region_for_def(def); - let impl_self_orig = self_substs.region_for_def(def); - let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig { - if impl_bindings.region_param(ebr).pure_wrt_drop { - tcx.types.re_static - } else { - r_orig - } - } else { - bug!("substs for an impl must map regions to ReEarlyBound"); - }; - debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}", - def, r_orig, r); - r - }, - |def, _| { - let t_orig = substs.type_for_def(def); - let impl_self_orig = self_substs.type_for_def(def); - let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty { - if impl_bindings.type_param(pt).pure_wrt_drop { - tcx.mk_nil() - } else { - t_orig - } - } else { - bug!("substs for an impl must map types to TyParam"); - }; - debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}", - def, t_orig, t_orig.sty, t, t.sty); - t - }); - - tcx.mk_adt(adt_def, &substs) + + Ok(()) } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 8bfb390bd2a5..dcef22da8796 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -457,7 +457,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_of_node_must_outlive(origin, id, var_region); let typ = self.resolve_node_type(id); - dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope); + let _ = dropck::check_safety_of_destructor_if_necessary( + self, typ, span, var_scope); }) } } @@ -995,10 +996,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match *region { ty::ReScope(rvalue_scope) => { let typ = self.resolve_type(cmt.ty); - dropck::check_safety_of_destructor_if_necessary(self, - typ, - span, - rvalue_scope); + let _ = dropck::check_safety_of_destructor_if_necessary( + self, typ, span, rvalue_scope); } ty::ReStatic => {} _ => { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index c50156fa5f27..2bae6a0d9e11 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4154,7 +4154,6 @@ register_diagnostics! { // E0248, // value used as a type, now reported earlier during resolution as E0412 // E0249, // E0319, // trait impls for defaulted traits allowed just for structs/enums - E0320, // recursive overflow during dropck // E0372, // coherence not object safe E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition From e8cf5f366263533bd739c4dda9bc8a57ec55b8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 23 Apr 2017 15:36:35 -0700 Subject: [PATCH 672/905] Clean up closure type mismatch errors --- src/librustc/diagnostics.rs | 2 + src/librustc/traits/error_reporting.rs | 66 ++++++++++++++++--- src/librustc/ty/sty.rs | 16 +++++ .../ui/mismatched_types/closure-arg-count.rs | 14 ++++ .../mismatched_types/closure-arg-count.stderr | 43 ++++++++++++ .../ui/mismatched_types/closure-mismatch.rs | 19 ++++++ .../mismatched_types/closure-mismatch.stderr | 21 ++++++ 7 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/mismatched_types/closure-arg-count.rs create mode 100644 src/test/ui/mismatched_types/closure-arg-count.stderr create mode 100644 src/test/ui/mismatched_types/closure-mismatch.rs create mode 100644 src/test/ui/mismatched_types/closure-mismatch.stderr diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 30e9f502abc8..6f9d9817a447 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1850,4 +1850,6 @@ register_diagnostics! { E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints E0587, // conflicting packed and align representation hints + E0593, // closure argument count mismatch + E0594 // closure mismatch } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba340a40692c..dc7e18f8172a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -35,7 +35,7 @@ use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; use syntax::ast::{self, NodeId}; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar}; -use ty::error::ExpectedFound; +use ty::error::{ExpectedFound, TypeError}; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::Subst; @@ -663,13 +663,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if actual_trait_ref.self_ty().references_error() { return; } - struct_span_err!(self.tcx.sess, span, E0281, - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ref.self_ty(), - expected_trait_ref, - actual_trait_ref, - e) + let expected_trait_ty = expected_trait_ref.self_ty(); + if expected_trait_ty.is_closure() { + if let &TypeError::TupleSize(ref expected_found) = e { + let mut err = struct_span_err!(self.tcx.sess, span, E0593, + "closure takes {} parameter{} but {} parameter{} are required here", + expected_found.found, + if expected_found.found == 1 { "" } else { "s" }, + expected_found.expected, + if expected_found.expected == 1 { "" } else { "s" }); + + err.span_label(span, &format!("expected closure that takes {} parameter{}", + expected_found.expected, + if expected_found.expected == 1 { + "" + } else { + "s" + })); + let closure_span = expected_trait_ty.ty_to_def_id().and_then(|did| { + self.tcx.hir.span_if_local(did) + }); + if let Some(span) = closure_span { + err.span_label(span, &format!("takes {} parameter{}", + expected_found.found, + if expected_found.found == 1 { + "" + } else { + "s" + })); + } + err + } else { + let mut err = struct_span_err!(self.tcx.sess, span, E0594, + "closure mismatch: `{}` implements the trait `{}`, \ + but the trait `{}` is required", + expected_trait_ty, + expected_trait_ref, + actual_trait_ref); + + let closure_span = expected_trait_ty.ty_to_def_id().and_then(|did| { + self.tcx.hir.span_if_local(did) + }); + if let Some(span) = closure_span { + err.span_label(span, &format!("{}", e)); + } else { + err.note(&format!("{}", e)); + } + err + } + } else { + struct_span_err!(self.tcx.sess, span, E0281, + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + expected_trait_ty, + expected_trait_ref, + actual_trait_ref, + e) + } } TraitNotObjectSafe(did) => { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d59248170344..be56ac48d3ee 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -68,6 +68,15 @@ pub enum BoundRegion { BrEnv, } +impl BoundRegion { + pub fn is_named(&self) -> bool { + match *self { + BoundRegion::BrNamed(..) => true, + _ => false, + } + } +} + /// When a region changed from late-bound to early-bound when #32330 /// was fixed, its `RegionParameterDef` will have one of these /// structures that we can use to give nicer errors. @@ -1193,6 +1202,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + pub fn is_closure(&self) -> bool { + match self.sty { + TyClosure(..) => true, + _ => false, + } + } + pub fn is_integral(&self) -> bool { match self.sty { TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true, diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs new file mode 100644 index 000000000000..fbe36cd8fd26 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -0,0 +1,14 @@ +// 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() { + [1, 2, 3].sort_by(|tuple| panic!()); + [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); +} diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr new file mode 100644 index 000000000000..f45734d675b8 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -0,0 +1,43 @@ +error[E0593]: closure takes 1 parameter but 2 parameters are required here + --> $DIR/closure-arg-count.rs:12:15 + | +12 | [1, 2, 3].sort_by(|tuple| panic!()); + | ^^^^^^^ ---------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error[E0593]: closure takes 1 parameter but 2 parameters are required here + --> $DIR/closure-arg-count.rs:12:15 + | +12 | [1, 2, 3].sort_by(|tuple| panic!()); + | ^^^^^^^ ---------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error[E0308]: mismatched types + --> $DIR/closure-arg-count.rs:13:24 + | +13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^^^^^^^^^ expected &{integer}, found tuple + | + = note: expected type `&{integer}` + found type `(_, _)` + +error[E0593]: closure takes 1 parameter but 2 parameters are required here + --> $DIR/closure-arg-count.rs:13:15 + | +13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^ -------------------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error[E0593]: closure takes 1 parameter but 2 parameters are required here + --> $DIR/closure-arg-count.rs:13:15 + | +13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^ -------------------------- takes 1 parameter + | | + | expected closure that takes 2 parameters + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs new file mode 100644 index 000000000000..91298cb2bbd5 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-mismatch.rs @@ -0,0 +1,19 @@ +// 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. + +trait Foo {} + +impl Foo for T {} + +fn baz(_: T) {} + +fn main() { + baz(|_| ()); +} diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr new file mode 100644 index 000000000000..09e31b263bc3 --- /dev/null +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -0,0 +1,21 @@ +error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:18:9: 18:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()` + --> $DIR/closure-mismatch.rs:18:5 + | +18 | baz(|_| ()); + | ^^^ expected bound lifetime parameter, found concrete lifetime + | + = note: concrete lifetime that was found is lifetime '_#0r + = 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` + +error[E0594]: closure mismatch: `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r (),)>` is required + --> $DIR/closure-mismatch.rs:18:5 + | +18 | baz(|_| ()); + | ^^^ ------ expected concrete lifetime, found bound lifetime parameter + | + = 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` + +error: aborting due to 2 previous errors + From 366dd1bd3fbabd020cd9acd8f12065e488acc3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 23 Apr 2017 15:37:16 -0700 Subject: [PATCH 673/905] Avoid spurious ` ` in lifetime diagnostics --- src/librustc/ty/error.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 73d9c8b00ae4..e41202771ccb 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -117,12 +117,16 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { write!(f, "lifetimes do not intersect") } RegionsInsufficientlyPolymorphic(br, _, _) => { - write!(f, "expected bound lifetime parameter {}, \ - found concrete lifetime", br) + write!(f, + "expected bound lifetime parameter{}{}, found concrete lifetime", + if br.is_named() { " " } else { "" }, + br) } RegionsOverlyPolymorphic(br, _, _) => { - write!(f, "expected concrete lifetime, \ - found bound lifetime parameter {}", br) + write!(f, + "expected concrete lifetime, found bound lifetime parameter{}{}", + if br.is_named() { " " } else { "" }, + br) } Sorts(values) => ty::tls::with(|tcx| { report_maybe_different(f, values.expected.sort_string(tcx), From 2111aff682ee4ced9dca27defb4643cc78ab8762 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 8 Apr 2017 15:55:53 -0500 Subject: [PATCH 674/905] Add Vec::splice and String::splice --- src/libcollections/slice.rs | 6 +- src/libcollections/string.rs | 130 ++++++++++++++++++++++- src/libcollections/tests/lib.rs | 1 + src/libcollections/tests/string.rs | 8 ++ src/libcollections/tests/vec.rs | 10 ++ src/libcollections/vec.rs | 165 ++++++++++++++++++++++++++++- 6 files changed, 313 insertions(+), 7 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 7c3c825cfd1f..2eef132374e5 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1519,13 +1519,9 @@ impl ToOwned for [T] { self.to_vec() } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec`, which is required for this method - // definition, is not available. Since we don't require this method for testing purposes, I'll - // just stub it - // NB see the slice::hack module in slice.rs for more information #[cfg(test)] fn to_owned(&self) -> Vec { - panic!("not available with cfg(test)") + hack::to_vec(self) } fn clone_into(&self, target: &mut Vec) { diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 8d6cf3051126..8090bc1996e4 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1316,7 +1316,7 @@ impl String { self.vec.clear() } - /// Create a draining iterator that removes the specified range in the string + /// Creates a draining iterator that removes the specified range in the string /// and yields the removed chars. /// /// Note: The element range is removed even if the iterator is not @@ -1382,6 +1382,63 @@ impl String { } } + /// Creates a splicing iterator that removes the specified range in the string, + /// replaces with the given string, and yields the removed chars. + /// The given string doesn’t need to be the same length as the range. + /// + /// Note: The element range is removed even if the iterator is not + /// consumed until the end. + /// + /// # Panics + /// + /// Panics if the starting point or end point do not lie on a [`char`] + /// boundary, or if they're out of bounds. + /// + /// [`char`]: ../../std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(splice)] + /// let mut s = String::from("Ξ± is alpha, Ξ² is beta"); + /// let beta_offset = s.find('Ξ²').unwrap_or(s.len()); + /// + /// // Replace the range up until the Ξ² from the string + /// let t: String = s.splice(..beta_offset, "Ξ‘ is capital alpha; ").collect(); + /// assert_eq!(t, "Ξ± is alpha, "); + /// assert_eq!(s, "Ξ‘ is capital alpha; Ξ² is beta"); + /// ``` + #[unstable(feature = "splice", reason = "recently added", issue = "32310")] + pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b> + where R: RangeArgument + { + // Memory safety + // + // The String version of Splice does not have the memory safety issues + // of the vector version. The data is just plain bytes. + // Because the range removal happens in Drop, if the Splice iterator is leaked, + // the removal will not happen. + let len = self.len(); + let start = *range.start().unwrap_or(&0); + let end = *range.end().unwrap_or(&len); + + // Take out two simultaneous borrows. The &mut String won't be accessed + // until iteration is over, in Drop. + let self_ptr = self as *mut _; + // slicing does the appropriate bounds checks + let chars_iter = self[start..end].chars(); + + Splice { + start: start, + end: end, + iter: chars_iter, + string: self_ptr, + replace_with: replace_with + } + } + /// Converts this `String` into a `Box`. /// /// This will drop any excess capacity. @@ -2145,3 +2202,74 @@ impl<'a> DoubleEndedIterator for Drain<'a> { #[unstable(feature = "fused", issue = "35602")] impl<'a> FusedIterator for Drain<'a> {} + +/// A splicing iterator for `String`. +/// +/// This struct is created by the [`splice()`] method on [`String`]. See its +/// documentation for more. +/// +/// [`splice()`]: struct.String.html#method.splice +/// [`String`]: struct.String.html +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +pub struct Splice<'a, 'b> { + /// Will be used as &'a mut String in the destructor + string: *mut String, + /// Start of part to remove + start: usize, + /// End of part to remove + end: usize, + /// Current remaining range to remove + iter: Chars<'a>, + replace_with: &'b str, +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {} +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +unsafe impl<'a, 'b> Send for Splice<'a, 'b> {} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> Drop for Splice<'a, 'b> { + fn drop(&mut self) { + unsafe { + let vec = (*self.string).as_mut_vec(); + let range_len = self.end - self.start; + let replacement_len = self.replace_with.len(); + let tail_len = vec.len() - self.end; + if replacement_len > range_len { + vec.reserve(replacement_len - range_len); + } + if replacement_len != range_len { + let src = vec.as_ptr().offset(self.end as isize); + let dst = vec.as_mut_ptr().offset((self.start + replacement_len) as isize); + ptr::copy(src, dst, tail_len); + } + let src = self.replace_with.as_ptr(); + let dst = vec.as_mut_ptr().offset(self.start as isize); + ptr::copy(src, dst, replacement_len); + vec.set_len(self.start + replacement_len + tail_len); + } + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> Iterator for Splice<'a, 'b> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} diff --git a/src/libcollections/tests/lib.rs b/src/libcollections/tests/lib.rs index 9c6e31d70a54..eae3bf3915f6 100644 --- a/src/libcollections/tests/lib.rs +++ b/src/libcollections/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] +#![feature(splice)] #![feature(step_by)] #![feature(str_escape)] #![feature(test)] diff --git a/src/libcollections/tests/string.rs b/src/libcollections/tests/string.rs index 2f021b9935d6..faaa9a1830b0 100644 --- a/src/libcollections/tests/string.rs +++ b/src/libcollections/tests/string.rs @@ -419,6 +419,14 @@ fn test_drain() { assert_eq!(t, ""); } +#[test] +fn test_splice() { + let mut s = "Hello, world!".to_owned(); + let t: String = s.splice(7..12, "δΈ–η•Œ").collect(); + assert_eq!(s, "Hello, δΈ–η•Œ!"); + assert_eq!(t, "world"); +} + #[test] fn test_extend_ref() { let mut a = "foo".to_string(); diff --git a/src/libcollections/tests/vec.rs b/src/libcollections/tests/vec.rs index 64c76142b59d..e3453c70abaf 100644 --- a/src/libcollections/tests/vec.rs +++ b/src/libcollections/tests/vec.rs @@ -579,6 +579,16 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5...5); } +#[test] +fn splice() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(2..4, a.iter().cloned()); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + v.splice(1..3, Some(20)); + assert_eq!(v, &[1, 20, 11, 12, 5]); +} + #[test] fn test_into_boxed_slice() { let xs = vec![1, 2, 3]; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 6deb87ae7720..bbb067ca4e3b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1057,7 +1057,7 @@ impl Vec { self.len += count; } - /// Create a draining iterator that removes the specified range in the vector + /// Creates a draining iterator that removes the specified range in the vector /// and yields the removed items. /// /// Note 1: The element range is removed even if the iterator is only @@ -1845,6 +1845,54 @@ impl Vec { } } } + + /// Creates a splicing iterator that replaces the specified range in the vector + /// with the given `replace_with` iterator and yields the removed items. + /// `replace_with` does not need to be the same length as `range`. + /// + /// Note 1: The element range is removed even if the iterator is not + /// consumed until the end. + /// + /// Note 2: It is unspecified how many elements are removed from the vector, + /// if the `Splice` value is leaked. + /// + /// Note 3: The input iterator `replace_with` is only consumed + /// when the `Splice` value is dropped. + /// + /// Note 4: This is optimal if: + /// + /// * The tail (elements in the vector after `range`) is empty, + /// * or `replace_with` yields fewer elements than `range`’s length + /// * or the lower bound of its `size_hint()` is exact. + /// + /// Otherwise, a temporary vector is allocated and the tail is moved twice. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// #![feature(splice)] + /// let mut v = vec![1, 2, 3]; + /// let new = [7, 8]; + /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect(); + /// assert_eq!(v, &[7, 8, 3]); + /// assert_eq!(u, &[1, 2]); + /// ``` + #[inline] + #[unstable(feature = "splice", reason = "recently added", issue = "32310")] + pub fn splice(&mut self, range: R, replace_with: I) -> Splice + where R: RangeArgument, I: IntoIterator + { + Splice { + drain: self.drain(range), + replace_with: replace_with.into_iter(), + } + } + } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -2344,3 +2392,118 @@ impl<'a, T> InPlace for PlaceBack<'a, T> { &mut *ptr } } + + +/// A splicing iterator for `Vec`. See the [`Vec::splice`](struct.Vec.html#method.splice) method. +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +pub struct Splice<'a, I: Iterator + 'a> { + drain: Drain<'a, I::Item>, + replace_with: I, +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> Iterator for Splice<'a, I> { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.drain.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> DoubleEndedIterator for Splice<'a, I> { + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {} + + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> Drop for Splice<'a, I> { + fn drop(&mut self) { + // exhaust drain first + while let Some(_) = self.drain.next() {} + + + unsafe { + if self.drain.tail_len == 0 { + let vec = &mut *self.drain.vec; + vec.extend(self.replace_with.by_ref()); + return + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return + } + } + + // Collect any remaining elements. + // This is a zero-length vector which does not allocate if `lower_bound` was exact. + let mut collected = self.replace_with.by_ref().collect::>().into_iter(); + // Now we have an exact count. + if collected.len() > 0 { + self.drain.move_tail(collected.len()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. + } +} + +/// Private helper methods for `Splice::drop` +impl<'a, T> Drain<'a, T> { + /// The range from `self.vec.len` to `self.tail_start` contains elements + /// that have been moved out. + /// Fill that range as much as possible with new elements from the `replace_with` iterator. + /// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.) + unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { + let vec = &mut *self.vec; + let range_start = vec.len; + let range_end = self.tail_start; + let range_slice = slice::from_raw_parts_mut( + vec.as_mut_ptr().offset(range_start as isize), + range_end - range_start); + + for place in range_slice { + if let Some(new_item) = replace_with.next() { + ptr::write(place, new_item); + vec.len += 1; + } else { + return false + } + } + true + } + + /// Make room for inserting more elements before the tail. + unsafe fn move_tail(&mut self, extra_capacity: usize) { + let vec = &mut *self.vec; + let used_capacity = self.tail_start + self.tail_len; + vec.buf.reserve(used_capacity, extra_capacity); + + let new_tail_start = self.tail_start + extra_capacity; + let src = vec.as_ptr().offset(self.tail_start as isize); + let dst = vec.as_mut_ptr().offset(new_tail_start as isize); + ptr::copy(src, dst, self.tail_len); + self.tail_start = new_tail_start; + } +} From b85e2e4735fe78fffeecd2fce96d7ce40d22438c Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 8 Apr 2017 16:12:58 -0500 Subject: [PATCH 675/905] Update splice impl --- src/libcollections/string.rs | 13 +++++++++++-- src/libcollections/vec.rs | 15 +++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 8090bc1996e4..cc4f9b86be4d 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1421,8 +1421,16 @@ impl String { // Because the range removal happens in Drop, if the Splice iterator is leaked, // the removal will not happen. let len = self.len(); - let start = *range.start().unwrap_or(&0); - let end = *range.end().unwrap_or(&len); + let start = match range.start() { + Included(&n) => n, + Excluded(&n) => n + 1, + Unbounded => 0, + }; + let end = match range.end() { + Included(&n) => n + 1, + Excluded(&n) => n, + Unbounded => len, + }; // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. @@ -2210,6 +2218,7 @@ impl<'a> FusedIterator for Drain<'a> {} /// /// [`splice()`]: struct.String.html#method.splice /// [`String`]: struct.String.html +#[derive(Debug)] #[unstable(feature = "splice", reason = "recently added", issue = "32310")] pub struct Splice<'a, 'b> { /// Will be used as &'a mut String in the destructor diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index bbb067ca4e3b..dc330d4b2590 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2394,7 +2394,14 @@ impl<'a, T> InPlace for PlaceBack<'a, T> { } -/// A splicing iterator for `Vec`. See the [`Vec::splice`](struct.Vec.html#method.splice) method. +/// A splicing iterator for `Vec`. +/// +/// This struct is created by the [`splice()`] method on [`Vec`]. See its +/// documentation for more. +/// +/// [`splice()`]: struct.Vec.html#method.splice +/// [`Vec`]: struct.Vec.html +#[derive(Debug)] #[unstable(feature = "splice", reason = "recently added", issue = "32310")] pub struct Splice<'a, I: Iterator + 'a> { drain: Drain<'a, I::Item>, @@ -2434,7 +2441,7 @@ impl<'a, I: Iterator> Drop for Splice<'a, I> { unsafe { if self.drain.tail_len == 0 { - let vec = &mut *self.drain.vec; + let vec = &mut *self.drain.vec.as_mut_ptr(); vec.extend(self.replace_with.by_ref()); return } @@ -2476,7 +2483,7 @@ impl<'a, T> Drain<'a, T> { /// Fill that range as much as possible with new elements from the `replace_with` iterator. /// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.) unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { - let vec = &mut *self.vec; + let vec = &mut *self.vec.as_mut_ptr(); let range_start = vec.len; let range_end = self.tail_start; let range_slice = slice::from_raw_parts_mut( @@ -2496,7 +2503,7 @@ impl<'a, T> Drain<'a, T> { /// Make room for inserting more elements before the tail. unsafe fn move_tail(&mut self, extra_capacity: usize) { - let vec = &mut *self.vec; + let vec = &mut *self.vec.as_mut_ptr(); let used_capacity = self.tail_start + self.tail_len; vec.buf.reserve(used_capacity, extra_capacity); From cec00bab1d5d74e5ad176fea0b2c5aab882f36e7 Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 8 Apr 2017 16:04:30 -0500 Subject: [PATCH 676/905] Improve splice docs and tests --- src/libcollections/string.rs | 4 +-- src/libcollections/tests/string.rs | 48 ++++++++++++++++++++++++++++++ src/libcollections/tests/vec.rs | 47 ++++++++++++++++++++++++++++- src/libcollections/vec.rs | 2 +- 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index cc4f9b86be4d..e7085e94336f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1386,8 +1386,8 @@ impl String { /// replaces with the given string, and yields the removed chars. /// The given string doesn’t need to be the same length as the range. /// - /// Note: The element range is removed even if the iterator is not - /// consumed until the end. + /// Note: The element range is removed when the `Splice` is dropped, + /// even if the iterator is not consumed until the end. /// /// # Panics /// diff --git a/src/libcollections/tests/string.rs b/src/libcollections/tests/string.rs index faaa9a1830b0..a32f5e3357f3 100644 --- a/src/libcollections/tests/string.rs +++ b/src/libcollections/tests/string.rs @@ -427,6 +427,54 @@ fn test_splice() { assert_eq!(t, "world"); } +#[test] +#[should_panic] +fn test_splice_char_boundary() { + let mut s = "Hello, δΈ–η•Œ!".to_owned(); + s.splice(..8, ""); +} + +#[test] +fn test_splice_inclusive_range() { + let mut v = String::from("12345"); + let t: String = v.splice(2...3, "789").collect(); + assert_eq!(v, "127895"); + assert_eq!(t, "34"); + let t2: String = v.splice(1...2, "A").collect(); + assert_eq!(v, "1A895"); + assert_eq!(t2, "27"); +} + +#[test] +#[should_panic] +fn test_splice_out_of_bounds() { + let mut s = String::from("12345"); + s.splice(5..6, "789"); +} + +#[test] +#[should_panic] +fn test_splice_inclusive_out_of_bounds() { + let mut s = String::from("12345"); + s.splice(5...5, "789"); +} + +#[test] +fn test_splice_empty() { + let mut s = String::from("12345"); + let t: String = s.splice(1..2, "").collect(); + assert_eq!(s, "1345"); + assert_eq!(t, "2"); +} + +#[test] +fn test_splice_unbounded() { + let mut s = String::from("12345"); + let t: String = s.splice(.., "").collect(); + assert_eq!(s, ""); + assert_eq!(t, "12345"); +} + #[test] fn test_extend_ref() { let mut a = "foo".to_string(); diff --git a/src/libcollections/tests/vec.rs b/src/libcollections/tests/vec.rs index e3453c70abaf..f47940dc33aa 100644 --- a/src/libcollections/tests/vec.rs +++ b/src/libcollections/tests/vec.rs @@ -580,7 +580,7 @@ fn test_drain_inclusive_out_of_bounds() { } #[test] -fn splice() { +fn test_splice() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; v.splice(2..4, a.iter().cloned()); @@ -589,6 +589,51 @@ fn splice() { assert_eq!(v, &[1, 20, 11, 12, 5]); } +#[test] +fn test_splice_inclusive_range() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect(); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + assert_eq!(t1, &[3, 4]); + let t2: Vec<_> = v.splice(1...2, Some(20)).collect(); + assert_eq!(v, &[1, 20, 11, 12, 5]); + assert_eq!(t2, &[2, 10]); +} + +#[test] +#[should_panic] +fn test_splice_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5..6, a.iter().cloned()); +} + +#[test] +#[should_panic] +fn test_splice_inclusive_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5...5, a.iter().cloned()); +} + +#[test] +fn test_splice_items_zero_sized() { + let mut vec = vec![(), (), ()]; + let vec2 = vec![]; + let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect(); + assert_eq!(vec, &[(), ()]); + assert_eq!(t, &[()]); +} + +#[test] +fn test_splice_unbounded() { + let mut vec = vec![1, 2, 3, 4, 5]; + let t: Vec<_> = vec.splice(.., None).collect(); + assert_eq!(vec, &[]); + assert_eq!(t, &[1, 2, 3, 4, 5]); +} + #[test] fn test_into_boxed_slice() { let xs = vec![1, 2, 3]; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index dc330d4b2590..e5964385b125 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1063,7 +1063,7 @@ impl Vec { /// Note 1: The element range is removed even if the iterator is only /// partially consumed or not consumed at all. /// - /// Note 2: It is unspecified how many elements are removed from the vector, + /// Note 2: It is unspecified how many elements are removed from the vector /// if the `Drain` value is leaked. /// /// # Panics From c3baa8c0a7c0f90c3630c5eacc8f8783505c90ec Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 8 Apr 2017 16:43:30 -0500 Subject: [PATCH 677/905] Use Vec::splice impl in string::Splice::drop() --- src/libcollections/string.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index e7085e94336f..0a82fda09cb8 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -2242,21 +2242,7 @@ impl<'a, 'b> Drop for Splice<'a, 'b> { fn drop(&mut self) { unsafe { let vec = (*self.string).as_mut_vec(); - let range_len = self.end - self.start; - let replacement_len = self.replace_with.len(); - let tail_len = vec.len() - self.end; - if replacement_len > range_len { - vec.reserve(replacement_len - range_len); - } - if replacement_len != range_len { - let src = vec.as_ptr().offset(self.end as isize); - let dst = vec.as_mut_ptr().offset((self.start + replacement_len) as isize); - ptr::copy(src, dst, tail_len); - } - let src = self.replace_with.as_ptr(); - let dst = vec.as_mut_ptr().offset(self.start as isize); - ptr::copy(src, dst, replacement_len); - vec.set_len(self.start + replacement_len + tail_len); + vec.splice(self.start..self.end, self.replace_with.bytes()); } } } From 7b86ba0d8de53fece3c5e4a522dbde123f483a7c Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Sat, 8 Apr 2017 16:58:47 -0500 Subject: [PATCH 678/905] Add splice to the unstable book. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../src/library-features/splice.md | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/doc/unstable-book/src/library-features/splice.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 613475730417..1adc59b84eac 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -195,6 +195,7 @@ - [slice_rsplit](library-features/slice-rsplit.md) - [sort_internals](library-features/sort-internals.md) - [sort_unstable](library-features/sort-unstable.md) + - [splice](library-features/splice.md) - [step_by](library-features/step-by.md) - [step_trait](library-features/step-trait.md) - [str_checked_slicing](library-features/str-checked-slicing.md) diff --git a/src/doc/unstable-book/src/library-features/splice.md b/src/doc/unstable-book/src/library-features/splice.md new file mode 100644 index 000000000000..ca7f78a8f79e --- /dev/null +++ b/src/doc/unstable-book/src/library-features/splice.md @@ -0,0 +1,24 @@ +# `splice` + +The tracking issue for this feature is: [#32310] + +[#32310]: https://github.com/rust-lang/rust/issues/32310 + +------------------------ + +The `splice()` method on `Vec` and `String` allows you to replace a range +of values in a vector or string with another range of values, and returns +the replaced values. + +A simple example: + +```rust +#![feature(splice)] +let mut s = String::from("Ξ± is alpha, Ξ² is beta"); +let beta_offset = s.find('Ξ²').unwrap_or(s.len()); + +// Replace the range up until the Ξ² from the string +let t: String = s.splice(..beta_offset, "Ξ‘ is capital alpha; ").collect(); +assert_eq!(t, "Ξ± is alpha, "); +assert_eq!(s, "Ξ‘ is capital alpha; Ξ² is beta"); +``` \ No newline at end of file From f8c6436173f9ccbe79eaf021161f26b601eef026 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 23 Apr 2017 21:47:09 -0700 Subject: [PATCH 679/905] Step::replace_one should put a one, not a zero (Issue #41492) Turns out all six of these impls are incorrect. --- src/libcore/iter/range.rs | 12 ++++++------ src/libcore/tests/iter.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/libcore/tests/lib.rs | 2 ++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 687c477f19e4..bd831d638c0c 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -86,12 +86,12 @@ macro_rules! step_impl_unsigned { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] @@ -157,12 +157,12 @@ macro_rules! step_impl_signed { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] @@ -206,12 +206,12 @@ macro_rules! step_impl_no_between { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 08442f9bcbff..001fa304cd08 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1082,3 +1082,41 @@ fn test_chain_fold() { assert_eq!(&[2, 3, 1, 2, 0], &result[..]); } +#[test] +fn test_step_replace_unsigned() { + let mut x = 4u32; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} + +#[test] +fn test_step_replace_signed() { + let mut x = 4i32; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} + +#[test] +fn test_step_replace_no_between() { + let mut x = 4u128; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} \ No newline at end of file diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 528ab3bc8452..f0c46a6f194d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(i128_type)] #![feature(iter_rfind)] #![feature(libc)] #![feature(nonzero)] @@ -30,6 +31,7 @@ #![feature(sort_internals)] #![feature(sort_unstable)] #![feature(step_by)] +#![feature(step_trait)] #![feature(test)] #![feature(try_from)] #![feature(unicode)] From 86b10671dbb7edf4090cb04476b4da205fd892b2 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Sun, 23 Apr 2017 22:00:09 -0700 Subject: [PATCH 680/905] Associated consts are not object safe. --- src/librustc/traits/object_safety.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index d190635bec30..f51711d03103 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -37,6 +37,9 @@ pub enum ObjectSafetyViolation { /// Method has something illegal Method(ast::Name, MethodViolationCode), + + /// Associated const + AssociatedConst(ast::Name), } impl ObjectSafetyViolation { @@ -54,6 +57,8 @@ impl ObjectSafetyViolation { in its arguments or return type", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), + ObjectSafetyViolation::AssociatedConst(name) => + format!("the trait cannot contain associated consts, such as `{}`", name), } } } @@ -141,6 +146,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { violations.push(ObjectSafetyViolation::SupertraitSelf); } + violations.extend(self.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Const) + .map(|item| ObjectSafetyViolation::AssociatedConst(item.name))); + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", trait_def_id, violations); From bd31498ef668ee6c6ac0d2777ed5195b5f5d77e4 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Mon, 24 Apr 2017 01:19:12 -0700 Subject: [PATCH 681/905] Add compile-fail test. --- src/librustc/traits/object_safety.rs | 2 +- .../object-safety-associated-consts.rs | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/object-safety-associated-consts.rs diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index f51711d03103..90260d173725 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -58,7 +58,7 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), ObjectSafetyViolation::AssociatedConst(name) => - format!("the trait cannot contain associated consts, such as `{}`", name), + format!("the trait cannot contain associated consts like `{}`", name), } } } diff --git a/src/test/compile-fail/object-safety-associated-consts.rs b/src/test/compile-fail/object-safety-associated-consts.rs new file mode 100644 index 000000000000..e38187fe86ab --- /dev/null +++ b/src/test/compile-fail/object-safety-associated-consts.rs @@ -0,0 +1,26 @@ +// 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. + +// Check that we correctly prevent users from making trait objects +// from traits with associated consts. + +trait Bar { + const X: usize; +} + +fn make_bar(t: &T) -> &Bar { + //~^ ERROR E0038 + //~| NOTE the trait cannot contain associated consts like `X` + //~| NOTE the trait `Bar` cannot be made into an object + t +} + +fn main() { +} From ed5d09d8f3e65d679aa24c6a50874920be5979f5 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Mon, 24 Apr 2017 01:20:36 -0700 Subject: [PATCH 682/905] Fix type error. --- src/librustc/traits/object_safety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 90260d173725..e53932888022 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -58,7 +58,7 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), ObjectSafetyViolation::AssociatedConst(name) => - format!("the trait cannot contain associated consts like `{}`", name), + format!("the trait cannot contain associated consts like `{}`", name).into(), } } } From 95ffda1e9ee72f2170d55e4790bef21fb4ac11b1 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Mon, 24 Apr 2017 01:40:17 -0700 Subject: [PATCH 683/905] Style. --- src/test/compile-fail/object-safety-associated-consts.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/object-safety-associated-consts.rs b/src/test/compile-fail/object-safety-associated-consts.rs index e38187fe86ab..499f41846f5a 100644 --- a/src/test/compile-fail/object-safety-associated-consts.rs +++ b/src/test/compile-fail/object-safety-associated-consts.rs @@ -16,9 +16,9 @@ trait Bar { } fn make_bar(t: &T) -> &Bar { - //~^ ERROR E0038 - //~| NOTE the trait cannot contain associated consts like `X` - //~| NOTE the trait `Bar` cannot be made into an object + //~^ ERROR E0038 + //~| NOTE the trait cannot contain associated consts like `X` + //~| NOTE the trait `Bar` cannot be made into an object t } From 5dc43d272dcc1c7ba256f2d9cb88454c1770e053 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Mon, 24 Apr 2017 02:42:36 -0700 Subject: [PATCH 684/905] Feature gate in test. --- src/test/compile-fail/object-safety-associated-consts.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/compile-fail/object-safety-associated-consts.rs b/src/test/compile-fail/object-safety-associated-consts.rs index 499f41846f5a..c442cd408365 100644 --- a/src/test/compile-fail/object-safety-associated-consts.rs +++ b/src/test/compile-fail/object-safety-associated-consts.rs @@ -11,6 +11,8 @@ // Check that we correctly prevent users from making trait objects // from traits with associated consts. +#![feature(associated_consts)] + trait Bar { const X: usize; } From 116e9831a57dd09b4c580c2f480064299137b0b0 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Fri, 18 Nov 2016 17:14:42 +0100 Subject: [PATCH 685/905] support `default impl` for specialization this commit implements the first step of the `default impl` feature: all items in a `default impl` are (implicitly) `default` and hence specializable. In order to test this feature I've copied all the tests provided for the `default` method implementation (in run-pass/specialization and compile-fail/specialization directories) and moved the `default` keyword from the item to the impl. See referenced issue for further info --- cargo | 2 +- rls | 2 +- src/compiler-rt | 2 +- src/doc/book | 2 +- src/doc/reference | 2 +- src/jemalloc | 2 +- src/liblibc | 2 +- src/librustc/hir/lowering.rs | 9 +- src/librustc/hir/mod.rs | 1 + src/librustc/hir/print.rs | 15 ++- src/librustc/middle/reachable.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 4 +- src/librustc/traits/project.rs | 24 +++- src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 4 + src/librustc_metadata/encoder.rs | 4 +- src/librustc_metadata/schema.rs | 1 + src/librustc_save_analysis/dump_visitor.rs | 4 +- src/librustc_trans/collector.rs | 3 +- src/librustc_typeck/check/mod.rs | 18 ++- src/librustc_typeck/check/wfcheck.rs | 4 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustdoc/doctree.rs | 1 + src/librustdoc/visit_ast.rs | 3 +- src/libsyntax/ast.rs | 1 + src/libsyntax/feature_gate.rs | 11 +- src/libsyntax/fold.rs | 9 +- src/libsyntax/parse/parser.rs | 29 +++-- src/libsyntax/print/pprust.rs | 13 ++- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 1 + src/rt/hoedown | 1 - .../specialization-default-projection.rs | 46 ++++++++ .../specialization-default-types.rs | 45 ++++++++ .../specialization-feature-gate-default.rs | 21 ++++ .../defaultimpl/specialization-no-default.rs | 95 ++++++++++++++++ .../defaultimpl/auxiliary/go_trait.rs | 53 +++++++++ .../auxiliary/specialization_cross_crate.rs | 82 ++++++++++++++ .../specialization_cross_crate_defaults.rs | 49 ++++++++ .../specialization-allowed-cross-crate.rs | 31 +++++ .../defaultimpl/specialization-assoc-fns.rs | 37 ++++++ .../defaultimpl/specialization-basics.rs | 106 ++++++++++++++++++ .../specialization-cross-crate-defaults.rs | 49 ++++++++ .../specialization-cross-crate-no-gate.rs | 29 +++++ .../defaultimpl/specialization-cross-crate.rs | 58 ++++++++++ .../specialization-default-methods.rs | 94 ++++++++++++++++ .../specialization-out-of-order.rs | 27 +++++ .../specialization-overlap-projection.rs | 33 ++++++ .../specialization-projection-alias.rs | 32 ++++++ .../defaultimpl/specialization-projection.rs | 49 ++++++++ 50 files changed, 1078 insertions(+), 41 deletions(-) delete mode 160000 src/rt/hoedown create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-basics.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-projection.rs diff --git a/cargo b/cargo index 8326a3683a90..c416fb60b11e 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 +Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 diff --git a/rls b/rls index 6ecff95fdc3e..016cbc514cf4 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce +Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 diff --git a/src/compiler-rt b/src/compiler-rt index d30da544a8af..a8fc4c169fac 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 +Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 diff --git a/src/doc/book b/src/doc/book index ad7de198561b..beea82b9230c 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 +Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 diff --git a/src/doc/reference b/src/doc/reference index 6b0de90d87dd..b060f732145f 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 +Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d diff --git a/src/jemalloc b/src/jemalloc index 11bfb0dcf85f..e058ca661692 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 +Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968 diff --git a/src/liblibc b/src/liblibc index c34a802d1eb0..05a2d197356e 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 +Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b7aafa0a9ab0..5fb8170cd6c3 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1326,7 +1326,13 @@ impl<'a> LoweringContext<'a> { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), trait_ref) } - ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { + ItemKind::Impl(unsafety, + polarity, + defaultness, + ref generics, + ref ifce, + ref ty, + ref impl_items) => { let new_impl_items = impl_items.iter() .map(|item| self.lower_impl_item_ref(item)) .collect(); @@ -1340,6 +1346,7 @@ impl<'a> LoweringContext<'a> { hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), + self.lower_defaultness(defaultness), self.lower_generics(generics), ifce, self.lower_ty(ty), diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 562b58844409..cb7f530b9952 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1712,6 +1712,7 @@ pub enum Item_ { /// An implementation, eg `impl Trait for Foo { .. }` ItemImpl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5144f75b1a36..dec0753be064 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -678,12 +678,14 @@ impl<'a> State<'a> { } hir::ItemImpl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -820,6 +822,13 @@ impl<'a> State<'a> { } } + pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { + if let hir::Defaultness::Default = defaultness { + self.word_nbsp("default")?; + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &hir::VariantData, generics: &hir::Generics, @@ -931,11 +940,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - - match ii.defaultness { - hir::Defaultness::Default { .. } => self.word_nbsp("default")?, - hir::Defaultness::Final => (), - } + self.print_defaultness(ii.defaultness)?; match ii.node { hir::ImplItemKind::Const(ref ty, expr) => { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index be4ec16cd63a..12280acfac21 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -50,7 +50,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool { } match item.node { - hir::ItemImpl(_, _, ref generics, ..) | + hir::ItemImpl(_, _, _, ref generics, ..) | hir::ItemFn(.., ref generics, _) => { generics_require_inlining(generics) } @@ -186,7 +186,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // does too. let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap(); match self.tcx.hir.expect_item(impl_node_id).node { - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { generics_require_inlining(generics) } _ => false diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a1aabc775a31..a8ba708cc2cd 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { // These kinds of items have only early bound lifetime parameters. let mut index = if let hir::ItemTrait(..) = item.node { 1 // Self comes before lifetimes @@ -834,7 +834,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } match parent.node { hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } _ => {} diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3d8f9e41c675..f417ad5b3d9d 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,6 +33,7 @@ use ty::subst::Subst; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; +use hir::{self}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -923,7 +924,28 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - node_item.item.defaultness.is_default() + let is_default = match selcx.tcx() + .map + .as_local_node_id(node_item.node.def_id()) { + Some(node_id) => { + let item = selcx.tcx().map.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_default() + } else { + false + } + } + None => { + selcx.tcx() + .global_tcx() + .sess + .cstore + .impl_defaultness(node_item.node.def_id()) + .is_default() + } + }; + + node_item.item.defaultness.is_default() || is_default }; // Only reveal a specializable default if we're past type-checking diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 9e6a45e7f8b7..618c1711dad4 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -90,6 +90,7 @@ provide! { <'tcx> tcx, def_id, cdata associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_polarity => { cdata.get_impl_polarity(def_id.index) } + impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a9eae5281b24..ff643c17cfa6 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -629,6 +629,10 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).polarity } + pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness { + self.get_impl_data(id).defaultness + } + pub fn get_coerce_unsized_info(&self, id: DefIndex) -> Option { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ce9f0a73fe2b..d55f489107d7 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -706,6 +706,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { hir::ItemDefaultImpl(..) => { let data = ImplData { polarity: hir::ImplPolarity::Positive, + defaultness: hir::Defaultness::Final, parent_impl: None, coerce_unsized_info: None, trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), @@ -713,7 +714,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { EntryKind::DefaultImpl(self.lazy(&data)) } - hir::ItemImpl(_, polarity, ..) => { + hir::ItemImpl(_, polarity, defaultness, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = tcx.lookup_trait_def(trait_ref.def_id); @@ -740,6 +741,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let data = ImplData { polarity: polarity, + defaultness: defaultness, parent_impl: parent, coerce_unsized_info: coerce_unsized_info, trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2f2e0e125aea..933c3482474b 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -406,6 +406,7 @@ impl_stable_hash_for!(struct TraitData<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub parent_impl: Option, /// This is `Some` only for impls of `CoerceUnsized`. diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3e8f7e11b6b4..36e59b4774ad 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -429,8 +429,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } None => { - if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { - if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node { + if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { trait_id = self.lookup_def_id(ty.id); } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 13bb0d371250..991470ebe640 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -880,7 +880,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { let parent_node_id = hir_map.get_parent_node(ii.id); let is_impl_generic = match hir_map.expect_item(parent_node_id) { &hir::Item { - node: hir::ItemImpl(_, _, ref generics, ..), + node: hir::ItemImpl(_, _, _, ref generics, ..), .. } => { generics.is_type_parameterized() @@ -911,6 +911,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, + _, _, ref generics, .., diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 098e8c53a52c..74886e503a85 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1142,7 +1142,23 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(parent) = parent { if parent.item.is_final() { - report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); + let is_final = match tcx.map.as_local_node_id(parent.node.def_id()) { + Some(node_id) => { + let item = tcx.map.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_final() + } else { + true + } + } + None => { + tcx.global_tcx().sess.cstore.impl_defaultness(parent.node.def_id()).is_final() + } + }; + + if is_final { + report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); + } } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 85c87adf9be6..8b8a765dd60a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -105,11 +105,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { /// /// won't be allowed unless there's an *explicit* implementation of `Send` /// for `T` - hir::ItemImpl(_, hir::ImplPolarity::Positive, _, + hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _, ref trait_ref, ref self_ty, _) => { self.check_impl(item, self_ty, trait_ref); } - hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => { + hir::ItemImpl(_, hir::ImplPolarity::Negative, _, _, Some(_), ..) => { // FIXME(#27579) what amount of WF checking do we need for neg impls? let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap(); diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 22247d2531ae..323700f9eafb 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -87,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { hir::ItemDefaultImpl(unsafety, _) => { self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); } - hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => { + hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => { self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); } _ => {} diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d819268240ba..71594825cdb0 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -214,6 +214,7 @@ pub struct Trait { pub struct Impl { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub generics: hir::Generics, pub trait_: Option, pub for_: P, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4252f2981ed6..4ffc8c97c500 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,7 +502,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.traits.push(t); }, - hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => { + hir::ItemImpl(unsafety, polarity, defaultness, ref gen, ref tr, ref ty, ref item_ids) => { // Don't duplicate impls when inlining, we'll pick them up // regardless of where they're located. if !self.inlining { @@ -512,6 +512,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let i = Impl { unsafety: unsafety, polarity: polarity, + defaultness: defaultness, generics: gen.clone(), trait_: tr.clone(), for_: ty.clone(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 131adfe47afd..e5bb02fe0823 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1852,6 +1852,7 @@ pub enum ItemKind { /// E.g. `impl Foo { .. }` or `impl Trait for Foo { .. }` Impl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9b55a860b359..152a4e7ee1ad 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1215,7 +1215,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { and possibly buggy"); } - ast::ItemKind::Impl(_, polarity, _, _, _, _) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { match polarity { ast::ImplPolarity::Negative => { gate_feature_post!(&self, optin_builtin_traits, @@ -1225,6 +1225,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { }, _ => {} } + + match defaultness { + ast::Defaultness::Default => { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); + } + _ => {} + } } _ => {} diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index f39399a62e85..58cf50cdc000 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -897,9 +897,16 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } - ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl( + ItemKind::Impl(unsafety, + polarity, + defaultness, + generics, + ifce, + ty, + impl_items) => ItemKind::Impl( unsafety, polarity, + defaultness, folder.fold_generics(generics), ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), folder.fold_ty(ty), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1baf0d1b54ce..58f81c8b3d75 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4863,7 +4863,9 @@ impl<'a> Parser<'a> { /// impl Foo { ... } /// impl ToString for &'static T { ... } /// impl Send for .. {} - fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> { + fn parse_item_impl(&mut self, + unsafety: ast::Unsafety, + defaultness: Defaultness) -> PResult<'a, ItemInfo> { let impl_span = self.span; // First, parse type parameters if necessary. @@ -4944,7 +4946,7 @@ impl<'a> Parser<'a> { } Ok((keywords::Invalid.ident(), - ItemKind::Impl(unsafety, polarity, generics, opt_trait, ty, impl_items), + ItemKind::Impl(unsafety, polarity, defaultness, generics, opt_trait, ty, impl_items), Some(attrs))) } } @@ -5756,13 +5758,19 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.check_keyword(keywords::Unsafe) && - self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) + if (self.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) && + self.look_ahead(2, |t| t.is_keyword(keywords::Impl))) { // IMPL ITEM + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; self.expect_keyword(keywords::Impl)?; - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe, defaultness)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -5856,9 +5864,16 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Impl) { + if (self.check_keyword(keywords::Impl)) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) + { // IMPL ITEM - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; + let defaultness = self.parse_defaultness()?; + self.expect_keyword(keywords::Impl)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal, defaultness)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index be1d26f8fe48..a911c21ed98d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1317,12 +1317,14 @@ impl<'a> State<'a> { } ast::ItemKind::Impl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -1477,6 +1479,13 @@ impl<'a> State<'a> { } } + pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> { + if let ast::Defaultness::Default = defatulness { + try!(self.word_nbsp("default")); + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &ast::VariantData, generics: &ast::Generics, @@ -1602,9 +1611,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - if let ast::Defaultness::Default = ii.defaultness { - self.word_nbsp("default")?; - } + self.print_defaultness(ii.defaultness)?; match ii.node { ast::ImplItemKind::Const(ref ty, ref expr) => { self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bae1c56db007..2e42c6986e64 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -266,7 +266,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::DefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) } - ItemKind::Impl(_, _, + ItemKind::Impl(_, _, _, ref type_parameters, ref opt_trait_reference, ref typ, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index e96883c26f33..be7883cad5f3 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -658,6 +658,7 @@ impl<'a> TraitDef<'a> { a, ast::ItemKind::Impl(unsafety, ast::ImplPolarity::Positive, + ast::Defaultness::Final, trait_generics, opt_trait_ref, self_type, diff --git a/src/rt/hoedown b/src/rt/hoedown deleted file mode 160000 index da282f1bb727..000000000000 --- a/src/rt/hoedown +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs new file mode 100644 index 000000000000..ad55f44255b4 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs @@ -0,0 +1,46 @@ +// 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(specialization)] + +// Make sure we can't project defaulted associated types + +trait Foo { + type Assoc; +} + +default impl Foo for T { + type Assoc = (); +} + +impl Foo for u8 { + type Assoc = String; +} + +fn generic() -> ::Assoc { + // `T` could be some downstream crate type that specializes (or, + // for that matter, `u8`). + + () //~ ERROR mismatched types +} + +fn monomorphic() -> () { + // Even though we know that `()` is not specialized in a + // downstream crate, typeck refuses to project here. + + generic::<()>() //~ ERROR mismatched types +} + +fn main() { + // No error here, we CAN project from `u8`, as there is no `default` + // in that impl. + let s: String = generic::(); + println!("{}", s); // bad news if this all compiles +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs new file mode 100644 index 000000000000..7353f7ac8c5c --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs @@ -0,0 +1,45 @@ +// 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. + +// It should not be possible to use the concrete value of a defaulted +// associated type in the impl defining it -- otherwise, what happens +// if it's overridden? + +#![feature(specialization)] + +trait Example { + type Output; + fn generate(self) -> Self::Output; +} + +default impl Example for T { + type Output = Box; + fn generate(self) -> Self::Output { + Box::new(self) //~ ERROR mismatched types + } +} + +impl Example for bool { + type Output = bool; + fn generate(self) -> bool { self } +} + +fn trouble(t: T) -> Box { + Example::generate(t) //~ ERROR mismatched types +} + +fn weaponize() -> bool { + let b: Box = trouble(true); + *b +} + +fn main() { + weaponize(); +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs new file mode 100644 index 000000000000..5bab4c5438e5 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.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. + +// Check that specialization must be ungated to use the `default` keyword + +trait Foo { + fn foo(&self); +} + +default impl Foo for T { //~ ERROR specialization is unstable + fn foo(&self) {} +} + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs new file mode 100644 index 000000000000..2874108157d8 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs @@ -0,0 +1,95 @@ +// 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(specialization)] + +// Check a number of scenarios in which one impl tries to override another, +// without correctly using `default`. + +//////////////////////////////////////////////////////////////////////////////// +// Test 1: one layer of specialization, multiple methods, missing `default` +//////////////////////////////////////////////////////////////////////////////// + +trait Foo { + fn foo(&self); + fn bar(&self); +} + +impl Foo for T { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Foo for u8 {} +impl Foo for u16 { + fn foo(&self) {} //~ ERROR E0520 +} +impl Foo for u32 { + fn bar(&self) {} //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 2: one layer of specialization, missing `default` on associated type +//////////////////////////////////////////////////////////////////////////////// + +trait Bar { + type T; +} + +impl Bar for T { + type T = u8; +} + +impl Bar for u8 { + type T = (); //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 3a: multiple layers of specialization, missing interior `default` +//////////////////////////////////////////////////////////////////////////////// + +trait Baz { + fn baz(&self); +} + +default impl Baz for T { + fn baz(&self) {} +} + +impl Baz for T { + fn baz(&self) {} +} + +impl Baz for i32 { + fn baz(&self) {} //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 3b: multiple layers of specialization, missing interior `default`, +// redundant `default` in bottom layer. +//////////////////////////////////////////////////////////////////////////////// + +trait Redundant { + fn redundant(&self); +} + +default impl Redundant for T { + fn redundant(&self) {} +} + +impl Redundant for T { + fn redundant(&self) {} +} + +default impl Redundant for i32 { + fn redundant(&self) {} //~ ERROR E0520 +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs new file mode 100644 index 000000000000..dd060f8ef40d --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs @@ -0,0 +1,53 @@ +// 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(specialization)] + +// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy. + +pub trait Go { + fn go(&self, arg: isize); +} + +pub fn go(this: &G, arg: isize) { + this.go(arg) +} + +pub trait GoMut { + fn go_mut(&mut self, arg: isize); +} + +pub fn go_mut(this: &mut G, arg: isize) { + this.go_mut(arg) +} + +pub trait GoOnce { + fn go_once(self, arg: isize); +} + +pub fn go_once(this: G, arg: isize) { + this.go_once(arg) +} + +default impl GoMut for G + where G : Go +{ + fn go_mut(&mut self, arg: isize) { + go(&*self, arg) + } +} + +default impl GoOnce for G + where G : GoMut +{ + fn go_once(mut self, arg: isize) { + go_mut(&mut self, arg) + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs new file mode 100644 index 000000000000..71dd7c99009e --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs @@ -0,0 +1,82 @@ +// 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(specialization)] + +pub trait Foo { + fn foo(&self) -> &'static str; +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +pub trait MyMarker {} +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs new file mode 100644 index 000000000000..9d0ea64fed42 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs @@ -0,0 +1,49 @@ +// 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(specialization)] + +// First, test only use of explicit `default` items: + +pub trait Foo { + fn foo(&self) -> bool; +} + +default impl Foo for T { + fn foo(&self) -> bool { false } +} + +impl Foo for i32 {} + +impl Foo for i64 { + fn foo(&self) -> bool { true } +} + +// Next, test mixture of explicit `default` and provided methods: + +pub trait Bar { + fn bar(&self) -> i32 { 0 } +} + +impl Bar for T {} // use the provided method + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + fn bar(&self) -> i32 { 3 } +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs new file mode 100644 index 000000000000..6b999f383583 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs @@ -0,0 +1,31 @@ +// 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. + +// aux-build:go_trait.rs + +#![feature(specialization)] + +extern crate go_trait; + +use go_trait::{Go,GoMut}; +use std::fmt::Debug; +use std::default::Default; + +struct MyThingy; + +impl Go for MyThingy { + fn go(&self, arg: isize) { } +} + +impl GoMut for MyThingy { + fn go_mut(&mut self, arg: isize) { } +} + +fn main() { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs new file mode 100644 index 000000000000..b99ba3d0f1c9 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.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. + +// Test that non-method associated functions can be specialized + +#![feature(specialization)] + +trait Foo { + fn mk() -> Self; +} + +default impl Foo for T { + fn mk() -> T { + T::default() + } +} + +impl Foo for Vec { + fn mk() -> Vec { + vec![0] + } +} + +fn main() { + let v1: Vec = Foo::mk(); + let v2: Vec = Foo::mk(); + + assert!(v1.len() == 0); + assert!(v2.len() == 1); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs new file mode 100644 index 000000000000..594f1e4fcdfc --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs @@ -0,0 +1,106 @@ +// 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(specialization)] + +// Tests a variety of basic specialization scenarios and method +// dispatch for them. + +trait Foo { + fn foo(&self) -> &'static str; +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +trait MyMarker {} +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} + +#[derive(Clone)] +struct MarkedAndClone; +impl MyMarker for MarkedAndClone {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs new file mode 100644 index 000000000000..62c7e3e2e443 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs @@ -0,0 +1,49 @@ +// 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. + +// aux-build:specialization_cross_crate_defaults.rs + +#![feature(specialization)] + +extern crate specialization_cross_crate_defaults; + +use specialization_cross_crate_defaults::*; + +struct LocalDefault; +struct LocalOverride; + +impl Foo for LocalDefault {} + +impl Foo for LocalOverride { + fn foo(&self) -> bool { true } +} + +fn test_foo() { + assert!(!0i8.foo()); + assert!(!0i32.foo()); + assert!(0i64.foo()); + + assert!(!LocalDefault.foo()); + assert!(LocalOverride.foo()); +} + +fn test_bar() { + assert!(0u8.bar() == 0); + assert!(0i32.bar() == 1); + assert!("hello".bar() == 0); + assert!(vec![()].bar() == 2); + assert!(vec![0i32].bar() == 2); + assert!(vec![0i64].bar() == 3); +} + +fn main() { + test_foo(); + test_bar(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs new file mode 100644 index 000000000000..b9548539e164 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs @@ -0,0 +1,29 @@ +// 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. + +// Test that specialization works even if only the upstream crate enables it + +// aux-build:specialization_cross_crate.rs + +extern crate specialization_cross_crate; + +use specialization_cross_crate::*; + +fn main() { + assert!(0u8.foo() == "generic Clone"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs new file mode 100644 index 000000000000..7517824b62bb --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs @@ -0,0 +1,58 @@ +// 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. + +// aux-build:specialization_cross_crate.rs + +#![feature(specialization)] + +extern crate specialization_cross_crate; + +use specialization_cross_crate::*; + +struct NotClone; + +#[derive(Clone)] +struct MarkedAndClone; +impl MyMarker for MarkedAndClone {} + +struct MyType(T); +default impl Foo for MyType { + fn foo(&self) -> &'static str { + "generic MyType" + } +} + +impl Foo for MyType { + fn foo(&self) -> &'static str { + "MyType" + } +} + +struct MyOtherType; +impl Foo for MyOtherType {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); + + assert!(MyType(()).foo() == "generic MyType"); + assert!(MyType(0u8).foo() == "MyType"); + assert!(MyOtherType.foo() == "generic"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs new file mode 100644 index 000000000000..4ac9afc1c897 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs @@ -0,0 +1,94 @@ +// 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(specialization)] + +// Test that default methods are cascaded correctly + +// First, test only use of explicit `default` items: + +trait Foo { + fn foo(&self) -> bool; +} + +// Specialization tree for Foo: +// +// T +// / \ +// i32 i64 + +default impl Foo for T { + fn foo(&self) -> bool { false } +} + +impl Foo for i32 {} + +impl Foo for i64 { + fn foo(&self) -> bool { true } +} + +fn test_foo() { + assert!(!0i8.foo()); + assert!(!0i32.foo()); + assert!(0i64.foo()); +} + +// Next, test mixture of explicit `default` and provided methods: + +trait Bar { + fn bar(&self) -> i32 { 0 } +} + +// Specialization tree for Bar. +// Uses of $ designate that method is provided +// +// $Bar (the trait) +// | +// T +// /|\ +// / | \ +// / | \ +// / | \ +// / | \ +// / | \ +// $i32 &str $Vec +// /\ +// / \ +// Vec $Vec + +// use the provided method +impl Bar for T {} + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + fn bar(&self) -> i32 { 3 } +} + +fn test_bar() { + assert!(0u8.bar() == 0); + assert!(0i32.bar() == 1); + assert!("hello".bar() == 0); + assert!(vec![()].bar() == 2); + assert!(vec![0i32].bar() == 2); + assert!(vec![0i64].bar() == 3); +} + +fn main() { + test_foo(); + test_bar(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs new file mode 100644 index 000000000000..f77b88e2f850 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs @@ -0,0 +1,27 @@ +// 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 that you can list the more specific impl before the more general one. + +#![feature(specialization)] + +trait Foo { + type Out; +} + +impl Foo for bool { + type Out = (); +} + +default impl Foo for T { + type Out = bool; +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs new file mode 100644 index 000000000000..500cded38c1a --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs @@ -0,0 +1,33 @@ +// 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 that impls on projected self types can resolve overlap, even when the +// projections involve specialization, so long as the associated type is +// provided by the most specialized impl. + +#![feature(specialization)] + +trait Assoc { + type Output; +} + +default impl Assoc for T { + type Output = bool; +} + +impl Assoc for u8 { type Output = u8; } +impl Assoc for u16 { type Output = u16; } + +trait Foo {} +impl Foo for u32 {} +impl Foo for ::Output {} +impl Foo for ::Output {} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs new file mode 100644 index 000000000000..2397c3e2bff5 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs @@ -0,0 +1,32 @@ +// 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. + +#![feature(specialization)] + +// Regression test for ICE when combining specialized associated types and type +// aliases + +trait Id_ { + type Out; +} + +type Id = ::Out; + +default impl Id_ for T { + type Out = T; +} + +fn test_proection() { + let x: Id = panic!(); +} + +fn main() { + +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs new file mode 100644 index 000000000000..6a833ba6760f --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs @@ -0,0 +1,49 @@ +// 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(specialization)] + +// Make sure we *can* project non-defaulted associated types +// cf compile-fail/specialization-default-projection.rs + +// First, do so without any use of specialization + +trait Foo { + type Assoc; +} + +impl Foo for T { + type Assoc = (); +} + +fn generic_foo() -> ::Assoc { + () +} + +// Next, allow for one layer of specialization + +trait Bar { + type Assoc; +} + +default impl Bar for T { + type Assoc = (); +} + +impl Bar for T { + type Assoc = u8; +} + +fn generic_bar_clone() -> ::Assoc { + 0u8 +} + +fn main() { +} From 6427fdce7a4c7b9d98bdffd396021046c8f8347f Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 21 Nov 2016 11:59:52 +0100 Subject: [PATCH 686/905] support `default impl` for specialization fix tidy --- src/librustdoc/visit_ast.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4ffc8c97c500..d463e41c58a2 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,7 +502,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.traits.push(t); }, - hir::ItemImpl(unsafety, polarity, defaultness, ref gen, ref tr, ref ty, ref item_ids) => { + hir::ItemImpl(unsafety, + polarity, + defaultness, + ref gen, + ref tr, + ref ty, + ref item_ids) => { // Don't duplicate impls when inlining, we'll pick them up // regardless of where they're located. if !self.inlining { From b0fca5f790e86a4235c64095f4ac55d325253b92 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 21 Nov 2016 18:39:25 +0000 Subject: [PATCH 687/905] support `default impl` for specialization rebase after support for llvm-3.7 --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/print.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5fb8170cd6c3..d072340d8c88 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1346,7 +1346,7 @@ impl<'a> LoweringContext<'a> { hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), - self.lower_defaultness(defaultness), + self.lower_defaultness(defaultness, true /* [1] */), self.lower_generics(generics), ifce, self.lower_ty(ty), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index dec0753be064..a78d5ce1c16d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -823,8 +823,9 @@ impl<'a> State<'a> { } pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { - if let hir::Defaultness::Default = defaultness { - self.word_nbsp("default")?; + match defaultness { + hir::Defaultness::Default { .. } => self.word_nbsp("default")?, + hir::Defaultness::Final => (), } Ok(()) } From f852e3fcbcdbcc42d7eb215b08bb3539f76b8ca1 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 24 Apr 2017 07:47:00 -0400 Subject: [PATCH 688/905] use the word 'length' in Vec::len's docs Fixes #37866 --- src/libcollections/vec.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 6deb87ae7720..1d443b19d80a 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1147,7 +1147,8 @@ impl Vec { self.truncate(0) } - /// Returns the number of elements in the vector. + /// Returns the number of elements in the vector, also referred to + /// as its 'length'. /// /// # Examples /// From 612bb1f54e8c6c424b6664e16301354c545be34d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 24 Apr 2017 15:20:46 +0300 Subject: [PATCH 689/905] rustc: rename some of the queries to match tcx methods. --- src/librustc/cfg/construct.rs | 2 +- src/librustc/infer/mod.rs | 4 +- src/librustc/middle/dead.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/mem_categorization.rs | 4 +- src/librustc/mir/mod.rs | 2 +- src/librustc/mir/tcx.rs | 2 +- src/librustc/traits/error_reporting.rs | 6 +- src/librustc/traits/mod.rs | 2 +- src/librustc/traits/object_safety.rs | 12 +- src/librustc/traits/project.rs | 8 +- src/librustc/traits/select.rs | 14 +- src/librustc/traits/specialize/mod.rs | 4 +- src/librustc/traits/util.rs | 6 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/item_path.rs | 4 +- src/librustc/ty/maps.rs | 14 +- src/librustc/ty/mod.rs | 68 ++++---- src/librustc/ty/relate.rs | 2 +- src/librustc/ty/sty.rs | 6 +- src/librustc/ty/subst.rs | 10 +- src/librustc/ty/util.rs | 10 +- src/librustc/ty/wf.rs | 2 +- src/librustc/util/ppaux.rs | 10 +- src/librustc_borrowck/borrowck/mod.rs | 4 +- src/librustc_const_eval/eval.rs | 6 +- src/librustc_const_eval/pattern.rs | 4 +- src/librustc_lint/builtin.rs | 18 +-- src/librustc_lint/types.rs | 6 +- src/librustc_metadata/cstore_impl.rs | 12 +- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/encoder.rs | 36 ++--- src/librustc_mir/build/scope.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 2 +- src/librustc_mir/mir_map.rs | 2 +- src/librustc_mir/shim.rs | 8 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/transform/type_check.rs | 2 +- src/librustc_passes/consts.rs | 2 +- src/librustc_privacy/lib.rs | 56 +++---- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 2 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/collector.rs | 4 +- src/librustc_trans/common.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 4 +- src/librustc_trans/trans_item.rs | 2 +- src/librustc_typeck/astconv.rs | 14 +- src/librustc_typeck/check/compare_method.rs | 24 +-- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/dropck.rs | 8 +- src/librustc_typeck/check/intrinsic.rs | 8 +- src/librustc_typeck/check/method/confirm.rs | 6 +- src/librustc_typeck/check/method/mod.rs | 6 +- src/librustc_typeck/check/method/probe.rs | 16 +- src/librustc_typeck/check/mod.rs | 74 ++++----- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 34 ++-- src/librustc_typeck/check_unused.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 8 +- .../coherence/inherent_impls.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/coherence/overlap.rs | 2 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustc_typeck/collect.rs | 148 +++++++++--------- src/librustc_typeck/impl_wf_check.rs | 8 +- src/librustc_typeck/lib.rs | 4 +- src/librustc_typeck/variance/constraints.rs | 22 +-- src/librustc_typeck/variance/solve.rs | 3 +- src/librustc_typeck/variance/terms.rs | 3 +- src/librustdoc/clean/inline.rs | 52 +++--- src/librustdoc/clean/mod.rs | 28 ++-- src/librustdoc/clean/simplify.rs | 2 +- 77 files changed, 435 insertions(+), 437 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 20b322ec1895..d234e408a22d 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -52,7 +52,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Find the tables for this body. let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id())); - let tables = tcx.item_tables(owner_def_id); + let tables = tcx.typeck_tables_of(owner_def_id); let mut cfg_builder = CFGBuilder { tcx: tcx, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4d8b31a33cde..e75513e924ee 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -450,7 +450,7 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId { Option>, Option>) { let item_id = tcx.hir.body_owner(self); - (Some(tcx.item_tables(tcx.hir.local_def_id(item_id))), + (Some(tcx.typeck_tables_of(tcx.hir.local_def_id(item_id))), None, Some(ty::ParameterEnvironment::for_item(tcx, item_id))) } @@ -1237,7 +1237,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { substs: &[Kind<'tcx>]) -> Ty<'tcx> { let default = if def.has_default { - let default = self.tcx.item_type(def.def_id); + let default = self.tcx.type_of(def.def_id); Some(type_variable::Default { ty: default.subst_spanned(self.tcx, substs, Some(span)), origin_span: span, diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 63d90d93bb51..0be8484b7840 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { match item.node { hir::ItemStruct(..) | hir::ItemUnion(..) => { let def_id = self.tcx.hir.local_def_id(item.id); - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); self.struct_has_extern_repr = def.repr.c(); intravisit::walk_item(self, &item); @@ -433,7 +433,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { - let field_type = self.tcx.item_type(self.tcx.hir.local_def_id(field.id)); + let field_type = self.tcx.type_of(self.tcx.hir.local_def_id(field.id)); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8b2631591582..82e7d972c579 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -998,7 +998,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { let enum_did = tcx.parent_def_id(variant_did).unwrap(); - let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() { + let downcast_cmt = if tcx.adt_def(enum_did).is_univariant() { cmt_pat } else { let cmt_pat_ty = cmt_pat.ty; diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index ecc0bb9fe497..435dd05358d4 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -66,7 +66,7 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.infcx.tcx.item_type(def_id).sty { + let intrinsic = match self.infcx.tcx.type_of(def_id).sty { ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic, _ => return false }; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b7da8480c1ce..631046788629 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1426,7 +1426,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { entry_ln: LiveNode, body: &hir::Body) { - let fn_ty = self.ir.tcx.item_type(self.ir.tcx.hir.local_def_id(id)); + let fn_ty = self.ir.tcx.type_of(self.ir.tcx.hir.local_def_id(id)); let fn_sig = match fn_ty.sty { ty::TyClosure(closure_def_id, substs) => { self.ir.tcx.closure_type(closure_def_id) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 188fcc914149..677eca10d7ba 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1159,7 +1159,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Def::VariantCtor(variant_did, ..) => { // univariant enums do not need downcasts let enum_did = self.tcx().parent_def_id(variant_did).unwrap(); - if !self.tcx().lookup_adt_def(enum_did).is_univariant() { + if !self.tcx().adt_def(enum_did).is_univariant() { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) } else { cmt @@ -1177,7 +1177,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expected_len = match def { Def::VariantCtor(def_id, CtorKind::Fn) => { let enum_def = self.tcx().parent_def_id(def_id).unwrap(); - self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len() + self.tcx().adt_def(enum_def).variant_with_id(def_id).fields.len() } Def::StructCtor(_, CtorKind::Fn) => { match self.pat_ty(&pat)?.sty { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index bfb72b5df7b2..724d4f457dea 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1015,7 +1015,7 @@ impl<'tcx> Operand<'tcx> { ) -> Self { Operand::Constant(Constant { span: span, - ty: tcx.item_type(def_id).subst(tcx, substs), + ty: tcx.type_of(def_id).subst(tcx, substs), literal: Literal::Value { value: ConstVal::Function(def_id, substs) }, }) } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f40b9c605375..b6020df07285 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -194,7 +194,7 @@ impl<'tcx> Rvalue<'tcx> { ) } AggregateKind::Adt(def, _, substs, _) => { - tcx.item_type(def.did).subst(tcx, substs) + tcx.type_of(def.did).subst(tcx, substs) } AggregateKind::Closure(did, substs) => { tcx.mk_closure_from_closure_substs(did, substs) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba340a40692c..353677f4f2be 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -258,7 +258,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut self_match_impls = vec![]; let mut fuzzy_match_impls = vec![]; - self.tcx.lookup_trait_def(trait_ref.def_id) + self.tcx.trait_def(trait_ref.def_id) .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| { let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); let impl_trait_ref = tcx @@ -314,7 +314,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let trait_str = self.tcx.item_path_str(trait_ref.def_id); if let Some(istring) = item.value_str() { let istring = &*istring.as_str(); - let generics = self.tcx.item_generics(trait_ref.def_id); + let generics = self.tcx.generics_of(trait_ref.def_id); let generic_map = generics.types.iter().map(|param| { (param.name.as_str().to_string(), trait_ref.substs.type_for_def(param).to_string()) @@ -372,7 +372,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref.skip_binder().self_ty(), true); let mut impl_candidates = Vec::new(); - let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id()); + let trait_def = self.tcx.trait_def(trait_ref.def_id()); match simp { Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 281c1e253798..a7f9cc74c4f5 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -641,7 +641,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // 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). - let predicates = tcx.item_predicates(def_id).instantiate_own(tcx, substs); + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index d190635bec30..f8d6058db3f2 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -74,7 +74,7 @@ pub enum MethodViolationCode { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn is_object_safe(self, trait_def_id: DefId) -> bool { // Because we query yes/no results frequently, we keep a cache: - let def = self.lookup_trait_def(trait_def_id); + let def = self.trait_def(trait_def_id); let result = def.object_safety().unwrap_or_else(|| { let result = self.object_safety_violations(trait_def_id).is_empty(); @@ -158,9 +158,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { substs: Substs::identity_for_item(self, trait_def_id) }); let predicates = if supertraits_only { - self.item_super_predicates(trait_def_id) + self.super_predicates_of(trait_def_id) } else { - self.item_predicates(trait_def_id) + self.predicates_of(trait_def_id) }; predicates .predicates @@ -199,7 +199,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Search for a predicate like `Self : Sized` amongst the trait bounds. let free_substs = self.construct_free_substs(def_id, self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = self.item_predicates(def_id); + let predicates = self.predicates_of(def_id); let predicates = predicates.instantiate(self, free_substs).predicates; elaborate_predicates(self, predicates) .any(|predicate| { @@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = self.item_type(method.def_id).fn_sig(); + let ref sig = self.type_of(method.def_id).fn_sig(); for input_ty in &sig.skip_binder().inputs()[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -283,7 +283,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !self.item_generics(method.def_id).types.is_empty() { + if !self.generics_of(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3d8f9e41c675..7e0954c92a66 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -279,7 +279,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) // Only normalize `impl Trait` after type-checking, usually in trans. if self.selcx.projection_mode() == Reveal::All { - let generic_ty = self.tcx().item_type(def_id); + let generic_ty = self.tcx().type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.fold_ty(concrete_ty) } else { @@ -787,7 +787,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = selcx.tcx().item_predicates(def_id); + let trait_predicates = selcx.tcx().predicates_of(def_id); let bounds = trait_predicates.instantiate(selcx.tcx(), substs); let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates); assemble_candidates_from_predicates(selcx, @@ -1288,7 +1288,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.trait_ref); tcx.types.err } else { - tcx.item_type(node_item.item.def_id) + tcx.type_of(node_item.item.def_id) }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { @@ -1317,7 +1317,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( -> Option> { let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; - let trait_def = selcx.tcx().lookup_trait_def(trait_def_id); + let trait_def = selcx.tcx().trait_def(trait_def_id); if !trait_def.is_complete(selcx.tcx()) { let impl_node = specialization_graph::Node::Impl(impl_def_id); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 207016170faa..cccc20e5b296 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -842,7 +842,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - if self.tcx().trait_impl_polarity(def_id) == hir::ImplPolarity::Negative { + if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) } } @@ -1222,8 +1222,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { def_id={:?}, substs={:?}", def_id, substs); - let item_predicates = self.tcx().item_predicates(def_id); - let bounds = item_predicates.instantiate(self.tcx(), substs); + let predicates_of = self.tcx().predicates_of(def_id); + let bounds = predicates_of.instantiate(self.tcx(), substs); debug!("match_projection_obligation_against_definition_bounds: \ bounds={:?}", bounds); @@ -1432,7 +1432,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - let def = self.tcx().lookup_trait_def(obligation.predicate.def_id()); + let def = self.tcx().trait_def(obligation.predicate.def_id()); def.for_each_relevant_impl( self.tcx(), @@ -1947,7 +1947,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)] + vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] } } } @@ -2526,7 +2526,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (&ty::TyAdt(def, substs_a), &ty::TyAdt(_, substs_b)) => { let fields = def .all_fields() - .map(|f| tcx.item_type(f.did)) + .map(|f| tcx.type_of(f.did)) .collect::>(); // The last field of the structure has to exist and contain type parameters. @@ -2844,7 +2844,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx.item_predicates(def_id); + let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); let predicates = predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, cause.clone(), recursion_depth, diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 5f02688be34b..6c685851e259 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -117,7 +117,7 @@ pub fn find_associated_item<'a, 'tcx>( assert!(!substs.needs_infer()); let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); - let trait_def = tcx.lookup_trait_def(trait_def_id); + let trait_def = tcx.trait_def(trait_def_id); let ancestors = trait_def.ancestors(impl_data.impl_def_id); match ancestors.defs(tcx, item.name, item.kind).next() { @@ -175,7 +175,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // See RFC 1210 for more details and justification. // Currently we do not allow e.g. a negative impl to specialize a positive one - if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) { + if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) { return false; } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index d4245ec9b247..396c7dbd1a87 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -130,7 +130,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { match *predicate { ty::Predicate::Trait(ref data) => { // Predicates declared on the trait. - let predicates = tcx.item_super_predicates(data.def_id()); + let predicates = tcx.super_predicates_of(data.def_id()); let mut predicates: Vec<_> = predicates.predicates @@ -301,7 +301,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> { None => { return None; } }; - let predicates = self.tcx.item_super_predicates(def_id); + let predicates = self.tcx.super_predicates_of(def_id); let visited = &mut self.visited; self.stack.extend( predicates.predicates @@ -368,7 +368,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - let predicates = selcx.tcx().item_predicates(impl_def_id); + let predicates = selcx.tcx().predicates_of(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = super::normalize(selcx, ObligationCause::dummy(), &predicates); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b20ac8ddbfc8..ac7a72e66655 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1258,7 +1258,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); - let adt_def = self.lookup_adt_def(def_id); + let adt_def = self.adt_def(def_id); let substs = self.mk_substs(iter::once(Kind::from(ty))); self.mk_ty(TyAdt(adt_def, substs)) } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index cfff3d0e5736..7dca28df9da3 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -52,7 +52,7 @@ impl<'tcx> InstanceDef<'tcx> { #[inline] pub fn def_ty<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { - tcx.item_type(self.def_id()) + tcx.type_of(self.def_id()) } #[inline] diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 386991052905..9aa2caadd1d3 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -203,7 +203,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // for local crates, check whether type info is // available; typeck might not have completed yet self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) && - self.maps.ty.borrow().contains_key(&impl_def_id) + self.maps.type_of.borrow().contains_key(&impl_def_id) }; if !use_types { @@ -215,7 +215,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // users may find it useful. Currently, we omit the parent if // the impl is either in the same module as the self-type or // as the trait. - let self_ty = self.item_type(impl_def_id); + let self_ty = self.type_of(impl_def_id); let in_self_mod = match characteristic_def_id_of_type(self_ty) { None => false, Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4595a8c4f778..f743da24972a 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -175,7 +175,7 @@ impl> QueryDescription for M { } } -impl<'tcx> QueryDescription for queries::super_predicates<'tcx> { +impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("computing the supertraits of `{}`", tcx.item_path_str(def_id)) @@ -380,12 +380,12 @@ macro_rules! define_maps { // the driver creates (using several `rustc_*` crates). define_maps! { <'tcx> /// Records the type of every item. - pub ty: ItemSignature(DefId) -> Ty<'tcx>, + pub type_of: ItemSignature(DefId) -> Ty<'tcx>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its /// associated generics and predicates. - pub generics: ItemSignature(DefId) -> &'tcx ty::Generics, - pub predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, + pub generics_of: ItemSignature(DefId) -> &'tcx ty::Generics, + pub predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, /// Maps from the def-id of a trait to the list of /// super-predicates. This is a subset of the full list of @@ -393,7 +393,7 @@ define_maps! { <'tcx> /// evaluate them even during type conversion, often before the /// full predicates are available (note that supertraits have /// additional acyclicity requirements). - pub super_predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, + pub super_predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. @@ -411,7 +411,7 @@ define_maps! { <'tcx> /// Maps from def-id of a type or region parameter to its /// (inferred) variance. - pub variances: ItemSignature(DefId) -> Rc>, + pub variances_of: ItemSignature(DefId) -> Rc>, /// Maps from an impl/trait def-id to a list of the def-ids of its items pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc>, @@ -455,7 +455,7 @@ define_maps! { <'tcx> pub typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult, - pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, + pub typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 352b6ab1d356..d5cd3742ffcc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -165,9 +165,9 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { let header = ImplHeader { impl_def_id: impl_def_id, - self_ty: tcx.item_type(impl_def_id), + self_ty: tcx.type_of(impl_def_id), trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.item_predicates(impl_def_id).predicates + predicates: tcx.predicates_of(impl_def_id).predicates }.subst(tcx, impl_substs); let traits::Normalized { value: mut header, obligations } = @@ -727,7 +727,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { instantiated: &mut InstantiatedPredicates<'tcx>, substs: &Substs<'tcx>) { if let Some(def_id) = self.parent { - tcx.item_predicates(def_id).instantiate_into(tcx, instantiated, substs); + tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs); } instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs))) } @@ -1633,7 +1633,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { #[inline] pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> { - tcx.item_predicates(self.did) + tcx.predicates_of(self.did) } /// Returns an iterator over all fields contained @@ -1840,7 +1840,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); - let predicates = tcx.item_predicates(self.did).predicates; + let predicates = tcx.predicates_of(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { vec![] } else { @@ -1881,7 +1881,7 @@ impl<'a, 'gcx, 'tcx> VariantDef { impl<'a, 'gcx, 'tcx> FieldDef { pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { - tcx.item_type(self.did).subst(tcx, subst) + tcx.type_of(self.did).subst(tcx, subst) } } @@ -2042,11 +2042,11 @@ impl<'gcx> ::std::ops::Deref for Attributes<'gcx> { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> { - self.item_tables(self.hir.body_owner_def_id(body)) + self.typeck_tables_of(self.hir.body_owner_def_id(body)) } - pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> { - queries::typeck_tables::get(self, DUMMY_SP, def_id) + pub fn typeck_tables_of(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> { + queries::typeck_tables_of::get(self, DUMMY_SP, def_id) } pub fn expr_span(self, id: NodeId) -> Span { @@ -2136,7 +2136,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect() } - pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { + pub fn impl_polarity(self, id: DefId) -> hir::ImplPolarity { queries::impl_polarity::get(self, DUMMY_SP, id) } @@ -2238,7 +2238,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() }); - self.trait_impl_polarity(def_id1) == self.trait_impl_polarity(def_id2) + self.impl_polarity(def_id1) == self.impl_polarity(def_id2) && trait1_is_empty && trait2_is_empty } @@ -2249,14 +2249,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match def { Def::Variant(did) | Def::VariantCtor(did, ..) => { let enum_did = self.parent_def_id(did).unwrap(); - self.lookup_adt_def(enum_did).variant_with_id(did) + self.adt_def(enum_did).variant_with_id(did) } Def::Struct(did) | Def::Union(did) => { - self.lookup_adt_def(did).struct_variant() + self.adt_def(did).struct_variant() } Def::StructCtor(ctor_did, ..) => { let did = self.parent_def_id(ctor_did).expect("struct ctor has no parent"); - self.lookup_adt_def(did).struct_variant() + self.adt_def(did).struct_variant() } _ => bug!("expect_variant_def used with unexpected def {:?}", def) } @@ -2327,33 +2327,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // If the given item is in an external crate, looks up its type and adds it to // the type cache. Returns the type parameters and type. - pub fn item_type(self, did: DefId) -> Ty<'gcx> { - queries::ty::get(self, DUMMY_SP, did) + pub fn type_of(self, did: DefId) -> Ty<'gcx> { + queries::type_of::get(self, DUMMY_SP, did) } /// Given the did of a trait, returns its canonical trait ref. - pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef { + pub fn trait_def(self, did: DefId) -> &'gcx TraitDef { queries::trait_def::get(self, DUMMY_SP, did) } /// Given the did of an ADT, return a reference to its definition. - pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef { + pub fn adt_def(self, did: DefId) -> &'gcx AdtDef { queries::adt_def::get(self, DUMMY_SP, did) } /// Given the did of an item, returns its generics. - pub fn item_generics(self, did: DefId) -> &'gcx Generics { - queries::generics::get(self, DUMMY_SP, did) + pub fn generics_of(self, did: DefId) -> &'gcx Generics { + queries::generics_of::get(self, DUMMY_SP, did) } /// Given the did of an item, returns its full set of predicates. - pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - queries::predicates::get(self, DUMMY_SP, did) + pub fn predicates_of(self, did: DefId) -> GenericPredicates<'gcx> { + queries::predicates_of::get(self, DUMMY_SP, did) } /// Given the did of a trait, returns its superpredicates. - pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - queries::super_predicates::get(self, DUMMY_SP, did) + pub fn super_predicates_of(self, did: DefId) -> GenericPredicates<'gcx> { + queries::super_predicates_of::get(self, DUMMY_SP, did) } /// Given the did of an item, returns its MIR, borrowed immutably. @@ -2399,12 +2399,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_attrs(did).iter().any(|item| item.check_name(attr)) } - pub fn item_variances(self, item_id: DefId) -> Rc> { - queries::variances::get(self, DUMMY_SP, item_id) + pub fn variances_of(self, item_id: DefId) -> Rc> { + queries::variances_of::get(self, DUMMY_SP, item_id) } pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { - let def = self.lookup_trait_def(trait_def_id); + let def = self.trait_def(trait_def_id); def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) } @@ -2419,7 +2419,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // metadata and don't need to track edges. let _ignore = self.dep_graph.in_ignore(); - let def = self.lookup_trait_def(trait_id); + let def = self.trait_def(trait_id); if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) { return; } @@ -2553,7 +2553,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // let tcx = self.global_tcx(); - let generic_predicates = tcx.item_predicates(def_id); + let generic_predicates = tcx.predicates_of(def_id); let bounds = generic_predicates.instantiate(tcx, free_substs); let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); let predicates = bounds.predicates; @@ -2678,12 +2678,12 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx [Ty<'tcx>] { - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { v.fields.last() }).flat_map(|f| { - def.sized_constraint_for_ty(tcx, tcx.item_type(f.did)) + def.sized_constraint_for_ty(tcx, tcx.type_of(f.did)) }).collect::>()); debug!("adt_sized_constraint: {:?} => {:?}", def, result); @@ -2695,7 +2695,7 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> DtorckConstraint<'tcx> { - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); debug!("dtorck_constraint: {:?}", def); @@ -2703,7 +2703,7 @@ fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let result = DtorckConstraint { outlives: vec![], dtorck_types: vec![ - tcx.mk_param_from_def(&tcx.item_generics(def_id).types[0]) + tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0]) ] }; debug!("dtorck_constraint: {:?} => {:?}", def, result); @@ -2711,7 +2711,7 @@ fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let mut result = def.all_fields() - .map(|field| tcx.item_type(field.did)) + .map(|field| tcx.type_of(field.did)) .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty)) .collect::>() .unwrap_or(DtorckConstraint::empty()); diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index cef24d44d687..58ebc843da10 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -126,7 +126,7 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, let variances; let opt_variances = if relation.tcx().variance_computed.get() { - variances = relation.tcx().item_variances(item_def_id); + variances = relation.tcx().variances_of(item_def_id); Some(&*variances) } else { None diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d59248170344..7857d07ed091 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) -> impl Iterator> + 'tcx { - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); self.substs[self.substs.len()-generics.own_count()..].iter().map( |t| t.as_type().expect("unexpected region in upvars")) } @@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> { (Trait(_), Trait(_)) => Ordering::Equal, (Projection(ref a), Projection(ref b)) => a.sort_key(tcx).cmp(&b.sort_key(tcx)), (AutoTrait(ref a), AutoTrait(ref b)) => - tcx.lookup_trait_def(*a).def_path_hash.cmp(&tcx.lookup_trait_def(*b).def_path_hash), + tcx.trait_def(*a).def_path_hash.cmp(&tcx.trait_def(*b).def_path_hash), (Trait(_), _) => Ordering::Less, (Projection(_), Trait(_)) => Ordering::Greater, (Projection(_), _) => Ordering::Less, @@ -841,7 +841,7 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { // We want something here that is stable across crate boundaries. // The DefId isn't but the `deterministic_hash` of the corresponding // DefPath is. - let trait_def = tcx.lookup_trait_def(self.trait_ref.def_id); + let trait_def = tcx.trait_def(self.trait_ref.def_id); let def_path_hash = trait_def.def_path_hash; // An `ast::Name` is also not stable (it's just an index into an diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 14aebdf8418f..961140d5eac6 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -185,7 +185,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { -> &'tcx Substs<'tcx> where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.item_generics(def_id); + let defs = tcx.generics_of(def_id); let mut substs = Vec::with_capacity(defs.count()); Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type); tcx.intern_substs(&substs) @@ -200,7 +200,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.item_generics(def_id); + let defs = tcx.generics_of(def_id); let mut result = Vec::with_capacity(defs.count()); result.extend(self[..].iter().cloned()); Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type); @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { if let Some(def_id) = defs.parent { - let parent_defs = tcx.item_generics(def_id); + let parent_defs = tcx.generics_of(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } Substs::fill_single(substs, defs, mk_region, mk_type) @@ -297,7 +297,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { source_ancestor: DefId, target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { - let defs = tcx.item_generics(source_ancestor); + let defs = tcx.generics_of(source_ancestor); tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } @@ -553,7 +553,7 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { trait_id: DefId, substs: &Substs<'tcx>) -> ty::TraitRef<'tcx> { - let defs = tcx.item_generics(trait_id); + let defs = tcx.generics_of(trait_id); ty::TraitRef { def_id: trait_id, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index f68cf6f97f85..007647a3297c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -372,8 +372,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait)); let mut dtor_did = None; - let ty = self.item_type(adt_did); - self.lookup_trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| { + let ty = self.type_of(adt_did); + self.trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| { if let Some(item) = self.associated_items(impl_did).next() { if let Ok(()) = validate(self, impl_did) { dtor_did = Some(item.def_id); @@ -422,7 +422,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } let impl_def_id = self.associated_item(dtor).container.id(); - let impl_generics = self.item_generics(impl_def_id); + let impl_generics = self.generics_of(impl_def_id); // We have a destructor - all the parameters that are not // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute) @@ -445,12 +445,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // , and then look up which of the impl substs refer to // parameters marked as pure. - let impl_substs = match self.item_type(impl_def_id).sty { + let impl_substs = match self.type_of(impl_def_id).sty { ty::TyAdt(def_, substs) if def_ == def => substs, _ => bug!() }; - let item_substs = match self.item_type(def.did).sty { + let item_substs = match self.type_of(def.did).sty { ty::TyAdt(def_, substs) if def_ == def => substs, _ => bug!() }; diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 0b0e8a180cc3..6c7073de70bb 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -443,7 +443,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { -> Vec> { let predicates = - self.infcx.tcx.item_predicates(def_id) + self.infcx.tcx.predicates_of(def_id) .instantiate(self.infcx.tcx, substs); let cause = self.cause(traits::ItemObligation(def_id)); predicates.predicates diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 2daf71d95add..df5a2731c890 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -104,7 +104,7 @@ pub fn parameterized(f: &mut fmt::Formatter, } } } - let mut generics = tcx.item_generics(item_def_id); + let mut generics = tcx.generics_of(item_def_id); let mut path_def_id = did; verbose = tcx.sess.verbose(); has_self = generics.has_self; @@ -114,7 +114,7 @@ pub fn parameterized(f: &mut fmt::Formatter, // Methods. assert!(is_value_path); child_types = generics.types.len(); - generics = tcx.item_generics(def_id); + generics = tcx.generics_of(def_id); num_regions = generics.regions.len(); num_types = generics.types.len(); @@ -144,7 +144,7 @@ pub fn parameterized(f: &mut fmt::Formatter, if !def.has_default { break; } - if tcx.item_type(def.def_id).subst(tcx, substs) != actual { + if tcx.type_of(def.def_id).subst(tcx, substs) != actual { break; } num_supplied_defaults += 1; @@ -772,11 +772,11 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { ty::tls::with(|tcx| { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = tcx.item_predicates(def_id); + let predicates_of = tcx.predicates_of(def_id); let substs = tcx.lift(&substs).unwrap_or_else(|| { tcx.intern_substs(&[]) }); - let bounds = item_predicates.instantiate(tcx, substs); + let bounds = predicates_of.instantiate(tcx, substs); let mut first = true; let mut is_sized = false; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 142286bd834d..99e533cbb83f 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -87,7 +87,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap(); let body_id = tcx.hir.body_owned_by(owner_id); let attributes = tcx.get_attrs(owner_def_id); - let tables = tcx.item_tables(owner_def_id); + let tables = tcx.typeck_tables_of(owner_def_id); let mut bccx = &mut BorrowckCtxt { tcx: tcx, @@ -169,7 +169,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( { let owner_id = tcx.hir.body_owner(body_id); let owner_def_id = tcx.hir.local_def_id(owner_id); - let tables = tcx.item_tables(owner_def_id); + let tables = tcx.typeck_tables_of(owner_def_id); let mut bccx = BorrowckCtxt { tcx: tcx, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index e9352f53c92d..cc9892ee8c21 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -376,7 +376,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, debug!("const call({:?})", call_args); let callee_cx = ConstContext { tcx: tcx, - tables: tcx.item_tables(def_id), + tables: tcx.typeck_tables_of(def_id), substs: substs, fn_args: Some(call_args) }; @@ -607,7 +607,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, U32(c as u32), ty), Variant(v) => { - let adt = tcx.lookup_adt_def(tcx.parent_def_id(v).unwrap()); + let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap()); let idx = adt.variant_index_with_id(v); cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty) } @@ -767,7 +767,7 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let cx = ConstContext { tcx, - tables: tcx.item_tables(def_id), + tables: tcx.typeck_tables_of(def_id), substs: substs, fn_args: None }; diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 0dfafeb6fb83..aea40b855354 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -547,7 +547,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { match def { Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); - let adt_def = self.tcx.lookup_adt_def(enum_id); + let adt_def = self.tcx.adt_def(enum_id); if adt_def.variants.len() > 1 { let substs = match ty.sty { TypeVariants::TyAdt(_, substs) => substs, @@ -591,7 +591,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { Some((def_id, _substs)) => { // Enter the inlined constant's tables temporarily. let old_tables = self.tables; - self.tables = tcx.item_tables(def_id); + self.tables = tcx.typeck_tables_of(def_id); let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { tcx.hir.body(tcx.hir.body_owned_by(id)) } else { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1c69f3cff172..c8644820ac0d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -118,7 +118,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { hir::ItemStruct(..) | hir::ItemUnion(..) => { let def_id = cx.tcx.hir.local_def_id(it.id); - self.check_heap_type(cx, it.span, cx.tcx.item_type(def_id)) + self.check_heap_type(cx, it.span, cx.tcx.type_of(def_id)) } _ => () } @@ -130,7 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { for struct_field in struct_def.fields() { let def_id = cx.tcx.hir.local_def_id(struct_field.id); self.check_heap_type(cx, struct_field.span, - cx.tcx.item_type(def_id)); + cx.tcx.type_of(def_id)); } } _ => (), @@ -504,21 +504,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(cx.tcx.hir.local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemUnion(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(cx.tcx.hir.local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(cx.tcx.hir.local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } _ => return, @@ -582,10 +582,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { }; if self.impling_types.is_none() { - let debug_def = cx.tcx.lookup_trait_def(debug); + let debug_def = cx.tcx.trait_def(debug); let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { - if let Some(ty_def) = cx.tcx.item_type(d).ty_to_def_id() { + if let Some(ty_def) = cx.tcx.type_of(d).ty_to_def_id() { if let Some(node_id) = cx.tcx.hir.as_local_node_id(ty_def) { impls.insert(node_id); } @@ -1094,7 +1094,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { } fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { - match cx.tcx.item_type(def_id).sty { + match cx.tcx.type_of(def_id).sty { ty::TyFnDef(.., bfty) if bfty.abi() == RustIntrinsic => (), _ => return false, } @@ -1151,7 +1151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { - let field_ty = ctx.tcx.item_type(ctx.tcx.hir.local_def_id(field.id)); + let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id)); if field_ty.needs_drop(ctx.tcx, param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 3e60d8a5ada0..c2181c9764c6 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -660,7 +660,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) { let def_id = self.cx.tcx.hir.local_def_id(id); - let sig = self.cx.tcx.item_type(def_id).fn_sig(); + let sig = self.cx.tcx.type_of(def_id).fn_sig(); let sig = self.cx.tcx.erase_late_bound_regions(&sig); for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) { @@ -677,7 +677,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) { let def_id = self.cx.tcx.hir.local_def_id(id); - let ty = self.cx.tcx.item_type(def_id); + let ty = self.cx.tcx.type_of(def_id); self.check_type_for_ffi_and_report_errors(span, ty); } } @@ -724,7 +724,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.item_type(cx.tcx.hir.local_def_id(it.id)); + let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id)); let layout = cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); ty.layout(&infcx).unwrap_or_else(|e| { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 9e6a45e7f8b7..f310279ea3c3 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -69,10 +69,10 @@ macro_rules! provide { } provide! { <'tcx> tcx, def_id, cdata - ty => { cdata.get_type(def_id.index, tcx) } - generics => { tcx.alloc_generics(cdata.get_generics(def_id.index)) } - predicates => { cdata.get_predicates(def_id.index, tcx) } - super_predicates => { cdata.get_super_predicates(def_id.index, tcx) } + type_of => { cdata.get_type(def_id.index, tcx) } + generics_of => { tcx.alloc_generics(cdata.get_generics(def_id.index)) } + predicates_of => { cdata.get_predicates(def_id.index, tcx) } + super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) } trait_def => { tcx.alloc_trait_def(cdata.get_trait_def(def_id.index)) } @@ -81,7 +81,7 @@ provide! { <'tcx> tcx, def_id, cdata let _ = cdata; tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) } - variances => { Rc::new(cdata.get_item_variances(def_id.index)) } + variances_of => { Rc::new(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { let mut result = vec![]; cdata.each_child_of_item(def_id.index, |child| result.push(child.def.def_id())); @@ -108,7 +108,7 @@ provide! { <'tcx> tcx, def_id, cdata mir } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } - typeck_tables => { cdata.item_body_tables(def_id.index, tcx) } + typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) } closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a9eae5281b24..1656d489269d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice>> for DecodeContext<' impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::AdtDef> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> { let def_id = DefId::decode(self)?; - Ok(self.tcx().lookup_adt_def(def_id)) + Ok(self.tcx().adt_def(def_id)) } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ce9f0a73fe2b..949949d2e102 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -242,12 +242,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { debug!("EntryBuilder::encode_item_variances({:?})", def_id); let tcx = self.tcx; - self.lazy_seq_from_slice(&tcx.item_variances(def_id)) + self.lazy_seq_from_slice(&tcx.variances_of(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - let ty = tcx.item_type(def_id); + let ty = tcx.type_of(def_id); debug!("EntryBuilder::encode_item_type({:?}) => {:?}", def_id, ty); self.lazy(&ty) } @@ -261,7 +261,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { (enum_did, Untracked(index)): (DefId, Untracked)) -> Entry<'tcx> { let tcx = self.tcx; - let def = tcx.lookup_adt_def(enum_did); + let def = tcx.adt_def(enum_did); let variant = &def.variants[index]; let def_id = variant.did; debug!("EntryBuilder::encode_enum_variant_info({:?})", def_id); @@ -341,7 +341,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { fn encode_fields(&mut self, adt_def_id: DefId) { - let def = self.tcx.lookup_adt_def(adt_def_id); + let def = self.tcx.adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, @@ -365,7 +365,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { usize)>)) -> Entry<'tcx> { let tcx = self.tcx; - let variant = &tcx.lookup_adt_def(adt_def_id).variants[variant_index]; + let variant = &tcx.adt_def(adt_def_id).variants[variant_index]; let field = &variant.fields[field_index]; let def_id = field.did; @@ -397,7 +397,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { debug!("EntryBuilder::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; - let variant = tcx.lookup_adt_def(adt_def_id).struct_variant(); + let variant = tcx.adt_def(adt_def_id).struct_variant(); let data = VariantData { ctor_kind: variant.ctor_kind, @@ -439,13 +439,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_generics(&mut self, def_id: DefId) -> Lazy { debug!("EntryBuilder::encode_generics({:?})", def_id); let tcx = self.tcx; - self.lazy(tcx.item_generics(def_id)) + self.lazy(tcx.generics_of(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { debug!("EntryBuilder::encode_predicates({:?})", def_id); let tcx = self.tcx; - self.lazy(&tcx.item_predicates(def_id)) + self.lazy(&tcx.predicates_of(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { @@ -570,7 +570,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node { (Some(body), true) } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { - let generics = self.tcx.item_generics(def_id); + let generics = self.tcx.generics_of(def_id); let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); let is_const_fn = sig.constness == hir::Constness::Const; @@ -674,7 +674,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { hir::ItemTy(..) => EntryKind::Type, hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)), hir::ItemStruct(ref struct_def, _) => { - let variant = tcx.lookup_adt_def(def_id).struct_variant(); + let variant = tcx.adt_def(def_id).struct_variant(); // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method @@ -694,7 +694,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { }), repr_options) } hir::ItemUnion(..) => { - let variant = tcx.lookup_adt_def(def_id).struct_variant(); + let variant = tcx.adt_def(def_id).struct_variant(); let repr_options = get_repr_options(&tcx, def_id); EntryKind::Union(self.lazy(&VariantData { @@ -716,7 +716,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { hir::ItemImpl(_, polarity, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); let parent = if let Some(trait_ref) = trait_ref { - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + let trait_def = tcx.trait_def(trait_ref.def_id); trait_def.ancestors(def_id).skip(1).next().and_then(|node| { match node { specialization_graph::Node::Impl(parent) => Some(parent), @@ -748,12 +748,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { EntryKind::Impl(self.lazy(&data)) } hir::ItemTrait(..) => { - let trait_def = tcx.lookup_trait_def(def_id); + let trait_def = tcx.trait_def(def_id); let data = TraitData { unsafety: trait_def.unsafety, paren_sugar: trait_def.paren_sugar, has_default_impl: tcx.trait_has_default_impl(def_id), - super_predicates: self.lazy(&tcx.item_super_predicates(def_id)), + super_predicates: self.lazy(&tcx.super_predicates_of(def_id)), }; EntryKind::Trait(self.lazy(&data)) @@ -774,7 +774,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { .map(|foreign_item| tcx.hir.local_def_id(foreign_item.id).index)) } hir::ItemEnum(..) => { - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); self.lazy_seq(def.variants.iter().map(|v| { assert!(v.did.is_local()); v.did.index @@ -782,7 +782,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { } hir::ItemStruct(..) | hir::ItemUnion(..) => { - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); self.lazy_seq(def.struct_variant().fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index @@ -919,7 +919,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemEnum(..) => { self.encode_fields(def_id); - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, EntryBuilder::encode_enum_variant_info, @@ -1539,7 +1539,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions { - let ty = tcx.item_type(did); + let ty = tcx.type_of(did); match ty.sty { ty::TyAdt(ref def, _) => return def.repr, _ => bug!("{} is not an ADT", ty), diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index dd4190a412da..95b20560c62a 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -784,7 +784,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, - ty: tcx.item_type(free_func).subst(tcx, substs), + ty: tcx.type_of(free_func).subst(tcx, substs), literal: Literal::Value { value: ConstVal::Function(free_func, substs), } diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index db9da2a280b9..e73eaafc4b9f 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -140,7 +140,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssociatedKind::Method && item.name == method_name { - let method_ty = self.tcx.item_type(item.def_id); + let method_ty = self.tcx.type_of(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, Literal::Value { diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 9dfe1a34c9ce..77f5c8ff124d 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -139,7 +139,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) // types/lifetimes replaced) let fn_sig = cx.tables().liberated_fn_sigs[&id].clone(); - let ty = tcx.item_type(tcx.hir.local_def_id(id)); + let ty = tcx.type_of(tcx.hir.local_def_id(id)); let mut abi = fn_sig.abi; let implicit_argument = if let ty::TyClosure(..) = ty.sty { // HACK(eddyb) Avoid having RustCall on closures, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 7f7377e5ffe3..9e57472c2365 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -167,7 +167,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, } else { param_env.free_substs }; - let fn_ty = tcx.item_type(def_id).subst(tcx, substs); + let fn_ty = tcx.type_of(def_id).subst(tcx, substs); let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); let span = tcx.def_span(def_id); @@ -290,7 +290,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, call_kind={:?}, untuple_args={:?})", def_id, rcvr_adjustment, call_kind, untuple_args); - let fn_ty = tcx.item_type(def_id).subst(tcx, param_env.free_substs); + let fn_ty = tcx.type_of(def_id).subst(tcx, param_env.free_substs); let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); let span = tcx.def_span(def_id); @@ -332,7 +332,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, CallKind::Direct(def_id) => ( Operand::Constant(Constant { span: span, - ty: tcx.item_type(def_id).subst(tcx, param_env.free_substs), + ty: tcx.type_of(def_id).subst(tcx, param_env.free_substs), literal: Literal::Value { value: ConstVal::Function(def_id, param_env.free_substs), }, @@ -422,7 +422,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, { let tcx = infcx.tcx; let def_id = tcx.hir.local_def_id(ctor_id); - let sig = match tcx.item_type(def_id).sty { + let sig = match tcx.type_of(def_id).sty { ty::TyFnDef(_, _, fty) => tcx.no_late_bound_regions(&fty) .expect("LBR in ADT constructor signature"), _ => bug!("unexpected type for ctor {:?}", def_id) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 526c1488ab48..3ef611dd3caf 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -258,7 +258,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let mut span = None; self.tcx - .lookup_trait_def(drop_trait_id) + .trait_def(drop_trait_id) .for_each_relevant_impl(self.tcx, self.mir.return_ty, |impl_did| { self.tcx.hir .as_local_node_id(impl_did) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index bfb08de56d8b..d2e4c1a96498 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -133,7 +133,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty }, Lvalue::Static(box Static { def_id, ty: sty }) => { let sty = self.sanitize_type(lvalue, sty); - let ty = self.tcx().item_type(def_id); + let ty = self.tcx().type_of(def_id); let ty = self.cx.normalize(&ty); if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) { span_mirbug!( diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index fdb675221337..f275b4cafaf9 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { }; let outer_tables = self.tables; - self.tables = self.tcx.item_tables(self.tcx.hir.local_def_id(item_id)); + self.tables = self.tcx.typeck_tables_of(self.tcx.hir.local_def_id(item_id)); let body = self.tcx.hir.body(body_id); if !self.in_fn { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 92f7e48b6be4..fb1c5738206c 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -88,7 +88,7 @@ struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> { impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { fn item_ty_level(&self, item_def_id: DefId) -> Option { - let ty_def_id = match self.tcx.item_type(item_def_id).sty { + let ty_def_id = match self.tcx.type_of(item_def_id).sty { ty::TyAdt(adt, _) => adt.did, ty::TyDynamic(ref obj, ..) if obj.principal().is_some() => obj.principal().unwrap().def_id(), @@ -236,7 +236,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { if item_level.is_some() { - self.reach(item.id).generics().predicates().item_type(); + self.reach(item.id).generics().predicates().ty(); } } hir::ItemTrait(.., ref trait_item_refs) => { @@ -251,7 +251,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { !trait_item_ref.defaultness.has_value() { // No type to visit. } else { - reach.item_type(); + reach.ty(); } } } @@ -264,7 +264,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { for impl_item_ref in impl_item_refs { let id = impl_item_ref.id.node_id; if trait_ref.is_some() || self.get(id).is_some() { - self.reach(id).generics().predicates().item_type(); + self.reach(id).generics().predicates().ty(); } } } @@ -278,7 +278,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { for variant in &def.variants { if self.get(variant.node.data.id()).is_some() { for field in variant.node.data.fields() { - self.reach(field.id).item_type(); + self.reach(field.id).ty(); } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. @@ -290,7 +290,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { if self.get(foreign_item.id).is_some() { - self.reach(foreign_item.id).generics().predicates().item_type(); + self.reach(foreign_item.id).generics().predicates().ty(); } } } @@ -301,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { self.reach(item.id).generics().predicates(); for field in struct_def.fields() { if self.get(field.id).is_some() { - self.reach(field.id).item_type(); + self.reach(field.id).ty(); } } } @@ -351,7 +351,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { if let hir::TyImplTrait(..) = ty.node { if self.get(ty.id).is_some() { // Reach the (potentially private) type and the API being exposed. - self.reach(ty.id).item_type().predicates(); + self.reach(ty.id).ty().predicates(); } } @@ -361,21 +361,21 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { fn generics(&mut self) -> &mut Self { - for def in &self.ev.tcx.item_generics(self.item_def_id).types { + for def in &self.ev.tcx.generics_of(self.item_def_id).types { if def.has_default { - self.ev.tcx.item_type(def.def_id).visit_with(self); + self.ev.tcx.type_of(def.def_id).visit_with(self); } } self } fn predicates(&mut self) -> &mut Self { - self.ev.tcx.item_predicates(self.item_def_id).visit_with(self); + self.ev.tcx.predicates_of(self.item_def_id).visit_with(self); self } - fn item_type(&mut self) -> &mut Self { - self.ev.tcx.item_type(self.item_def_id).visit_with(self); + fn ty(&mut self) -> &mut Self { + self.ev.tcx.type_of(self.item_def_id).visit_with(self); self } @@ -924,21 +924,21 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { fn generics(&mut self) -> &mut Self { - for def in &self.tcx.item_generics(self.item_def_id).types { + for def in &self.tcx.generics_of(self.item_def_id).types { if def.has_default { - self.tcx.item_type(def.def_id).visit_with(self); + self.tcx.type_of(def.def_id).visit_with(self); } } self } fn predicates(&mut self) -> &mut Self { - self.tcx.item_predicates(self.item_def_id).visit_with(self); + self.tcx.predicates_of(self.item_def_id).visit_with(self); self } - fn item_type(&mut self) -> &mut Self { - self.tcx.item_type(self.item_def_id).visit_with(self); + fn ty(&mut self) -> &mut Self { + self.tcx.type_of(self.item_def_id).visit_with(self); self } @@ -1104,7 +1104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // Subitems of these items have inherited publicity hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { - self.check(item.id, item_visibility).generics().predicates().item_type(); + self.check(item.id, item_visibility).generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = item_visibility; @@ -1121,7 +1121,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> !trait_item_ref.defaultness.has_value() { // No type to visit. } else { - check.item_type(); + check.ty(); } } } @@ -1130,7 +1130,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> for variant in &def.variants { for field in variant.node.data.fields() { - self.check(field.id, item_visibility).item_type(); + self.check(field.id, item_visibility).ty(); } } } @@ -1138,7 +1138,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> hir::ItemForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { let vis = ty::Visibility::from_hir(&foreign_item.vis, item.id, tcx); - self.check(foreign_item.id, vis).generics().predicates().item_type(); + self.check(foreign_item.id, vis).generics().predicates().ty(); } } // Subitems of structs and unions have their own publicity @@ -1148,7 +1148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> for field in struct_def.fields() { let field_visibility = ty::Visibility::from_hir(&field.vis, item.id, tcx); - self.check(field.id, min(item_visibility, field_visibility)).item_type(); + self.check(field.id, min(item_visibility, field_visibility)).ty(); } } // The interface is empty @@ -1157,7 +1157,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // Subitems of inherent impls have their own publicity hir::ItemImpl(.., None, _, ref impl_item_refs) => { let ty_vis = - self.check(item.id, ty::Visibility::Invisible).item_type().min_visibility; + self.check(item.id, ty::Visibility::Invisible).ty().min_visibility; self.check(item.id, ty_vis).generics().predicates(); for impl_item_ref in impl_item_refs { @@ -1165,7 +1165,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, tcx); self.check(impl_item.id, min(impl_item_vis, ty_vis)) - .generics().predicates().item_type(); + .generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = impl_item_vis; @@ -1176,11 +1176,11 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // Subitems of trait impls have inherited publicity hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => { let vis = self.check(item.id, ty::Visibility::Invisible) - .item_type().impl_trait_ref().min_visibility; + .ty().impl_trait_ref().min_visibility; self.check(item.id, vis).generics().predicates(); for impl_item_ref in impl_item_refs { let impl_item = self.tcx.hir.impl_item(impl_item_ref.id); - self.check(impl_item.id, vis).generics().predicates().item_type(); + self.check(impl_item.id, vis).generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = vis; @@ -1200,7 +1200,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // e.g. `impl Iterator` has two predicates, // `X: Iterator` and `::Item == T`, // where `X` is the `impl Iterator` itself, - // stored in `item_predicates`, not in the `Ty` itself. + // stored in `predicates_of`, not in the `Ty` itself. self.check(ty.id, self.inner_visibility).predicates(); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3e8f7e11b6b4..9e3e727d4bdc 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -114,7 +114,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>) { let item_def_id = self.tcx.hir.local_def_id(item_id); - match self.tcx.maps.typeck_tables.borrow().get(&item_def_id) { + match self.tcx.maps.typeck_tables_of.borrow().get(&item_def_id) { Some(tables) => { let old_tables = self.save_ctxt.tables; self.save_ctxt.tables = tables; diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index d822f7bea3a3..e2c399e85cd5 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -341,7 +341,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); filter!(self.span_utils, sub_span, field.span, None); let def_id = self.tcx.hir.local_def_id(field.id); - let typ = self.tcx.item_type(def_id).to_string(); + let typ = self.tcx.type_of(def_id).to_string(); let span = field.span; let text = self.span_utils.snippet(field.span); diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index f21864764ddf..a96128fcf2f5 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -232,7 +232,7 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = tcx.item_type(ty_def_id); + instance_ty = tcx.type_of(ty_def_id); break; } _ => { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ba119bd9ef06..e8cca7bc74f1 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1041,7 +1041,7 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { hir_map::NodeImplItem(&hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.hir.local_def_id(id); - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); let attributes = tcx.get_attrs(def_id); (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 13bb0d371250..93ec7e11606d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -935,14 +935,14 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' continue; } - if !tcx.item_generics(method.def_id).types.is_empty() { + if !tcx.generics_of(method.def_id).types.is_empty() { continue; } let instance = monomorphize::resolve(scx, method.def_id, callee_substs); - let predicates = tcx.item_predicates(instance.def_id()).predicates + let predicates = tcx.predicates_of(instance.def_id()).predicates .subst(tcx, instance.substs); if !traits::normalize_and_test_predicates(tcx, predicates) { continue; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 648ea92c8437..025062f7ddef 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -563,7 +563,7 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = shared.tcx().item_type(def_id); + let ty = shared.tcx().type_of(def_id); shared.tcx().trans_apply_param_substs(substs, &ty) } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 1b7cf26853bc..982ea5ffeb70 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -237,7 +237,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. - let generics = cx.tcx().item_generics(fn_def_id); + let generics = cx.tcx().generics_of(fn_def_id); let substs = instance.substs.truncate_to(cx.tcx(), generics); let template_parameters = get_template_parameters(cx, &generics, @@ -382,7 +382,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn get_type_parameter_names(cx: &CrateContext, generics: &ty::Generics) -> Vec { let mut names = generics.parent.map_or(vec![], |def_id| { - get_type_parameter_names(cx, cx.tcx().item_generics(def_id)) + get_type_parameter_names(cx, cx.tcx().generics_of(def_id)) }); names.extend(generics.types.iter().map(|param| param.name)); names diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index de35d1b7dd4c..d8e139dc505b 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -444,7 +444,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { }, ty::TyClosure(def_id, ref closure_substs) => { self.push_def_path(def_id, output); - let generics = self.tcx.item_generics(self.tcx.closure_base_def_id(def_id)); + let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); let substs = closure_substs.substs.truncate_to(self.tcx, generics); self.push_type_params(substs, iter::empty(), output); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5137ae6ff422..c18658998944 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -217,7 +217,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - let decl_generics = tcx.item_generics(def_id); + let decl_generics = tcx.generics_of(def_id); let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); if expected_num_region_params != supplied_num_region_params { @@ -238,7 +238,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let default_needs_object_self = |p: &ty::TypeParameterDef| { if is_object && p.has_default { - if ty::queries::ty::get(tcx, span, p.def_id).has_self_ty() { + if ty::queries::type_of::get(tcx, span, p.def_id).has_self_ty() { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -307,7 +307,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // This is a default type parameter. self.normalize_ty( span, - ty::queries::ty::get(tcx, span, def.def_id) + ty::queries::type_of::get(tcx, span, def.def_id) .subst_spanned(tcx, substs, Some(span)) ) } @@ -458,7 +458,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); - let trait_def = self.tcx().lookup_trait_def(trait_def_id); + let trait_def = self.tcx().trait_def(trait_def_id); match trait_segment.parameters { hir::AngleBracketedParameters(_) => { @@ -600,7 +600,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let substs = self.ast_path_substs_for_ty(span, did, item_segment); self.normalize_ty( span, - ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs) + ty::queries::type_of::get(self.tcx(), span, did).subst(self.tcx(), substs) ) } @@ -1008,7 +1008,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let node_id = tcx.hir.as_local_node_id(did).unwrap(); let item_id = tcx.hir.get_parent_node(node_id); let item_def_id = tcx.hir.local_def_id(item_id); - let generics = tcx.item_generics(item_def_id); + let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id).index]; tcx.mk_param(index, tcx.hir.name(node_id)) } @@ -1018,7 +1018,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assert_eq!(opt_self_ty, None); self.prohibit_type_params(&path.segments); - let ty = ty::queries::ty::get(tcx, span, def_id); + let ty = ty::queries::type_of::get(tcx, span, def_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index ae70049cc5bd..a38840552c23 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -180,10 +180,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); - let impl_m_generics = tcx.item_generics(impl_m.def_id); - let trait_m_generics = tcx.item_generics(trait_m.def_id); - let impl_m_predicates = tcx.item_predicates(impl_m.def_id); - let trait_m_predicates = tcx.item_predicates(trait_m.def_id); + let impl_m_generics = tcx.generics_of(impl_m.def_id); + let trait_m_generics = tcx.generics_of(trait_m.def_id); + let impl_m_predicates = tcx.predicates_of(impl_m.def_id); + let trait_m_predicates = tcx.predicates_of(trait_m.def_id); // Check region bounds. check_region_bounds_on_impl_method(tcx, @@ -199,7 +199,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_predicates = tcx.item_predicates(impl_m_predicates.parent.unwrap()); + let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); @@ -261,7 +261,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let tcx = infcx.tcx; let m_sig = |method: &ty::AssociatedItem| { - match tcx.item_type(method.def_id).sty { + match tcx.type_of(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -509,7 +509,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.mk_self_type() }; - let method_ty = tcx.item_type(method.def_id); + let method_ty = tcx.type_of(method.def_id); let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { ExplicitSelf::ByValue => "self".to_string(), @@ -567,8 +567,8 @@ fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_m: &ty::AssociatedItem, trait_item_span: Option) -> Result<(), ErrorReported> { - let impl_m_generics = tcx.item_generics(impl_m.def_id); - let trait_m_generics = tcx.item_generics(trait_m.def_id); + let impl_m_generics = tcx.generics_of(impl_m.def_id); + let trait_m_generics = tcx.generics_of(trait_m.def_id); let num_impl_m_type_params = impl_m_generics.types.len(); let num_trait_m_type_params = trait_m_generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { @@ -637,7 +637,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_span: Option) -> Result<(), ErrorReported> { let m_fty = |method: &ty::AssociatedItem| { - match tcx.item_type(method.def_id).sty { + match tcx.type_of(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -750,8 +750,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. - let impl_ty = tcx.item_type(impl_c.def_id).subst(tcx, impl_to_skol_substs); - let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); + let impl_ty = tcx.type_of(impl_c.def_id).subst(tcx, impl_to_skol_substs); + let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_skol_substs); let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); // There is no "body" here, so just pass dummy id. diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 4cc3f2dacdfe..d92dafe69045 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -135,7 +135,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn has_no_input_arg(&self, method: &AssociatedItem) -> bool { match method.def() { Def::Method(def_id) => { - match self.tcx.item_type(def_id).sty { + match self.tcx.type_of(def_id).sty { ty::TypeVariants::TyFnDef(_, _, sig) => { sig.inputs().skip_binder().len() == 1 } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index c125d7c02556..8d26f0074297 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -42,8 +42,8 @@ use syntax_pos::Span; pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, drop_impl_did: DefId) -> Result<(), ErrorReported> { - let dtor_self_type = tcx.item_type(drop_impl_did); - let dtor_predicates = tcx.item_predicates(drop_impl_did); + let dtor_self_type = tcx.type_of(drop_impl_did); + let dtor_predicates = tcx.predicates_of(drop_impl_did); match dtor_self_type.sty { ty::TyAdt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(tcx, @@ -85,7 +85,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); - let named_type = tcx.item_type(self_type_did); + let named_type = tcx.type_of(self_type_did); let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs); let drop_impl_span = tcx.def_span(drop_impl_did); @@ -175,7 +175,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // We can assume the predicates attached to struct/enum definition // hold. - let generic_assumptions = tcx.item_predicates(self_type_did); + let generic_assumptions = tcx.predicates_of(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); let assumptions_in_impl_context = assumptions_in_impl_context.predicates; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index bf7649242fa7..2a97bc1d98fe 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -46,7 +46,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir::Unsafety::Unsafe, abi ))); - let i_n_tps = tcx.item_generics(def_id).types.len(); + let i_n_tps = tcx.generics_of(def_id).types.len(); if i_n_tps != n_tps { let span = match it.node { hir::ForeignItemFn(_, _, ref generics) => generics.span, @@ -64,7 +64,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType), - tcx.item_type(def_id), + tcx.type_of(def_id), fty); } } @@ -324,7 +324,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let def_id = tcx.hir.local_def_id(it.id); - let i_n_tps = tcx.item_generics(def_id).types.len(); + let i_n_tps = tcx.generics_of(def_id).types.len(); let name = it.name.as_str(); let (n_tps, inputs, output) = match &*name { @@ -367,7 +367,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut structural_to_nomimal = FxHashMap(); - let sig = tcx.item_type(def_id).fn_sig(); + let sig = tcx.type_of(def_id).fn_sig(); let sig = tcx.no_late_bound_regions(&sig).unwrap(); if intr.inputs.len() != sig.inputs().len() { span_err!(tcx.sess, it.span, E0444, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 26ba965fe5cc..f0a74ea4be92 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let method_generics = self.tcx.item_generics(pick.item.def_id); + let method_generics = self.tcx.generics_of(pick.item.def_id); let num_method_types = method_generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { @@ -358,14 +358,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. let def_id = pick.item.def_id; - let method_predicates = self.tcx.item_predicates(def_id) + let method_predicates = self.tcx.predicates_of(def_id) .instantiate(self.tcx, all_substs); let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); debug!("method_predicates after subst = {:?}", method_predicates); - let sig = self.tcx.item_type(def_id).fn_sig(); + let sig = self.tcx.type_of(def_id).fn_sig(); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 7dd2699a6eaf..951683e7ffc9 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -232,7 +232,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; let method_item = self.associated_item(trait_def_id, m_name).unwrap(); let def_id = method_item.def_id; - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); assert_eq!(generics.types.len(), 0); assert_eq!(generics.regions.len(), 0); @@ -245,7 +245,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let original_method_ty = tcx.item_type(def_id); + let original_method_ty = tcx.type_of(def_id); let fn_sig = original_method_ty.fn_sig(); let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, @@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let bounds = self.tcx.item_predicates(def_id).instantiate(self.tcx, substs); + let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) { InferOk { value, obligations: o } => { obligations.extend(o); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 80f9372eb54c..6dd4fb7301bc 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -661,7 +661,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { expected: ty::Ty<'tcx>) -> bool { match method.def() { Def::Method(def_id) => { - let fty = self.tcx.item_type(def_id).fn_sig(); + let fty = self.tcx.type_of(def_id).fn_sig(); self.probe(|_| { let substs = self.fresh_substs_for_item(self.span, method.def_id); let output = fty.output().subst(self.tcx, substs); @@ -706,7 +706,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { import_id: Option, trait_def_id: DefId, item: ty::AssociatedItem) { - let trait_def = self.tcx.lookup_trait_def(trait_def_id); + let trait_def = self.tcx.trait_def(trait_def_id); // FIXME(arielb1): can we use for_each_relevant_impl here? trait_def.for_each_impl(self.tcx, |impl_def_id| { @@ -760,7 +760,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } }; - let impl_type = self.tcx.item_type(impl_def_id); + let impl_type = self.tcx.type_of(impl_def_id); let impl_simplified_type = match ty::fast_reject::simplify_type(self.tcx, impl_type, false) { Some(simplified_type) => simplified_type, @@ -867,7 +867,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { def_id, substs); - let trait_predicates = self.tcx.item_predicates(def_id); + let trait_predicates = self.tcx.predicates_of(def_id); let bounds = trait_predicates.instantiate(self.tcx, substs); let predicates = bounds.predicates; debug!("assemble_projection_candidates: predicates={:?}", @@ -1185,7 +1185,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = self.tcx.item_predicates(impl_def_id); + let impl_bounds = self.tcx.predicates_of(impl_def_id); let impl_bounds = impl_bounds.instantiate(self.tcx, substs); let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = traits::normalize(selcx, cause.clone(), &impl_bounds); @@ -1294,7 +1294,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { - let self_ty = self.tcx.item_type(method).fn_sig().input(0); + let self_ty = self.tcx.type_of(method).fn_sig().input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, self_ty, @@ -1307,7 +1307,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - let generics = self.tcx.item_generics(method); + let generics = self.tcx.generics_of(method); assert_eq!(substs.types().count(), generics.parent_types as usize); assert_eq!(substs.regions().count(), generics.parent_regions as usize); @@ -1341,7 +1341,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Get the type of an impl and generate substitutions with placeholders. fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) { - let impl_ty = self.tcx.item_type(impl_def_id); + let impl_ty = self.tcx.type_of(impl_def_id); let substs = Substs::for_item(self.tcx, impl_def_id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 098e8c53a52c..a27397fa444d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -628,7 +628,7 @@ fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum debug_assert!(crate_num == LOCAL_CRATE); tcx.sess.track_errors(|| { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - tcx.item_tables(body_owner_def_id); + tcx.typeck_tables_of(body_owner_def_id); }); }) } @@ -636,7 +636,7 @@ fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum pub fn provide(providers: &mut Providers) { *providers = Providers { typeck_item_bodies, - typeck_tables, + typeck_tables_of, closure_type, closure_kind, adt_destructor, @@ -648,14 +648,14 @@ fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig<'tcx> { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.item_tables(def_id).closure_tys[&node_id] + tcx.typeck_tables_of(def_id).closure_tys[&node_id] } fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureKind { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.item_tables(def_id).closure_kinds[&node_id] + tcx.typeck_tables_of(def_id).closure_kinds[&node_id] } fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -664,14 +664,14 @@ fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) } -fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::TypeckTables<'tcx> { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". let outer_def_id = tcx.closure_base_def_id(def_id); if outer_def_id != def_id { - return tcx.item_tables(outer_def_id); + return tcx.typeck_tables_of(outer_def_id); } let id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -736,7 +736,7 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Inherited::build(tcx, id).enter(|inh| { let fcx = if let Some(decl) = fn_decl { - let fn_sig = tcx.item_type(def_id).fn_sig(); + let fn_sig = tcx.type_of(def_id).fn_sig(); check_abi(tcx, span, fn_sig.abi()); @@ -752,7 +752,7 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_fn(&inh, fn_sig, decl, id, body) } else { let fcx = FnCtxt::new(&inh, body.value.id); - let expected_type = tcx.item_type(def_id); + let expected_type = tcx.type_of(def_id); let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); @@ -946,7 +946,7 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: ast::NodeId, span: Span) { let def_id = tcx.hir.local_def_id(id); - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); @@ -956,7 +956,7 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // if struct is packed and not aligned, check fields for alignment. // Checks for combining packed and align attrs on single struct are done elsewhere. - if tcx.lookup_adt_def(def_id).repr.packed() && tcx.lookup_adt_def(def_id).repr.align == 0 { + if tcx.adt_def(def_id).repr.packed() && tcx.adt_def(def_id).repr.align == 0 { check_packed(tcx, span, def_id); } } @@ -965,7 +965,7 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: ast::NodeId, span: Span) { let def_id = tcx.hir.local_def_id(id); - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); } @@ -979,7 +979,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item // Consts can play a role in type-checking, so they are included here. hir::ItemStatic(..) | hir::ItemConst(..) => { - tcx.item_tables(tcx.hir.local_def_id(it.id)); + tcx.typeck_tables_of(tcx.hir.local_def_id(it.id)); } hir::ItemEnum(ref enum_definition, _) => { check_enum(tcx, @@ -1013,7 +1013,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item } hir::ItemTy(_, ref generics) => { let def_id = tcx.hir.local_def_id(it.id); - let pty_ty = tcx.item_type(def_id); + let pty_ty = tcx.type_of(def_id); check_bounds_are_used(tcx, generics, pty_ty); } hir::ItemForeignMod(ref m) => { @@ -1029,7 +1029,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item } } else { for item in &m.items { - let generics = tcx.item_generics(tcx.hir.local_def_id(item.id)); + let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); if !generics.types.is_empty() { let mut err = struct_span_err!(tcx.sess, item.span, E0044, "foreign items may not have type parameters"); @@ -1052,7 +1052,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, item: &hir::Item) { - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); if let Some(ref attr) = item.attrs.iter().find(|a| { a.check_name("rustc_on_unimplemented") }) { @@ -1159,7 +1159,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if impl_trait_ref.references_error() { return; } // Locate trait definition and items - let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); + let trait_def = tcx.trait_def(impl_trait_ref.def_id); let mut overridden_associated_type = None; let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir.impl_item(iiref.id)); @@ -1280,11 +1280,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let signature = |item: &ty::AssociatedItem| { match item.kind { ty::AssociatedKind::Method => { - format!("{}", tcx.item_type(item.def_id).fn_sig().0) + format!("{}", tcx.type_of(item.def_id).fn_sig().0) } ty::AssociatedKind::Type => format!("type {};", item.name.to_string()), ty::AssociatedKind::Const => { - format!("const {}: {:?};", item.name.to_string(), tcx.item_type(item.def_id)) + format!("const {}: {:?};", item.name.to_string(), tcx.type_of(item.def_id)) } } }; @@ -1330,7 +1330,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, item_def_id: DefId) -> bool { - let rty = tcx.item_type(item_def_id); + let rty = tcx.type_of(item_def_id); // Check that it is possible to represent this type. This call identifies // (1) types that contain themselves and (2) types that contain a different @@ -1348,7 +1348,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { - let t = tcx.item_type(def_id); + let t = tcx.type_of(def_id); match t.sty { ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; @@ -1387,14 +1387,14 @@ fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) fn check_packed_inner<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, stack: &mut Vec) -> bool { - let t = tcx.item_type(def_id); + let t = tcx.type_of(def_id); if stack.contains(&def_id) { debug!("check_packed_inner: {:?} is recursive", t); return false; } match t.sty { ty::TyAdt(def, substs) if def.is_struct() => { - if tcx.lookup_adt_def(def.did).repr.align > 0 { + if tcx.adt_def(def.did).repr.align > 0 { return true; } // push struct def_id before checking fields @@ -1424,7 +1424,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, vs: &'tcx [hir::Variant], id: ast::NodeId) { let def_id = tcx.hir.local_def_id(id); - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() && tcx.has_attr(def_id, "repr") { @@ -1445,7 +1445,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for v in vs { if let Some(e) = v.node.disr_expr { - tcx.item_tables(tcx.hir.local_def_id(e.node_id)); + tcx.typeck_tables_of(tcx.hir.local_def_id(e.node_id)); } } @@ -1493,7 +1493,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let item_id = tcx.hir.ty_param_owner(node_id); let item_def_id = tcx.hir.local_def_id(item_id); - let generics = tcx.item_generics(item_def_id); + let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&def_id.index]; ty::GenericPredicates { parent: None, @@ -1792,7 +1792,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// generic type scheme. fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>) -> ty::InstantiatedPredicates<'tcx> { - let bounds = self.tcx.item_predicates(def_id); + let bounds = self.tcx.predicates_of(def_id); let result = bounds.instantiate(self.tcx, substs); let result = self.normalize_associated_types_in(span, &result); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", @@ -1817,8 +1817,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span)); self.anon_types.borrow_mut().insert(id, ty_var); - let item_predicates = self.tcx.item_predicates(def_id); - let bounds = item_predicates.instantiate(self.tcx, substs); + let predicates_of = self.tcx.predicates_of(def_id); + let bounds = predicates_of.instantiate(self.tcx, substs); for predicate in bounds.predicates { // Change the predicate to refer to the type variable, @@ -2614,7 +2614,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, // (potential) receiver for this impl did: DefId) -> TypeAndSubsts<'tcx> { - let ity = self.tcx.item_type(did); + let ity = self.tcx.type_of(did); debug!("impl_self_ty: ity={:?}", ity); let substs = self.fresh_substs_for_item(span, did); @@ -4208,11 +4208,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::VariantCtor(def_id, ..) => { // Everything but the final segment should have no // parameters at all. - let mut generics = self.tcx.item_generics(def_id); + let mut generics = self.tcx.generics_of(def_id); if let Some(def_id) = generics.parent { // Variant and struct constructors use the // generics of their parent type definition. - generics = self.tcx.item_generics(def_id); + generics = self.tcx.generics_of(def_id); } type_segment = Some((segments.last().unwrap(), generics)); } @@ -4222,7 +4222,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::Const(def_id) | Def::Static(def_id, _) => { fn_segment = Some((segments.last().unwrap(), - self.tcx.item_generics(def_id))); + self.tcx.generics_of(def_id))); } // Case 3. Reference to a method or associated const. @@ -4236,9 +4236,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::ImplContainer(_) => {} } - let generics = self.tcx.item_generics(def_id); + let generics = self.tcx.generics_of(def_id); if segments.len() >= 2 { - let parent_generics = self.tcx.item_generics(generics.parent.unwrap()); + let parent_generics = self.tcx.generics_of(generics.parent.unwrap()); type_segment = Some((&segments[segments.len() - 2], parent_generics)); } else { // `::assoc` will end up here, and so can `T::assoc`. @@ -4351,7 +4351,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.to_ty(ast_ty) } else if !infer_types && def.has_default { // No type parameter provided, but a default exists. - let default = self.tcx.item_type(def.def_id); + let default = self.tcx.type_of(def.def_id); self.normalize_ty( span, default.subst_spanned(self.tcx, substs, Some(span)) @@ -4367,7 +4367,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. - let ty = self.tcx.item_type(def.def_id()); + let ty = self.tcx.type_of(def.def_id()); assert!(!substs.has_escaping_regions()); assert!(!ty.has_escaping_regions()); @@ -4387,7 +4387,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. - let ty = self.tcx.item_type(impl_def_id); + let ty = self.tcx.type_of(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); match self.sub_types(false, &self.misc(span), self_ty, impl_ty) { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index dcef22da8796..3508ddbe5f48 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1725,7 +1725,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // ``` // // we can thus deduce that `>::SomeType : 'a`. - let trait_predicates = self.tcx.item_predicates(projection_ty.trait_ref.def_id); + let trait_predicates = self.tcx.predicates_of(projection_ty.trait_ref.def_id); assert_eq!(trait_predicates.parent, None); let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(self.tcx, predicates) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 85c87adf9be6..5bb45cbb1ae8 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -168,18 +168,18 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), - fcx.tcx.item_type(def_id)) + fcx.tcx.type_of(def_id)) }; match item.kind { ty::AssociatedKind::Const => { - let ty = fcx.tcx.item_type(item.def_id); + let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } ty::AssociatedKind::Method => { reject_shadowing_type_parameters(fcx.tcx, item.def_id); - let method_ty = fcx.tcx.item_type(item.def_id); + let method_ty = fcx.tcx.type_of(item.def_id); let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); let sig = method_ty.fn_sig(); @@ -191,7 +191,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } ty::AssociatedKind::Type => { if item.defaultness.has_value() { - let ty = fcx.tcx.item_type(item.def_id); + let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } @@ -262,7 +262,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // // 3) that the trait definition does not have any type parameters - let predicates = self.tcx.item_predicates(trait_def_id); + let predicates = self.tcx.predicates_of(trait_def_id); // We must exclude the Self : Trait predicate contained by all // traits. @@ -277,7 +277,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } }); - let has_ty_params = self.tcx.item_generics(trait_def_id).types.len() > 1; + let has_ty_params = self.tcx.generics_of(trait_def_id).types.len() > 1; // We use an if-else here, since the generics will also trigger // an extraneous error message when we find predicates like @@ -334,7 +334,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; let def_id = fcx.tcx.hir.local_def_id(item.id); - let ty = fcx.tcx.item_type(def_id); + let ty = fcx.tcx.type_of(def_id); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty); let sig = item_ty.fn_sig(); @@ -354,7 +354,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { debug!("check_item_type: {:?}", item); self.for_item(item).with_fcx(|fcx, this| { - let ty = fcx.tcx.item_type(fcx.tcx.hir.local_def_id(item.id)); + let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, &fcx.parameter_environment .free_substs, @@ -393,7 +393,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } } None => { - let self_ty = fcx.tcx.item_type(item_def_id); + let self_ty = fcx.tcx.type_of(item_def_id); let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); } @@ -468,7 +468,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let span = method_sig.decl.inputs[0].span; let free_substs = &fcx.parameter_environment.free_substs; - let method_ty = fcx.tcx.item_type(method.def_id); + let method_ty = fcx.tcx.type_of(method.def_id); let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); @@ -502,14 +502,14 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { ast_generics: &hir::Generics) { let item_def_id = self.tcx.hir.local_def_id(item.id); - let ty = self.tcx.item_type(item_def_id); + let ty = self.tcx.type_of(item_def_id); if self.tcx.has_error_field(ty) { return; } - let ty_predicates = self.tcx.item_predicates(item_def_id); + let ty_predicates = self.tcx.predicates_of(item_def_id); assert_eq!(ty_predicates.parent, None); - let variances = self.tcx.item_variances(item_def_id); + let variances = self.tcx.variances_of(item_def_id); let mut constrained_parameters: FxHashSet<_> = variances.iter().enumerate() @@ -561,8 +561,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) { - let generics = tcx.item_generics(def_id); - let parent = tcx.item_generics(generics.parent.unwrap()); + let generics = tcx.generics_of(def_id); + let parent = tcx.generics_of(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.types .iter() .map(|tp| (tp.name, tp.def_id)) @@ -631,7 +631,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fields = struct_def.fields().iter() .map(|field| { - let field_ty = self.tcx.item_type(self.tcx.hir.local_def_id(field.id)); + let field_ty = self.tcx.type_of(self.tcx.hir.local_def_id(field.id)); let field_ty = self.instantiate_type_scheme(field.span, &self.parameter_environment .free_substs, @@ -660,7 +660,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => { // Inherent impl: take implied bounds from the self type. - let self_ty = self.tcx.item_type(impl_def_id); + let self_ty = self.tcx.type_of(impl_def_id); let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); vec![self_ty] } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index c9479c5cebc3..a985ac61cb3a 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -67,7 +67,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let item_def_id = tcx.hir.local_def_id(item_id); // this will have been written by the main typeck pass - if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) { + if let Some(tables) = tcx.maps.typeck_tables_of.borrow().get(&item_def_id) { let imports = &tables.used_trait_imports; debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); used_trait_imports.extend(imports); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 47b41a75cf53..937769537683 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -57,7 +57,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _drop_did: DefId, impl_did: DefId) { - match tcx.item_type(impl_did).sty { + match tcx.type_of(impl_did).sty { ty::TyAdt(..) => {} _ => { // Destructors only work on nominal types. @@ -101,7 +101,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; }; - let self_type = tcx.item_type(impl_did); + let self_type = tcx.type_of(impl_did); debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type); @@ -192,7 +192,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did) }); - let source = tcx.item_type(impl_did); + let source = tcx.type_of(impl_did); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.substs.type_at(1); @@ -259,7 +259,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .filter_map(|(i, f)| { let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); - if tcx.item_type(f.did).is_phantom_data() { + if tcx.type_of(f.did).is_phantom_data() { // Ignore PhantomData fields return None; } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index dc4bd7733fc2..58603900e135 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { } let def_id = self.tcx.hir.local_def_id(item.id); - let self_ty = self.tcx.item_type(def_id); + let self_ty = self.tcx.type_of(def_id); match self_ty.sty { ty::TyAdt(def, _) => { self.check_def_id(item, def.did); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index b385ddc49c1e..abfee989d65f 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -47,7 +47,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { } enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id); - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + let trait_def = tcx.trait_def(trait_ref.def_id); trait_def.record_local_impl(tcx, impl_def_id, trait_ref); } } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 74edc7bff495..383a9e0e6954 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -41,7 +41,7 @@ pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { let _task = tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); - let def = tcx.lookup_trait_def(trait_def_id); + let def = tcx.trait_def(trait_def_id); // attempt to insert into the specialization graph let insert_result = def.add_impl_for_specialization(tcx, impl_def_id); diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 22247d2531ae..4463cff9c503 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -34,7 +34,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { None => {} Some(trait_ref) => { - let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); + let trait_def = self.tcx.trait_def(trait_ref.def_id); let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr()); match (trait_def.unsafety, unsafe_attr, unsafety, polarity) { (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 660ce837043c..83727e9da032 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -31,7 +31,7 @@ then types, or something like that) because the user can introduce arbitrary interdependencies. So instead we generally convert things lazilly and on demand, and include logic that checks for cycles. Demand is driven by calls to `AstConv::get_item_type_scheme` or -`AstConv::lookup_trait_def`. +`AstConv::trait_def`. Currently, we "convert" types and traits in two phases (note that conversion only affects the types of items / enum variants / methods; @@ -91,10 +91,10 @@ pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) { *providers = Providers { - ty, - generics, - predicates, - super_predicates, + type_of, + generics_of, + predicates_of, + super_predicates_of, type_param_predicates, trait_def, adt_def, @@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { for param in &generics.ty_params { if param.default.is_some() { let def_id = self.tcx.hir.local_def_id(param.id); - self.tcx.item_type(def_id); + self.tcx.type_of(def_id); } } intravisit::walk_generics(self, generics); @@ -150,8 +150,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if let hir::ExprClosure(..) = expr.node { let def_id = self.tcx.hir.local_def_id(expr.id); - self.tcx.item_generics(def_id); - self.tcx.item_type(def_id); + self.tcx.generics_of(def_id); + self.tcx.type_of(def_id); } intravisit::walk_expr(self, expr); } @@ -159,8 +159,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty) { if let hir::TyImplTrait(..) = ty.node { let def_id = self.tcx.hir.local_def_id(ty.id); - self.tcx.item_generics(def_id); - self.tcx.item_predicates(def_id); + self.tcx.generics_of(def_id); + self.tcx.predicates_of(def_id); } intravisit::walk_ty(self, ty); } @@ -271,7 +271,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_id = tcx.hir.as_local_node_id(def_id).unwrap(); let param_owner = tcx.hir.ty_param_owner(param_id); let param_owner_def_id = tcx.hir.local_def_id(param_owner); - let generics = tcx.item_generics(param_owner_def_id); + let generics = tcx.generics_of(param_owner_def_id); let index = generics.type_param_to_index[&def_id.index]; let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id)); @@ -279,7 +279,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let parent = if item_def_id == param_owner_def_id { None } else { - tcx.item_generics(item_def_id).parent + tcx.generics_of(item_def_id).parent }; let mut result = parent.map_or(ty::GenericPredicates { @@ -452,43 +452,43 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { hir::ItemForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { let def_id = tcx.hir.local_def_id(item.id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } } hir::ItemEnum(ref enum_definition, _) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); convert_enum_variant_types(tcx, def_id, &enum_definition.variants); }, hir::ItemDefaultImpl(..) => { tcx.impl_trait_ref(def_id); } hir::ItemImpl(..) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); tcx.impl_trait_ref(def_id); - tcx.item_predicates(def_id); + tcx.predicates_of(def_id); }, hir::ItemTrait(..) => { - tcx.item_generics(def_id); - tcx.lookup_trait_def(def_id); - ty::queries::super_predicates::get(tcx, it.span, def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.trait_def(def_id); + ty::queries::super_predicates_of::get(tcx, it.span, def_id); + tcx.predicates_of(def_id); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); for f in struct_def.fields() { let def_id = tcx.hir.local_def_id(f.id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } if !struct_def.is_struct() { @@ -497,14 +497,14 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { }, hir::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(tcx, it.span, generics, "type"); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } } } @@ -512,40 +512,40 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast::NodeId) { let trait_item = tcx.hir.expect_trait_item(trait_item_id); let def_id = tcx.hir.local_def_id(trait_item.id); - tcx.item_generics(def_id); + tcx.generics_of(def_id); match trait_item.node { hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(_, Some(_)) | hir::TraitItemKind::Method(..) => { - tcx.item_type(def_id); + tcx.type_of(def_id); } hir::TraitItemKind::Type(_, None) => {} }; - tcx.item_predicates(def_id); + tcx.predicates_of(def_id); } fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(impl_item_id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ctor_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(ctor_id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, variants: &[hir::Variant]) { - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); let mut prev_discr = None::; @@ -583,9 +583,9 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for f in variant.node.data.fields() { let def_id = tcx.hir.local_def_id(f.id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } // Convert the ctor, if any. This also registers the variant as @@ -686,9 +686,9 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Ensures that the super-predicates of the trait with def-id /// trait_def_id are converted and stored. This also ensures that /// the transitive super-predicates are converted; -fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def_id: DefId) - -> ty::GenericPredicates<'tcx> { +fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + trait_def_id: DefId) + -> ty::GenericPredicates<'tcx> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap(); @@ -725,7 +725,7 @@ fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) { - ty::queries::super_predicates::get(tcx, item.span, bound.def_id()); + ty::queries::super_predicates_of::get(tcx, item.span, bound.def_id()); } ty::GenericPredicates { @@ -767,9 +767,9 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.alloc_trait_def(def) } -fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> &'tcx ty::Generics { +fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx ty::Generics { use rustc::hir::map::*; use rustc::hir::*; @@ -873,7 +873,7 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut parent_has_self = false; let mut own_start = has_self as u32; let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| { - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); assert_eq!(has_self, false); parent_has_self = generics.has_self; own_start = generics.count() as u32; @@ -958,9 +958,9 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Ty<'tcx> { +fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Ty<'tcx> { use rustc::hir::map::*; use rustc::hir::*; @@ -1017,7 +1017,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemEnum(..) | ItemStruct(..) | ItemUnion(..) => { - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } @@ -1049,12 +1049,12 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeStructCtor(&ref def) | NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => { - let ty = tcx.item_type(tcx.hir.get_parent_did(node_id)); + let ty = tcx.type_of(tcx.hir.get_parent_did(node_id)); match *def { VariantData::Unit(..) | VariantData::Struct(..) => ty, VariantData::Tuple(ref fields, _) => { let inputs = fields.iter().map(|f| { - tcx.item_type(tcx.hir.local_def_id(f.id)) + tcx.type_of(tcx.hir.local_def_id(f.id)) }); let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig( @@ -1089,7 +1089,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeVariant(&Spanned { node: Variant_ { disr_expr: Some(e), .. }, .. }) if e.node_id == node_id => { - tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id)) + tcx.adt_def(tcx.hir.get_parent_did(node_id)) .repr.discr_type().to_ty(tcx) } @@ -1104,7 +1104,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => { let owner = tcx.hir.get_parent_did(node_id); - tcx.item_tables(owner).node_id_to_type(node_id) + tcx.typeck_tables_of(owner).node_id_to_type(node_id) } x => { @@ -1127,7 +1127,7 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } hir::ItemImpl(.., ref opt_trait_ref, _, _) => { opt_trait_ref.as_ref().map(|ast_trait_ref| { - let selfty = tcx.item_type(def_id); + let selfty = tcx.type_of(def_id); AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty) }) } @@ -1141,7 +1141,7 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); match tcx.hir.expect_item(node_id).node { hir::ItemImpl(_, polarity, ..) => polarity, - ref item => bug!("trait_impl_polarity: {:?} not an impl", item) + ref item => bug!("impl_polarity: {:?} not an impl", item) } } @@ -1205,9 +1205,9 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>( .filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id)) } -fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> ty::GenericPredicates<'tcx> { +fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> ty::GenericPredicates<'tcx> { use rustc::hir::map::*; use rustc::hir::*; @@ -1280,7 +1280,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => &no_generics }; - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); let parent_count = generics.parent_count() as u32; let has_own_self = generics.has_self && parent_count == 0; @@ -1291,7 +1291,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // on a trait we need to add in the supertrait bounds and bounds found on // associated types. if let Some((trait_ref, _)) = is_trait { - predicates = tcx.item_super_predicates(def_id).predicates; + predicates = tcx.super_predicates_of(def_id).predicates; // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. @@ -1410,7 +1410,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // in trait checking. See `setup_constraining_predicates` // for details. if let NodeItem(&Item { node: ItemImpl(..), .. }) = node { - let self_ty = tcx.item_type(def_id); + let self_ty = tcx.type_of(def_id); let trait_ref = tcx.impl_trait_ref(def_id); ctp::setup_constraining_predicates(&mut predicates, trait_ref, diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 5751dc5ab8a0..1c44572fbb4a 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -95,9 +95,9 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_refs: &[hir::ImplItemRef]) { // Every lifetime used in an associated type must be constrained. - let impl_self_ty = tcx.item_type(impl_def_id); - let impl_generics = tcx.item_generics(impl_def_id); - let impl_predicates = tcx.item_predicates(impl_def_id); + let impl_self_ty = tcx.type_of(impl_def_id); + let impl_generics = tcx.generics_of(impl_def_id); + let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref); @@ -120,7 +120,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item.kind == ty::AssociatedKind::Type && item.defaultness.has_value() }) .flat_map(|def_id| { - ctp::parameters_for(&tcx.item_type(def_id), true) + ctp::parameters_for(&tcx.type_of(def_id), true) }).collect(); for (ty_lifetime, lifetime) in impl_generics.regions.iter() .zip(&impl_hir_generics.lifetimes) diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0754b52cf280..94b4bfade949 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -179,7 +179,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: ast::NodeId, main_span: Span) { let main_def_id = tcx.hir.local_def_id(main_id); - let main_t = tcx.item_type(main_def_id); + let main_t = tcx.type_of(main_def_id); match main_t.sty { ty::TyFnDef(..) => { match tcx.hir.find(main_id) { @@ -229,7 +229,7 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, start_id: ast::NodeId, start_span: Span) { let start_def_id = tcx.hir.local_def_id(start_id); - let start_t = tcx.item_type(start_def_id); + let start_t = tcx.type_of(start_def_id); match start_t.sty { ty::TyFnDef(..) => { match tcx.hir.find(start_id) { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 1bde1eea37c3..5bbc285c3d5c 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -81,7 +81,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - let generics = tcx.item_generics(did); + let generics = tcx.generics_of(did); // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -89,14 +89,14 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { // // self.add_constraints_from_generics(generics); - for field in tcx.lookup_adt_def(did).all_fields() { + for field in tcx.adt_def(did).all_fields() { self.add_constraints_from_ty(generics, - tcx.item_type(field.did), + tcx.type_of(field.did), self.covariant); } } hir::ItemTrait(..) => { - let generics = tcx.item_generics(did); + let generics = tcx.generics_of(did); let trait_ref = ty::TraitRef { def_id: did, substs: Substs::identity_for_item(tcx, did) @@ -233,7 +233,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } else { // Parameter on an item defined within another crate: // variance already inferred, just look it up. - let variances = self.tcx().item_variances(item_def_id); + let variances = self.tcx().variances_of(item_def_id); self.constant_term(variances[index]) } } @@ -286,10 +286,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { trait_ref, variance); - let trait_generics = self.tcx().item_generics(trait_ref.def_id); + let trait_generics = self.tcx().generics_of(trait_ref.def_id); // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See + // `trait_def`, but I'm trying to be future-proof. See // README.md for a discussion on dep-graph management. self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id)); @@ -345,10 +345,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyAdt(def, substs) => { - let adt_generics = self.tcx().item_generics(def.did); + let adt_generics = self.tcx().generics_of(def.did); // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See + // `trait_def`, but I'm trying to be future-proof. See // README.md for a discussion on dep-graph management. self.tcx().dep_graph.read(VarianceDepNode(def.did)); @@ -362,10 +362,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyProjection(ref data) => { let trait_ref = &data.trait_ref; - let trait_generics = self.tcx().item_generics(trait_ref.def_id); + let trait_generics = self.tcx().generics_of(trait_ref.def_id); // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See + // `trait_def`, but I'm trying to be future-proof. See // README.md for a discussion on dep-graph management. self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id)); diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 6628c7c521fd..27116cbbb7ae 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -137,8 +137,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { item_variances); } - tcx.maps.variances - .borrow_mut() + tcx.maps.variances_of.borrow_mut() .insert(item_def_id, Rc::new(item_variances)); } } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 890414e317c6..61ff154e458d 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -178,8 +178,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { // parameters". if self.num_inferred() == inferreds_on_entry { let item_def_id = self.tcx.hir.local_def_id(item_id); - self.tcx.maps.variances - .borrow_mut() + self.tcx.maps.variances_of.borrow_mut() .insert(item_def_id, self.empty_variances.clone()); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6016fd488f56..d68ce47b4cf4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -152,12 +152,12 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); - let predicates = cx.tcx.item_predicates(did); - let generics = (cx.tcx.item_generics(did), &predicates).clean(cx); + let predicates = cx.tcx.predicates_of(did); + let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); clean::Trait { - unsafety: cx.tcx.lookup_trait_def(did).unsafety, + unsafety: cx.tcx.trait_def(did).unsafety, generics: generics, items: trait_items, bounds: supertrait_bounds, @@ -165,7 +165,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { } fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { - let sig = cx.tcx.item_type(did).fn_sig(); + let sig = cx.tcx.type_of(did).fn_sig(); let constness = if cx.tcx.sess.cstore.is_const_fn(did) { hir::Constness::Const @@ -173,10 +173,10 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { hir::Constness::NotConst }; - let predicates = cx.tcx.item_predicates(did); + let predicates = cx.tcx.predicates_of(did); clean::Function { decl: (did, sig).clean(cx), - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), unsafety: sig.unsafety(), constness: constness, abi: sig.abi(), @@ -184,18 +184,18 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { } fn build_enum(cx: &DocContext, did: DefId) -> clean::Enum { - let predicates = cx.tcx.item_predicates(did); + let predicates = cx.tcx.predicates_of(did); clean::Enum { - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), variants_stripped: false, - variants: cx.tcx.lookup_adt_def(did).variants.clean(cx), + variants: cx.tcx.adt_def(did).variants.clean(cx), } } fn build_struct(cx: &DocContext, did: DefId) -> clean::Struct { - let predicates = cx.tcx.item_predicates(did); - let variant = cx.tcx.lookup_adt_def(did).struct_variant(); + let predicates = cx.tcx.predicates_of(did); + let variant = cx.tcx.adt_def(did).struct_variant(); clean::Struct { struct_type: match variant.ctor_kind { @@ -203,30 +203,30 @@ fn build_struct(cx: &DocContext, did: DefId) -> clean::Struct { CtorKind::Fn => doctree::Tuple, CtorKind::Const => doctree::Unit, }, - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } } fn build_union(cx: &DocContext, did: DefId) -> clean::Union { - let predicates = cx.tcx.item_predicates(did); - let variant = cx.tcx.lookup_adt_def(did).struct_variant(); + let predicates = cx.tcx.predicates_of(did); + let variant = cx.tcx.adt_def(did).struct_variant(); clean::Union { struct_type: doctree::Plain, - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } } fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { - let predicates = cx.tcx.item_predicates(did); + let predicates = cx.tcx.predicates_of(did); clean::Typedef { - type_: cx.tcx.item_type(did).clean(cx), - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + type_: cx.tcx.type_of(did).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), } } @@ -326,7 +326,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { }); } - let for_ = tcx.item_type(did).clean(cx); + let for_ = tcx.type_of(did).clean(cx); // Only inline impl if the implementing type is // reachable in rustdoc generated documentation @@ -336,7 +336,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } } - let predicates = tcx.item_predicates(did); + let predicates = tcx.predicates_of(did); let trait_items = tcx.associated_items(did).filter_map(|item| { match item.kind { ty::AssociatedKind::Const => { @@ -348,7 +348,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { Some(clean::Item { name: Some(item.name.clean(cx)), inner: clean::AssociatedConstItem( - tcx.item_type(item.def_id).clean(cx), + tcx.type_of(item.def_id).clean(cx), default, ), source: tcx.def_span(item.def_id).clean(cx), @@ -388,7 +388,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } ty::AssociatedKind::Type => { let typedef = clean::Typedef { - type_: tcx.item_type(item.def_id).clean(cx), + type_: tcx.type_of(item.def_id).clean(cx), generics: clean::Generics { lifetimes: vec![], type_params: vec![], @@ -408,7 +408,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } } }).collect::>(); - let polarity = tcx.trait_impl_polarity(did); + let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| { match bound { clean::TraitBound(polyt, _) => polyt.trait_, @@ -432,7 +432,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { provided_trait_methods: provided, trait_: trait_, for_: for_, - generics: (tcx.item_generics(did), &predicates).clean(cx), + generics: (tcx.generics_of(did), &predicates).clean(cx), items: trait_items, polarity: Some(polarity.clean(cx)), }), @@ -496,14 +496,14 @@ fn print_inlined_const(cx: &DocContext, did: DefId) -> String { fn build_const(cx: &DocContext, did: DefId) -> clean::Constant { clean::Constant { - type_: cx.tcx.item_type(did).clean(cx), + type_: cx.tcx.type_of(did).clean(cx), expr: print_inlined_const(cx, did) } } fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: cx.tcx.item_type(did).clean(cx), + type_: cx.tcx.type_of(did).clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, expr: "\n\n\n".to_string(), // trigger the "[definition]" links } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cf872db68237..a25eb60d2a2f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -606,7 +606,7 @@ impl<'tcx> Clean for ty::TypeParameterDef { did: self.def_id, bounds: vec![], // these are filled in from the where-clauses default: if self.has_default { - Some(cx.tcx.item_type(self.def_id).clean(cx)) + Some(cx.tcx.type_of(self.def_id).clean(cx)) } else { None } @@ -1356,19 +1356,19 @@ impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.kind { ty::AssociatedKind::Const => { - let ty = cx.tcx.item_type(self.def_id); + let ty = cx.tcx.type_of(self.def_id); AssociatedConstItem(ty.clean(cx), None) } ty::AssociatedKind::Method => { - let generics = (cx.tcx.item_generics(self.def_id), - &cx.tcx.item_predicates(self.def_id)).clean(cx); - let sig = cx.tcx.item_type(self.def_id).fn_sig(); + let generics = (cx.tcx.generics_of(self.def_id), + &cx.tcx.predicates_of(self.def_id)).clean(cx); + let sig = cx.tcx.type_of(self.def_id).fn_sig(); let mut decl = (self.def_id, sig).clean(cx); if self.method_has_self_argument { let self_ty = match self.container { ty::ImplContainer(def_id) => { - cx.tcx.item_type(def_id) + cx.tcx.type_of(def_id) } ty::TraitContainer(_) => cx.tcx.mk_self_type() }; @@ -1418,8 +1418,8 @@ impl<'tcx> Clean for ty::AssociatedItem { // are actually located on the trait/impl itself, so we need to load // all of the generics from there and then look for bounds that are // applied to this associated type in question. - let predicates = cx.tcx.item_predicates(did); - let generics = (cx.tcx.item_generics(did), &predicates).clean(cx); + let predicates = cx.tcx.predicates_of(did); + let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { WherePredicate::BoundPredicate { @@ -1454,7 +1454,7 @@ impl<'tcx> Clean for ty::AssociatedItem { } let ty = if self.defaultness.has_value() { - Some(cx.tcx.item_type(self.def_id)) + Some(cx.tcx.type_of(self.def_id)) } else { None }; @@ -1922,9 +1922,9 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyAnon(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = cx.tcx.item_predicates(def_id); + let predicates_of = cx.tcx.predicates_of(def_id); let substs = cx.tcx.lift(&substs).unwrap(); - let bounds = item_predicates.instantiate(cx.tcx, substs); + let bounds = predicates_of.instantiate(cx.tcx, substs); ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| { predicate.to_opt_poly_trait_ref().clean(cx) }).collect()) @@ -1963,7 +1963,7 @@ impl<'tcx> Clean for ty::FieldDef { stability: get_stability(cx, self.did), deprecation: get_deprecation(cx, self.did), def_id: self.did, - inner: StructFieldItem(cx.tcx.item_type(self.did).clean(cx)), + inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)), } } } @@ -2116,7 +2116,7 @@ impl<'tcx> Clean for ty::VariantDef { CtorKind::Const => VariantKind::CLike, CtorKind::Fn => { VariantKind::Tuple( - self.fields.iter().map(|f| cx.tcx.item_type(f.did).clean(cx)).collect() + self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect() ) } CtorKind::Fictive => { @@ -2132,7 +2132,7 @@ impl<'tcx> Clean for ty::VariantDef { def_id: field.did, stability: get_stability(cx, field.did), deprecation: get_deprecation(cx, field.did), - inner: StructFieldItem(cx.tcx.item_type(field.did).clean(cx)) + inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx)) } }).collect() }) diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 7240f0aedbd2..be02d24e4415 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -153,7 +153,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, if child == trait_ { return true } - let predicates = cx.tcx.item_super_predicates(child).predicates; + let predicates = cx.tcx.super_predicates_of(child).predicates; predicates.iter().filter_map(|pred| { if let ty::Predicate::Trait(ref pred) = *pred { if pred.0.trait_ref.self_ty().is_self() { From 3ad844cfe2cc130779ff876a5581b1cec02f6d3f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 18 Mar 2017 15:33:56 +0100 Subject: [PATCH 690/905] Add more explanation on RefCell::get_mut --- src/libcore/cell.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ba04cbb0543c..f62057b3a52d 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -725,6 +725,15 @@ impl RefCell { /// This call borrows `RefCell` mutably (at compile-time) so there is no /// need for dynamic checks. /// + /// However be cautious: this method expects `self` to be mutable, which is + /// generally not the case when using a `RefCell`. Take a look at the + /// [`borrow_mut`] method instead if `self` isn't mutable. + /// + /// Also, please be aware that this method is only for special circumstances and is usually + /// not you want. In case of doubt, use [`borrow_mut`] instead. + /// + /// [`borrow_mut`]: #method.borrow_mut + /// /// # Examples /// /// ``` From e4825290223f39647bf2782b9d4ef5f00554c7ee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Dec 2016 16:12:38 -0800 Subject: [PATCH 691/905] Fix invalid module suggestion --- src/libsyntax/parse/parser.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1baf0d1b54ce..dd32b40554b5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5363,26 +5363,33 @@ impl<'a> Parser<'a> { } let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); - let this_module = match self.directory.path.file_name() { - Some(file_name) => file_name.to_str().unwrap().to_owned(), - None => self.root_module_name.as_ref().unwrap().clone(), - }; - err.span_note(id_sp, - &format!("maybe move this module `{0}` to its own directory \ - via `{0}{1}mod.rs`", - this_module, - path::MAIN_SEPARATOR)); + if id_sp != syntax_pos::DUMMY_SP { + let full_path = self.sess.codemap().span_to_filename(id_sp); + let path = Path::new(&full_path); + let filename = path.file_stem().unwrap(); + let parent = path.parent().unwrap_or(Path::new("")) + .to_str().unwrap_or("").to_owned(); + let path = format!("{}/{}", + if parent.len() == 0 { "." } else { &parent }, + filename.to_str().unwrap_or("")); + err.span_note(id_sp, + &format!("maybe move this module `{0}` to its own directory \ + via `{0}{1}mod.rs`", + path, + path::MAIN_SEPARATOR)); + } if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ of possibly redeclaring it", paths.name)); - Err(err) - } else { - Err(err) } + Err(err) } else { - paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) + match paths.result { + Ok(succ) => Ok(succ), + Err(err) => Err(self.span_fatal_err(id_sp, &err.err_msg, &err.help_msg)), + } } } From bd880bc6bf62a223664467d4df2b056a9122b7e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 3 Jan 2017 12:19:13 +0100 Subject: [PATCH 692/905] Add tests for module suggestions --- src/libsyntax/parse/parser.rs | 43 ++++++++++++------- src/test/compile-fail/auxiliary/foo/bar.rs | 11 +++++ src/test/compile-fail/auxiliary/foo/mod.rs | 11 +++++ .../invalid-module-declaration.rs | 20 +++++++++ 4 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 src/test/compile-fail/auxiliary/foo/bar.rs create mode 100644 src/test/compile-fail/auxiliary/foo/mod.rs create mode 100644 src/test/compile-fail/invalid-module-declaration.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dd32b40554b5..ac72d21ec427 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -58,8 +58,11 @@ use symbol::{Symbol, keywords}; use util::ThinVec; use std::collections::HashSet; -use std::{cmp, mem, slice}; -use std::path::{self, Path, PathBuf}; +use std::env; +use std::mem; +use std::path::{Path, PathBuf}; +use std::rc::Rc; +use std::slice; bitflags! { flags Restrictions: u8 { @@ -5364,19 +5367,29 @@ impl<'a> Parser<'a> { let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); if id_sp != syntax_pos::DUMMY_SP { - let full_path = self.sess.codemap().span_to_filename(id_sp); - let path = Path::new(&full_path); - let filename = path.file_stem().unwrap(); - let parent = path.parent().unwrap_or(Path::new("")) - .to_str().unwrap_or("").to_owned(); - let path = format!("{}/{}", - if parent.len() == 0 { "." } else { &parent }, - filename.to_str().unwrap_or("")); - err.span_note(id_sp, - &format!("maybe move this module `{0}` to its own directory \ - via `{0}{1}mod.rs`", - path, - path::MAIN_SEPARATOR)); + let mut src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); + if let Some(stem) = src_path.clone().file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + if let Ok(cur_dir) = env::current_dir() { + let tmp = if let (Ok(src_path), Ok(dest_path)) = + (Path::new(&src_path).strip_prefix(&cur_dir), + Path::new(&dest_path).strip_prefix(&cur_dir)) { + Some((src_path.to_path_buf(), dest_path.to_path_buf())) + } else { + None + }; + if let Some(tmp) = tmp { + src_path = tmp.0; + dest_path = tmp.1; + } + } + err.span_note(id_sp, + &format!("maybe move this module `{}` to its own \ + directory via `{}`", src_path.to_string_lossy(), + dest_path.to_string_lossy())); + } } if paths.path_exists { err.span_note(id_sp, diff --git a/src/test/compile-fail/auxiliary/foo/bar.rs b/src/test/compile-fail/auxiliary/foo/bar.rs new file mode 100644 index 000000000000..4b6b4f5ebf82 --- /dev/null +++ b/src/test/compile-fail/auxiliary/foo/bar.rs @@ -0,0 +1,11 @@ +// 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. + +pub mod baz; diff --git a/src/test/compile-fail/auxiliary/foo/mod.rs b/src/test/compile-fail/auxiliary/foo/mod.rs new file mode 100644 index 000000000000..6d77fb60a35d --- /dev/null +++ b/src/test/compile-fail/auxiliary/foo/mod.rs @@ -0,0 +1,11 @@ +// 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. + +pub mod bar; diff --git a/src/test/compile-fail/invalid-module-declaration.rs b/src/test/compile-fail/invalid-module-declaration.rs new file mode 100644 index 000000000000..658fa0a65c47 --- /dev/null +++ b/src/test/compile-fail/invalid-module-declaration.rs @@ -0,0 +1,20 @@ +// 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. + +// ignore-tidy-linelength + +// error-pattern: cannot declare a new module at this location +// error-pattern: maybe move this module `src/test/compile-fail/auxiliary/foo/bar.rs` to its own directory via `src/test/compile-fail/auxiliary/foo/bar/mod.rs` + +mod auxiliary { + mod foo; +} + +fn main() {} From b10c04472bf0969d123aa4461a7f0a1a255ac660 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Feb 2017 17:08:46 +0100 Subject: [PATCH 693/905] Remove strip prefix --- src/libsyntax/parse/parser.rs | 18 ++---------------- .../compile-fail/invalid-module-declaration.rs | 2 +- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac72d21ec427..9df791c1c124 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -58,7 +58,6 @@ use symbol::{Symbol, keywords}; use util::ThinVec; use std::collections::HashSet; -use std::env; use std::mem; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -5367,24 +5366,11 @@ impl<'a> Parser<'a> { let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); if id_sp != syntax_pos::DUMMY_SP { - let mut src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); + let src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); if let Some(stem) = src_path.clone().file_stem() { let mut dest_path = src_path.clone(); dest_path.set_file_name(stem); dest_path.push("mod.rs"); - if let Ok(cur_dir) = env::current_dir() { - let tmp = if let (Ok(src_path), Ok(dest_path)) = - (Path::new(&src_path).strip_prefix(&cur_dir), - Path::new(&dest_path).strip_prefix(&cur_dir)) { - Some((src_path.to_path_buf(), dest_path.to_path_buf())) - } else { - None - }; - if let Some(tmp) = tmp { - src_path = tmp.0; - dest_path = tmp.1; - } - } err.span_note(id_sp, &format!("maybe move this module `{}` to its own \ directory via `{}`", src_path.to_string_lossy(), @@ -5401,7 +5387,7 @@ impl<'a> Parser<'a> { } else { match paths.result { Ok(succ) => Ok(succ), - Err(err) => Err(self.span_fatal_err(id_sp, &err.err_msg, &err.help_msg)), + Err(err) => Err(self.span_fatal_err(id_sp, err)), } } } diff --git a/src/test/compile-fail/invalid-module-declaration.rs b/src/test/compile-fail/invalid-module-declaration.rs index 658fa0a65c47..c15cfb8cc8e2 100644 --- a/src/test/compile-fail/invalid-module-declaration.rs +++ b/src/test/compile-fail/invalid-module-declaration.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // error-pattern: cannot declare a new module at this location -// error-pattern: maybe move this module `src/test/compile-fail/auxiliary/foo/bar.rs` to its own directory via `src/test/compile-fail/auxiliary/foo/bar/mod.rs` +// error-pattern: maybe move this module mod auxiliary { mod foo; From 9bde6b6d96ccb76825c8e3bca54c28727ceeed63 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 24 Apr 2017 17:23:36 +0300 Subject: [PATCH 694/905] rustc: expose the common DUMMY_SP query case as tcx methods. --- src/librustc/lint/context.rs | 4 +- src/librustc/middle/dead.rs | 3 +- src/librustc/middle/reachable.rs | 5 +- src/librustc/middle/stability.rs | 2 +- src/librustc/ty/maps.rs | 7 ++ src/librustc/ty/mod.rs | 79 ++----------------- src/librustc/ty/util.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 4 +- src/librustc_const_eval/eval.rs | 4 +- src/librustc_metadata/encoder.rs | 4 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_privacy/lib.rs | 4 +- src/librustc_trans/callee.rs | 5 +- src/librustc_typeck/check/mod.rs | 2 +- .../coherence/inherent_impls.rs | 4 +- .../coherence/inherent_impls_overlap.rs | 4 +- src/librustc_typeck/coherence/mod.rs | 9 +-- src/librustdoc/clean/inline.rs | 3 +- 18 files changed, 39 insertions(+), 108 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 20bf241a9990..6947e7c3f408 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -43,7 +43,7 @@ use std::fmt; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; -use syntax_pos::{DUMMY_SP, MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span}; use errors::{self, Diagnostic, DiagnosticBuilder}; use hir; use hir::def_id::LOCAL_CRATE; @@ -1234,7 +1234,7 @@ fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck); - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir.krate(); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 0be8484b7840..0840495ff77a 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -26,7 +26,6 @@ use util::nodemap::FxHashSet; use syntax::{ast, codemap}; use syntax::attr; -use syntax::codemap::DUMMY_SP; use syntax_pos; // Any local node that may call something in its body block should be @@ -593,7 +592,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir.krate(); let live_symbols = find_live(tcx, access_levels, krate); let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index be4ec16cd63a..431760b6fcd6 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -28,7 +28,6 @@ use util::nodemap::{NodeSet, FxHashSet}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::codemap::DUMMY_SP; use hir; use hir::def_id::LOCAL_CRATE; use hir::intravisit::{Visitor, NestedVisitorMap}; @@ -364,13 +363,13 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { - ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) + tcx.reachable_set(LOCAL_CRATE) } fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc { debug_assert!(crate_num == LOCAL_CRATE); - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 1e856f6716ef..7431eb3fe96e 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -656,7 +656,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let sess = &tcx.sess; - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api { let krate = tcx.hir.krate(); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index f743da24972a..3023e006d1b1 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -351,6 +351,13 @@ macro_rules! define_maps { } })* + impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> { + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + queries::$name::get(self, DUMMY_SP, key) + })* + } + pub struct Providers<$tcx> { $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $V),* } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d5cd3742ffcc..9af8e2a3fc22 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1686,7 +1686,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { let substs = Substs::empty(); - match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) { + match tcx.const_eval((expr_did, substs)) { Ok(ConstVal::Integral(v)) => { discr = v; } @@ -1725,7 +1725,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } ty::VariantDiscr::Explicit(expr_did) => { let substs = Substs::empty(); - match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) { + match tcx.const_eval((expr_did, substs)) { Ok(ConstVal::Integral(v)) => { explicit_value = v; break; @@ -1760,7 +1760,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { - queries::adt_destructor::get(tcx, DUMMY_SP, self.did) + tcx.adt_destructor(self.did) } /// Returns a list of types such that `Self: Sized` if and only @@ -2045,10 +2045,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.typeck_tables_of(self.hir.body_owner_def_id(body)) } - pub fn typeck_tables_of(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> { - queries::typeck_tables_of::get(self, DUMMY_SP, def_id) - } - pub fn expr_span(self, id: NodeId) -> Span { match self.hir.find(id) { Some(hir_map::NodeExpr(e)) => { @@ -2136,24 +2132,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect() } - pub fn impl_polarity(self, id: DefId) -> hir::ImplPolarity { - queries::impl_polarity::get(self, DUMMY_SP, id) - } - pub fn trait_relevant_for_never(self, did: DefId) -> bool { self.associated_items(did).any(|item| { item.relevant_for_never() }) } - pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo { - queries::coerce_unsized_info::get(self, DUMMY_SP, did) - } - - pub fn associated_item(self, def_id: DefId) -> AssociatedItem { - queries::associated_item::get(self, DUMMY_SP, def_id) - } - fn associated_item_from_trait_item_ref(self, parent_def_id: DefId, trait_item_ref: &hir::TraitItemRef) @@ -2207,10 +2191,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { - queries::associated_item_def_ids::get(self, DUMMY_SP, def_id) - } - #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. pub fn associated_items(self, def_id: DefId) -> impl Iterator + 'a { @@ -2218,12 +2198,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])) } - /// Returns the trait-ref corresponding to a given impl, or None if it is - /// an inherent impl. - pub fn impl_trait_ref(self, id: DefId) -> Option> { - queries::impl_trait_ref::get(self, DUMMY_SP, id) - } - /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { @@ -2325,40 +2299,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - // If the given item is in an external crate, looks up its type and adds it to - // the type cache. Returns the type parameters and type. - pub fn type_of(self, did: DefId) -> Ty<'gcx> { - queries::type_of::get(self, DUMMY_SP, did) - } - - /// Given the did of a trait, returns its canonical trait ref. - pub fn trait_def(self, did: DefId) -> &'gcx TraitDef { - queries::trait_def::get(self, DUMMY_SP, did) - } - - /// Given the did of an ADT, return a reference to its definition. - pub fn adt_def(self, did: DefId) -> &'gcx AdtDef { - queries::adt_def::get(self, DUMMY_SP, did) - } - - /// Given the did of an item, returns its generics. - pub fn generics_of(self, did: DefId) -> &'gcx Generics { - queries::generics_of::get(self, DUMMY_SP, did) - } - - /// Given the did of an item, returns its full set of predicates. - pub fn predicates_of(self, did: DefId) -> GenericPredicates<'gcx> { - queries::predicates_of::get(self, DUMMY_SP, did) - } - - /// Given the did of a trait, returns its superpredicates. - pub fn super_predicates_of(self, did: DefId) -> GenericPredicates<'gcx> { - queries::super_predicates_of::get(self, DUMMY_SP, did) - } - /// Given the did of an item, returns its MIR, borrowed immutably. pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { - queries::mir::get(self, DUMMY_SP, did).borrow() + self.mir(did).borrow() } /// Return the possibly-auto-generated MIR of a (DefId, Subst) pair. @@ -2367,7 +2310,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { match instance { ty::InstanceDef::Item(did) if true => self.item_mir(did), - _ => queries::mir_shims::get(self, DUMMY_SP, instance).borrow(), + _ => self.mir_shims(instance).borrow(), } } @@ -2399,10 +2342,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_attrs(did).iter().any(|item| item.check_name(attr)) } - pub fn variances_of(self, item_id: DefId) -> Rc> { - queries::variances_of::get(self, DUMMY_SP, item_id) - } - pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { let def = self.trait_def(trait_def_id); def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) @@ -2437,14 +2376,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS); } - pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind { - queries::closure_kind::get(self, DUMMY_SP, def_id) - } - - pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> { - queries::closure_type::get(self, DUMMY_SP, def_id) - } - /// Given the def_id of an impl, return the def_id of the trait it implements. /// If it implements no trait, return `None`. pub fn trait_id_of_impl(self, def_id: DefId) -> Option { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 007647a3297c..54e00efc08e7 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -369,7 +369,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return None; }; - ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait)); + self.coherent_trait((LOCAL_CRATE, drop_trait)); let mut dtor_did = None; let ty = self.type_of(adt_did); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 99e533cbb83f..401c878cd401 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -42,7 +42,7 @@ use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; -use syntax_pos::{DUMMY_SP, MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; @@ -63,7 +63,7 @@ pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - ty::queries::borrowck::get(tcx, DUMMY_SP, body_owner_def_id); + tcx.borrowck(body_owner_def_id); }); } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index cc9892ee8c21..e7ccf3cbdb8f 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -27,7 +27,7 @@ use rustc::util::nodemap::DefIdMap; use syntax::ast; use rustc::hir::{self, Expr}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use std::cmp::Ordering; @@ -773,7 +773,7 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + tcx.mir_const_qualif(def_id); tcx.hir.body(tcx.hir.body_owned_by(id)) } else { tcx.sess.cstore.item_body(tcx, def_id) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 949949d2e102..4fd8d478717a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -36,7 +36,7 @@ use syntax::ast::{self, CRATE_NODE_ID}; use syntax::codemap::Spanned; use syntax::attr; use syntax::symbol::Symbol; -use syntax_pos::{self, DUMMY_SP}; +use syntax_pos; use rustc::hir::{self, PatKind}; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -1169,7 +1169,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let body = tcx.hir.body_owned_by(id); Entry { - kind: EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id)), + kind: EntryKind::Const(tcx.mir_const_qualif(def_id)), visibility: self.lazy(&ty::Visibility::Public), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 3ef611dd3caf..48f70c268512 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -959,7 +959,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { let src = MirSource::from_node(tcx, id); if let MirSource::Const(_) = src { - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + tcx.mir_const_qualif(def_id); continue; } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index fb1c5738206c..06685665dd1d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -38,7 +38,7 @@ use rustc::ty::fold::TypeVisitor; use rustc::ty::maps::Providers; use rustc::util::nodemap::NodeSet; use syntax::ast; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; use std::cmp; use std::mem::replace; @@ -1222,7 +1222,7 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { tcx.dep_graph.with_ignore(|| { // FIXME - ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE) + tcx.privacy_access_levels(LOCAL_CRATE) }) } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 264e26e4594c..78e0a524ef2d 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -21,9 +21,8 @@ use declare; use llvm::{self, ValueRef}; use monomorphize::{self, Instance}; use rustc::hir::def_id::DefId; -use rustc::ty::{self, TypeFoldable}; +use rustc::ty::TypeFoldable; use rustc::ty::subst::Substs; -use syntax_pos::DUMMY_SP; use trans_item::TransItem; use type_of; @@ -105,7 +104,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // *in Rust code* may unwind. Foreign items like `extern "C" { // fn foo(); }` are assumed not to unwind **unless** they have // a `#[unwind]` attribute. - if !ty::queries::is_foreign_item::get(tcx, DUMMY_SP, instance.def_id()) { + if !tcx.is_foreign_item(instance.def_id()) { attributes::unwind(llfn, true); unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a27397fa444d..1c0c68ae7d7c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -621,7 +621,7 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult } pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { - ty::queries::typeck_item_bodies::get(tcx, DUMMY_SP, LOCAL_CRATE) + tcx.typeck_item_bodies(LOCAL_CRATE) } fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> CompileResult { diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 58603900e135..45881bb3b783 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -26,7 +26,7 @@ use rustc::util::nodemap::DefIdMap; use std::rc::Rc; use syntax::ast; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -67,7 +67,7 @@ pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4 let result = tcx.dep_graph.with_ignore(|| { - let crate_map = ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, ty_def_id.krate); + let crate_map = tcx.crate_inherent_impls(ty_def_id.krate); match crate_map.inherent_impls.get(&ty_def_id) { Some(v) => v.clone(), None => Rc::new(vec![]), diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 33280fb931aa..34aec8ef1ac8 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -14,8 +14,6 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt}; -use syntax_pos::DUMMY_SP; - pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); @@ -68,7 +66,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { } fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { - let impls = ty::queries::inherent_impls::get(self.tcx, DUMMY_SP, ty_def_id); + let impls = self.tcx.inherent_impls(ty_def_id); for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index abfee989d65f..56ae9d545751 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -16,11 +16,10 @@ // mappings. That mapping code resides here. use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::ty::{self, TyCtxt, TypeFoldable}; +use rustc::ty::{TyCtxt, TypeFoldable}; use rustc::ty::maps::Providers; use syntax::ast; -use syntax_pos::DUMMY_SP; mod builtin; mod inherent_impls; @@ -132,7 +131,7 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &trait_def_id in tcx.hir.krate().trait_impls.keys() { - ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id)); + tcx.coherent_trait((LOCAL_CRATE, trait_def_id)); } unsafety::check(tcx); @@ -140,6 +139,6 @@ pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { overlap::check_default_impls(tcx); // these queries are executed for side-effects (error reporting): - ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); - ty::queries::crate_inherent_impls_overlap_check::get(tcx, DUMMY_SP, LOCAL_CRATE); + tcx.crate_inherent_impls(LOCAL_CRATE); + tcx.crate_inherent_impls_overlap_check(LOCAL_CRATE); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d68ce47b4cf4..71bb53e9b81c 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -15,7 +15,6 @@ use std::io; use std::iter::once; use syntax::ast; -use syntax_pos::DUMMY_SP; use rustc::hir; use rustc::hir::def::{Def, CtorKind}; @@ -234,7 +233,7 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); - for &did in ty::queries::inherent_impls::get(tcx, DUMMY_SP, did).iter() { + for &did in tcx.inherent_impls(did).iter() { build_impl(cx, did, &mut impls); } From 0d63f13378f8d8625a439ecbb36b3f97d0d2263d Mon Sep 17 00:00:00 2001 From: Jessica Hamilton Date: Mon, 24 Apr 2017 14:21:36 +0000 Subject: [PATCH 695/905] Haiku: add missing cases of using LIBRARY_PATH --- src/bootstrap/bootstrap.py | 3 +++ src/bootstrap/util.rs | 2 ++ src/librustc_back/dynamic_lib.rs | 2 ++ src/tools/compiletest/src/procsrv.rs | 2 ++ 4 files changed, 9 insertions(+) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3233a73b007c..55622c6b81b2 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -367,6 +367,9 @@ class RustBuild(object): env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["DYLD_LIBRARY_PATH"]) \ if "DYLD_LIBRARY_PATH" in env else "" + env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ + (os.pathsep + env["LIBRARY_PATH"]) \ + if "LIBRARY_PATH" in env else "" env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index dab20f44bc36..e01c06b10fcd 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -139,6 +139,8 @@ pub fn dylib_path_var() -> &'static str { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } diff --git a/src/librustc_back/dynamic_lib.rs b/src/librustc_back/dynamic_lib.rs index 38e60060925e..e6f305c22b2d 100644 --- a/src/librustc_back/dynamic_lib.rs +++ b/src/librustc_back/dynamic_lib.rs @@ -68,6 +68,8 @@ impl DynamicLibrary { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs index 3d8f2296236a..dbda8f4d802c 100644 --- a/src/tools/compiletest/src/procsrv.rs +++ b/src/tools/compiletest/src/procsrv.rs @@ -20,6 +20,8 @@ pub fn dylib_env_var() -> &'static str { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } From feae5a08a2d5d8db14a4b99a050dbc14a6bffb2a Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Mon, 24 Apr 2017 09:49:29 -0500 Subject: [PATCH 696/905] Add Splice forget test --- src/libcollections/tests/string.rs | 7 +++++++ src/libcollections/tests/vec.rs | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/src/libcollections/tests/string.rs b/src/libcollections/tests/string.rs index a32f5e3357f3..b1731b2a5dca 100644 --- a/src/libcollections/tests/string.rs +++ b/src/libcollections/tests/string.rs @@ -475,6 +475,13 @@ fn test_splice_unbounded() { assert_eq!(t, "12345"); } +#[test] +fn test_splice_forget() { + let mut s = String::from("12345"); + ::std::mem::forget(s.splice(2..4, "789")); + assert_eq!(s, "12345"); +} + #[test] fn test_extend_ref() { let mut a = "foo".to_string(); diff --git a/src/libcollections/tests/vec.rs b/src/libcollections/tests/vec.rs index f47940dc33aa..29f18274962f 100644 --- a/src/libcollections/tests/vec.rs +++ b/src/libcollections/tests/vec.rs @@ -634,6 +634,14 @@ fn test_splice_unbounded() { assert_eq!(t, &[1, 2, 3, 4, 5]); } +#[test] +fn test_splice_forget() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + ::std::mem::forget(v.splice(2..4, a.iter().cloned())); + assert_eq!(v, &[1, 2]); +} + #[test] fn test_into_boxed_slice() { let xs = vec![1, 2, 3]; From decf7598ef3a245ddaed9272091b3afc3466617f Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 24 Apr 2017 18:06:39 +0300 Subject: [PATCH 697/905] rustc: use tcx.at(span) to set the location of a query. --- src/librustc/middle/const_val.rs | 4 +- src/librustc/ty/maps.rs | 43 +++++++++++++++---- src/librustc/ty/mod.rs | 5 +-- src/librustc/ty/util.rs | 2 +- src/librustc_const_eval/eval.rs | 2 +- src/librustc_metadata/encoder.rs | 6 +-- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_typeck/astconv.rs | 8 ++-- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 2 +- .../coherence/inherent_impls.rs | 2 +- src/librustc_typeck/collect.rs | 8 ++-- 13 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index ec7b3c4dd8df..74026abe64db 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,7 +14,7 @@ pub use rustc_const_math::ConstInt; use hir; use hir::def::Def; use hir::def_id::DefId; -use ty::{self, TyCtxt}; +use ty::TyCtxt; use ty::subst::Substs; use util::common::ErrorReported; use rustc_const_math::*; @@ -228,7 +228,7 @@ pub fn eval_length(tcx: TyCtxt, let count_expr = &tcx.hir.body(count).value; let count_def_id = tcx.hir.body_owner_def_id(count); let substs = Substs::empty(); - match ty::queries::const_eval::get(tcx, count_expr.span, (count_def_id, substs)) { + match tcx.at(count_expr.span).const_eval((count_def_id, substs)) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 3023e006d1b1..1407e57dc2a6 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -21,6 +21,7 @@ use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; +use std::ops::Deref; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; @@ -329,14 +330,6 @@ macro_rules! define_maps { Self::try_get_with(tcx, span, key, Clone::clone) } - $(#[$attr])* - pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V { - Self::try_get(tcx, span, key).unwrap_or_else(|e| { - tcx.report_cycle(e); - Value::from_cycle_error(tcx.global_tcx()) - }) - } - pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) { // FIXME(eddyb) Move away from using `DepTrackingMap` // so we don't have to explicitly ignore a false edge: @@ -351,10 +344,42 @@ macro_rules! define_maps { } })* + #[derive(Copy, Clone)] + pub struct TyCtxtAt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + pub span: Span, + } + + impl<'a, 'gcx, 'tcx> Deref for TyCtxtAt<'a, 'gcx, 'tcx> { + type Target = TyCtxt<'a, 'gcx, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.tcx + } + } + impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> { + /// Return a transparent wrapper for `TyCtxt` which uses + /// `span` as the location of queries performed through it. + pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> { + TyCtxtAt { + tcx: self, + span + } + } + $($(#[$attr])* pub fn $name(self, key: $K) -> $V { - queries::$name::get(self, DUMMY_SP, key) + self.at(DUMMY_SP).$name(key) + })* + } + + impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> { + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + queries::$name::try_get(self.tcx, self.span, key).unwrap_or_else(|e| { + self.report_cycle(e); + Value::from_cycle_error(self.global_tcx()) + }) })* } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9af8e2a3fc22..a923ae154027 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2699,9 +2699,8 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) { /// A map for the local crate mapping each type to a vector of its /// inherent impls. This is not meant to be used outside of coherence; /// rather, you should request the vector for a specific type via -/// `ty::queries::inherent_impls::get(def_id)` so as to minimize your -/// dependencies (constructing this map requires touching the entire -/// crate). +/// `tcx.inherent_impls(def_id)` so as to minimize your dependencies +/// (constructing this map requires touching the entire crate). #[derive(Clone, Debug)] pub struct CrateInherentImpls { pub inherent_impls: DefIdMap>>, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 54e00efc08e7..87921c80502e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -522,7 +522,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::TyAdt(def, substs) => { let ty::DtorckConstraint { dtorck_types, outlives - } = ty::queries::adt_dtorck_constraint::get(self, span, def.did); + } = self.at(span).adt_dtorck_constraint(def.did); Ok(ty::DtorckConstraint { // FIXME: we can try to recursively `dtorck_constraint_on_ty` // there, but that needs some way to handle cycles. diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index e7ccf3cbdb8f..9470316c7e7e 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -299,7 +299,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, match cx.tables.qpath_def(qpath, e.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - match ty::queries::const_eval::get(tcx, e.span, (def_id, substs)) { + match tcx.at(e.span).const_eval((def_id, substs)) { Ok(val) => val, Err(ConstEvalErr { kind: TypeckError, .. }) => { signal!(e, TypeckError); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 4fd8d478717a..783e7604cdaf 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -547,7 +547,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let kind = match impl_item.kind { ty::AssociatedKind::Const => { EntryKind::AssociatedConst(container, - ty::queries::mir_const_qualif::get(self.tcx, ast_item.span, def_id)) + self.tcx.at(ast_item.span).mir_const_qualif(def_id)) } ty::AssociatedKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { @@ -656,7 +656,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic, hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic, hir::ItemConst(..) => { - EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, item.span, def_id)) + EntryKind::Const(tcx.at(item.span).mir_const_qualif(def_id)) } hir::ItemFn(_, _, constness, .., body) => { let data = FnData { @@ -732,7 +732,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let coerce_unsized_info = trait_ref.and_then(|t| { if Some(t.def_id) == tcx.lang_items.coerce_unsized_trait() { - Some(ty::queries::coerce_unsized_info::get(tcx, item.span, def_id)) + Some(tcx.at(item.span).coerce_unsized_info(def_id)) } else { None } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 736c076ea154..7b267fa276b1 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -594,7 +594,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let c = &cx.tcx.hir.body(count).value; let def_id = cx.tcx.hir.body_owner_def_id(count); let substs = Substs::empty(); - let count = match ty::queries::const_eval::get(cx.tcx, c.span, (def_id, substs)) { + let count = match cx.tcx.at(c.span).const_eval((def_id, substs)) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 48f70c268512..afb775aa01e7 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -573,9 +573,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if substs.types().next().is_some() { self.add_type(constant.ty); } else { - let bits = ty::queries::mir_const_qualif::get(self.tcx, - constant.span, - def_id); + let bits = self.tcx.at(constant.span).mir_const_qualif(def_id); let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif"); self.add(qualif); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c18658998944..c06e0bd5cede 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -238,7 +238,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let default_needs_object_self = |p: &ty::TypeParameterDef| { if is_object && p.has_default { - if ty::queries::type_of::get(tcx, span, p.def_id).has_self_ty() { + if tcx.at(span).type_of(p.def_id).has_self_ty() { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -307,7 +307,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // This is a default type parameter. self.normalize_ty( span, - ty::queries::type_of::get(tcx, span, def.def_id) + tcx.at(span).type_of(def.def_id) .subst_spanned(tcx, substs, Some(span)) ) } @@ -600,7 +600,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let substs = self.ast_path_substs_for_ty(span, did, item_segment); self.normalize_ty( span, - ty::queries::type_of::get(self.tcx(), span, did).subst(self.tcx(), substs) + self.tcx().at(span).type_of(did).subst(self.tcx(), substs) ) } @@ -1018,7 +1018,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assert_eq!(opt_self_ty, None); self.prohibit_type_params(&path.segments); - let ty = ty::queries::type_of::get(tcx, span, def_id); + let ty = tcx.at(span).type_of(def_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6dd4fb7301bc..70d733682065 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -479,7 +479,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { - let impl_def_ids = ty::queries::inherent_impls::get(self.tcx, self.span, def_id); + let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id); for &impl_def_id in impl_def_ids.iter() { self.assemble_inherent_impl_probe(impl_def_id); } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 937769537683..57193b3584df 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -170,7 +170,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // course. if impl_did.is_local() { let span = tcx.def_span(impl_did); - ty::queries::coerce_unsized_info::get(tcx, span, impl_did); + tcx.at(span).coerce_unsized_info(impl_did); } } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 45881bb3b783..400aaf82fe42 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -14,7 +14,7 @@ //! for any change, but it is very cheap to compute. In practice, most //! code in the compiler never *directly* requests this map. Instead, //! it requests the inherent impls specific to some type (via -//! `ty::queries::inherent_impls::get(def_id)`). That value, however, +//! `tcx.inherent_impls(def_id)`). That value, however, //! is computed by selecting an idea from this table. use rustc::dep_graph::DepNode; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 83727e9da032..099586e6bcc2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { def_id: DefId) -> ty::GenericPredicates<'tcx> { - ty::queries::type_param_predicates::get(self.tcx, span, (self.item_def_id, def_id)) + self.tcx.at(span).type_param_predicates((self.item_def_id, def_id)) } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { @@ -475,7 +475,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { hir::ItemTrait(..) => { tcx.generics_of(def_id); tcx.trait_def(def_id); - ty::queries::super_predicates_of::get(tcx, it.span, def_id); + tcx.at(it.span).super_predicates_of(def_id); tcx.predicates_of(def_id); }, hir::ItemStruct(ref struct_def, _) | @@ -556,7 +556,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); let substs = Substs::empty(); - let result = ty::queries::const_eval::get(tcx, variant.span, (expr_did, substs)); + let result = tcx.at(variant.span).const_eval((expr_did, substs)); // enum variant evaluation happens before the global constant check // so we need to report the real error @@ -725,7 +725,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) { - ty::queries::super_predicates_of::get(tcx, item.span, bound.def_id()); + tcx.at(item.span).super_predicates_of(bound.def_id()); } ty::GenericPredicates { From 009f45f8f1fcc0d0a6700fec8e0fd64d5aa739d2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 17 Apr 2017 17:24:05 -0700 Subject: [PATCH 698/905] Run tests for the cargo submodule in tree Previously the `cargotest` suite would run some arbitrary revision of Cargo's test suite, but now that we're bundling it in tree we should be running the Cargo submodule's test suite instead. --- cargo | 2 +- src/bootstrap/check.rs | 40 ++++++++++++++++++++++++++---------- src/bootstrap/lib.rs | 13 ++++++++++++ src/bootstrap/mk/Makefile.in | 1 + src/bootstrap/step.rs | 4 ++++ src/tools/cargotest/main.rs | 20 ------------------ 6 files changed, 48 insertions(+), 32 deletions(-) diff --git a/cargo b/cargo index 8326a3683a90..03efb7fc8b0d 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 +Subproject commit 03efb7fc8b0dbb54973ee1b6188f3faf14fffe36 diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f8f641060c44..8ab07e9e5b56 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -78,14 +78,6 @@ pub fn linkcheck(build: &Build, host: &str) { pub fn cargotest(build: &Build, stage: u32, host: &str) { let ref compiler = Compiler::new(stage, host); - // Configure PATH to find the right rustc. NB. we have to use PATH - // and not RUSTC because the Cargo test suite has tests that will - // fail if rustc is not spelled `rustc`. - let path = build.sysroot(compiler).join("bin"); - let old_path = ::std::env::var("PATH").expect(""); - let sep = if cfg!(windows) { ";" } else {":" }; - let ref newpath = format!("{}{}{}", path.display(), sep, old_path); - // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise // quickly run into path name limit constraints. @@ -95,9 +87,35 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) { let _time = util::timeit(); let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest")); build.prepare_tool_cmd(compiler, &mut cmd); - build.run(cmd.env("PATH", newpath) - .arg(&build.cargo) - .arg(&out_dir)); + build.run(cmd.arg(&build.cargo) + .arg(&out_dir) + .env("RUSTC", build.compiler_path(compiler)) + .env("RUSTDOC", build.rustdoc(compiler))) +} + +/// Runs `cargo test` for `cargo` packaged with Rust. +pub fn cargo(build: &Build, stage: u32, host: &str) { + let ref compiler = Compiler::new(stage, host); + + // Configure PATH to find the right rustc. NB. we have to use PATH + // and not RUSTC because the Cargo test suite has tests that will + // fail if rustc is not spelled `rustc`. + let path = build.sysroot(compiler).join("bin"); + let old_path = ::std::env::var("PATH").expect(""); + let sep = if cfg!(windows) { ";" } else {":" }; + let ref newpath = format!("{}{}{}", path.display(), sep, old_path); + + let mut cargo = build.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.src.join("cargo/Cargo.toml")); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + // Don't run cross-compile tests, we may not have cross-compiled libstd libs + // available. + cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); + + build.run(cargo.env("PATH", newpath)); } /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler. diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 5e046f41673e..5f518ea56027 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -557,6 +557,19 @@ impl Build { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } + // When being built Cargo will at some point call `nmake.exe` on Windows + // MSVC. Unfortunately `nmake` will read these two environment variables + // below and try to intepret them. We're likely being run, however, from + // MSYS `make` which uses the same variables. + // + // As a result, to prevent confusion and errors, we remove these + // variables from our environment to prevent passing MSYS make flags to + // nmake, causing it to blow up. + if cfg!(target_env = "msvc") { + cargo.env_remove("MAKE"); + cargo.env_remove("MAKEFLAGS"); + } + // Environment variables *required* needed throughout the build // // FIXME: should update code to not require this env var diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 457ac825832c..a5df741e2bfc 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -55,6 +55,7 @@ check: check-aux: $(Q)$(BOOTSTRAP) test \ src/tools/cargotest \ + cargo \ src/test/pretty \ src/test/run-pass/pretty \ src/test/run-fail/pretty \ diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 17902a39df1e..d811e1122c42 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -470,6 +470,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("librustc")) .host(true) .run(move |s| check::cargotest(build, s.stage, s.target)); + rules.test("check-cargo", "cargo") + .dep(|s| s.name("tool-cargo")) + .host(true) + .run(move |s| check::cargo(build, s.stage, s.target)); rules.test("check-tidy", "src/tools/tidy") .dep(|s| s.name("tool-tidy").stage(0)) .default(true) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index c7113edbf9e6..012ee835494e 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -22,12 +22,6 @@ struct Test { } const TEST_REPOS: &'static [Test] = &[ - Test { - name: "cargo", - repo: "https://github.com/rust-lang/cargo", - sha: "0e1e34be7540bdaed4918457654fbf028cf69e56", - lock: None, - }, Test { name: "iron", repo: "https://github.com/iron/iron", @@ -61,20 +55,6 @@ const TEST_REPOS: &'static [Test] = &[ ]; fn main() { - // One of the projects being tested here is Cargo, and when being tested - // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately - // `nmake` will read these two environment variables below and try to - // intepret them. We're likely being run, however, from MSYS `make` which - // uses the same variables. - // - // As a result, to prevent confusion and errors, we remove these variables - // from our environment to prevent passing MSYS make flags to nmake, causing - // it to blow up. - if cfg!(target_env = "msvc") { - env::remove_var("MAKE"); - env::remove_var("MAKEFLAGS"); - } - let args = env::args().collect::>(); let ref cargo = args[1]; let out_dir = Path::new(&args[2]); From c66c6e96978cd81130587e9f4d1fa52dc1b183d6 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Tue, 11 Apr 2017 16:02:43 -0400 Subject: [PATCH 699/905] More methods for str boxes. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../src/library-features/str-box-extras.md | 9 ++++++++ src/liballoc/boxed.rs | 18 +++++++++++----- src/liballoc/lib.rs | 2 ++ src/liballoc/str.rs | 21 +++++++++++++++++++ src/libcollections/lib.rs | 1 + src/libcollections/str.rs | 11 +++++++++- src/libcollections/string.rs | 5 +++-- 8 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 src/doc/unstable-book/src/library-features/str-box-extras.md create mode 100644 src/liballoc/str.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 3e0415439774..76196173b11e 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -207,6 +207,7 @@ - [str_checked_slicing](library-features/str-checked-slicing.md) - [str_escape](library-features/str-escape.md) - [str_internals](library-features/str-internals.md) + - [str_box_extras](library-features/str-box-extras.md) - [str_mut_extras](library-features/str-mut-extras.md) - [test](library-features/test.md) - [thread_id](library-features/thread-id.md) diff --git a/src/doc/unstable-book/src/library-features/str-box-extras.md b/src/doc/unstable-book/src/library-features/str-box-extras.md new file mode 100644 index 000000000000..d05dcafa84da --- /dev/null +++ b/src/doc/unstable-book/src/library-features/str-box-extras.md @@ -0,0 +1,9 @@ +# `str_box_extras` + +The tracking issue for this feature is: [#str_box_extras] + +[#str_box_extras]: https://github.com/rust-lang/rust/issues/41119 + +------------------------ + + diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 43b0d72186a2..b03e3bb7a4bd 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -68,6 +68,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut}; use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, 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. @@ -320,8 +321,7 @@ impl Default for Box<[T]> { #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { - let default: Box<[u8]> = Default::default(); - unsafe { mem::transmute(default) } + unsafe { from_boxed_utf8_unchecked(Default::default()) } } } @@ -366,7 +366,7 @@ impl Clone for Box { let buf = RawVec::with_capacity(len); unsafe { ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len); - mem::transmute(buf.into_box()) // bytes to str ~magic + from_boxed_utf8_unchecked(buf.into_box()) } } } @@ -441,8 +441,16 @@ impl<'a, T: Copy> From<&'a [T]> for Box<[T]> { #[stable(feature = "box_from_slice", since = "1.17.0")] impl<'a> From<&'a str> for Box { fn from(s: &'a str) -> Box { - let boxed: Box<[u8]> = Box::from(s.as_bytes()); - unsafe { mem::transmute(boxed) } + unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) } + } +} + +#[stable(feature = "boxed_str_conv", since = "1.18.0")] +impl From> for Box<[u8]> { + fn from(s: Box) -> Self { + unsafe { + mem::transmute(s) + } } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0c01eabd593f..418a084da678 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -128,6 +128,8 @@ mod boxed_test; pub mod arc; pub mod rc; pub mod raw_vec; +#[unstable(feature = "str_box_extras", issue = "41119")] +pub mod str; pub mod oom; pub use oom::oom; diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs new file mode 100644 index 000000000000..c87db16a0f41 --- /dev/null +++ b/src/liballoc/str.rs @@ -0,0 +1,21 @@ +// 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. + +//! Methods for dealing with boxed strings. +use core::mem; + +use boxed::Box; + +/// Converts a boxed slice of bytes to a boxed string slice without checking +/// that the string contains valid UTF-8. +#[unstable(feature = "str_box_extras", issue = "41119")] +pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { + mem::transmute(v) +} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 3bea61f6220b..c3db76e6c759 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -60,6 +60,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] +#![feature(str_box_extras)] #![feature(str_mut_extras)] #![feature(trusted_len)] #![feature(unicode)] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 8168e02bf826..964660183e75 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -70,14 +70,17 @@ pub use core::str::{Matches, RMatches}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8, Chars, CharIndices, Bytes}; +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}; +#[unstable(feature = "str_box_extras", issue = "41119")] +pub use alloc::str::from_boxed_utf8_unchecked; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; + #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] @@ -1715,6 +1718,12 @@ impl str { core_str::StrExt::parse(self) } + /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. + #[unstable(feature = "str_box_extras", issue = "41119")] + pub fn into_boxed_bytes(self: Box) -> Box<[u8]> { + self.into() + } + /// Replaces all matches of a pattern with another string. /// /// `replace` creates a new [`String`], and copies the data from this string slice into it. diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 8d6cf3051126..69dfb466d707 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -56,10 +56,11 @@ #![stable(feature = "rust1", since = "1.0.0")] +use alloc::str as alloc_str; + use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; -use core::mem; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str as core_str; @@ -1398,7 +1399,7 @@ impl String { #[stable(feature = "box_str", since = "1.4.0")] pub fn into_boxed_str(self) -> Box { let slice = self.vec.into_boxed_slice(); - unsafe { mem::transmute::, Box>(slice) } + unsafe { alloc_str::from_boxed_utf8_unchecked(slice) } } } From 957d51aecb3eb4960129b38b147cff0b8d0fae5c Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 25 Apr 2017 01:02:59 +0200 Subject: [PATCH 700/905] Fix a copy-paste error in `Instant::sub_duration` Fixes #41514. --- src/libstd/sys/unix/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index a08cec38f732..a1ad94872de5 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -157,7 +157,7 @@ mod inner { pub fn sub_duration(&self, other: &Duration) -> Instant { Instant { t: self.t.checked_sub(dur2intervals(other)) - .expect("overflow when adding duration to instant"), + .expect("overflow when subtracting duration from instant"), } } } From 70e673952ee7544576e2912efe9735bc4617e447 Mon Sep 17 00:00:00 2001 From: Andrew Gaspar Date: Mon, 20 Feb 2017 11:10:32 -0800 Subject: [PATCH 701/905] Adds rust-windbg.cmd script --- src/bootstrap/dist.rs | 7 ++++++- src/etc/rust-windbg.cmd | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/etc/rust-windbg.cmd diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 4328c4e3f1d4..ada8d4df604e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -254,7 +254,12 @@ pub fn debugger_scripts(build: &Build, install(&build.src.join("src/etc/").join(file), &dst, 0o644); }; if host.contains("windows-msvc") { - // no debugger scripts + // windbg debugger scripts + install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), + 0o755); + + cp_debugger_script("natvis/libcore.natvis"); + cp_debugger_script("natvis/libcollections.natvis"); } else { cp_debugger_script("debugger_pretty_printers_common.py"); diff --git a/src/etc/rust-windbg.cmd b/src/etc/rust-windbg.cmd new file mode 100644 index 000000000000..4cdd6b986099 --- /dev/null +++ b/src/etc/rust-windbg.cmd @@ -0,0 +1,18 @@ +@echo off +setlocal + +REM Copyright 2014 The Rust Project Developers. See the COPYRIGHT +REM file at the top-level directory of this distribution and at +REM http://rust-lang.org/COPYRIGHT. +REM +REM Licensed under the Apache License, Version 2.0 or the MIT license +REM , at your +REM option. This file may not be copied, modified, or distributed +REM except according to those terms. + +for /f "delims=" %%i in ('rustc --print=sysroot') do set rustc_sysroot=%%i + +set rust_etc=%rustc_sysroot%\lib\rustlib\etc + +windbg -c ".nvload %rust_etc%\libcore.natvis;.nvload %rust_etc%\libcollections.natvis;" %* \ No newline at end of file From a765dcaf5378cbd6cfa71f3fdeede82eeca4fc26 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sat, 22 Apr 2017 01:14:18 -0700 Subject: [PATCH 702/905] Add internal accessor methods to io::{Chain, Take}. Resolves #29067. --- src/libstd/io/mod.rs | 131 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index cd096c115ba5..cf548346b176 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1494,6 +1494,83 @@ pub struct Chain { done_first: bool, } +impl Chain { + /// Consumes the `Chain`, returning the wrapped readers. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.into_inner(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="0")] + pub fn into_inner(self) -> (T, U) { + (self.first, self.second) + } + + /// Gets references to the underlying readers in this `Chain`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="0")] + pub fn get_ref(&self) -> (&T, &U) { + (&self.first, &self.second) + } + + /// Gets mutable references to the underlying readers in this `Chain`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let mut chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="0")] + pub fn get_mut(&mut self) -> (&mut T, &mut U) { + (&mut self.first, &mut self.second) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Chain { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1606,6 +1683,60 @@ impl Take { pub fn into_inner(self) -> T { self.inner } + + /// Gets a reference to the underlying reader. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="0")] + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying reader. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="0")] + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } } #[stable(feature = "rust1", since = "1.0.0")] From aab87e3e9e71696d475a0b2c57f0dee7f702fc27 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sat, 22 Apr 2017 03:35:53 -0700 Subject: [PATCH 703/905] Add more_io_inner_methods feature to unstable book. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../src/library-features/more-io-inner-methods.md | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 src/doc/unstable-book/src/library-features/more-io-inner-methods.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 613475730417..9b77d99403fd 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -160,6 +160,7 @@ - [linked_list_extras](library-features/linked-list-extras.md) - [lookup_host](library-features/lookup-host.md) - [manually_drop](library-features/manually-drop.md) + - [more_io_inner_methods](library-features/more-io-inner-methods.md) - [mpsc_select](library-features/mpsc-select.md) - [n16](library-features/n16.md) - [never_type_impls](library-features/never-type-impls.md) diff --git a/src/doc/unstable-book/src/library-features/more-io-inner-methods.md b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md new file mode 100644 index 000000000000..1b56a8b395c6 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md @@ -0,0 +1,9 @@ +# `more_io_inner_methods` + +The tracking issue for this feature is: None. + +------------------------ + +This feature enables several internal accessor methods on structures in +`std::io` including `Take::{get_ref, get_mut}` and `Chain::{into_inner, get_ref, +get_mut}`. From b52c8c2fcf9ff32e225f57456b65d72b736f3c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 23 Apr 2017 17:54:32 -0700 Subject: [PATCH 704/905] Reorder code, fix unittests --- src/librustc/diagnostics.rs | 29 +++- src/librustc/traits/error_reporting.rs | 145 ++++++++++++------ src/test/compile-fail/E0281.rs | 15 +- src/test/compile-fail/fn-variance-1.rs | 8 +- src/test/compile-fail/issue-36053-2.rs | 7 + .../unboxed-closures-vtable-mismatch.rs | 8 + .../ui/mismatched_types/closure-arg-count.rs | 1 + .../mismatched_types/closure-arg-count.stderr | 58 ++++--- .../mismatched_types/closure-mismatch.stderr | 7 +- 9 files changed, 192 insertions(+), 86 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 6f9d9817a447..8ef42826faca 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1049,18 +1049,19 @@ which expected that trait. This error typically occurs when working with `Fn`-based types. Erroneous code example: ```compile_fail,E0281 -fn foo(x: F) { } +fn foo(x: F) { } fn main() { - // type mismatch: the type ... implements the trait `core::ops::Fn<(_,)>`, - // but the trait `core::ops::Fn<()>` is required (expected (), found tuple + // type mismatch: ... implements the trait `core::ops::Fn<(String,)>`, + // but the trait `core::ops::Fn<(usize,)>` is required // [E0281] - foo(|y| { }); + foo(|y: String| { }); } ``` -The issue in this case is that `foo` is defined as accepting a `Fn` with no -arguments, but the closure we attempted to pass to it requires one argument. +The issue in this case is that `foo` is defined as accepting a `Fn` with one +argument of type `String`, but the closure we attempted to pass to it requires +one arguments of type `usize`. "##, E0282: r##" @@ -1807,6 +1808,20 @@ makes a difference in practice.) [rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md "##, +E0593: r##" +You tried to supply an `Fn`-based type with an incorrect number of arguments +than what was expected. Erroneous code example: + +```compile_fail,E0593 +fn foo(x: F) { } + +fn main() { + // [E0593] closure takes 1 argument but 0 arguments are required + foo(|y| { }); +} +``` +"##, + } @@ -1850,6 +1865,4 @@ register_diagnostics! { E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints E0587, // conflicting packed and align representation hints - E0593, // closure argument count mismatch - E0594 // closure mismatch } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index dc7e18f8172a..532a6be356e3 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -664,61 +664,52 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return; } let expected_trait_ty = expected_trait_ref.self_ty(); - if expected_trait_ty.is_closure() { - if let &TypeError::TupleSize(ref expected_found) = e { - let mut err = struct_span_err!(self.tcx.sess, span, E0593, - "closure takes {} parameter{} but {} parameter{} are required here", - expected_found.found, - if expected_found.found == 1 { "" } else { "s" }, - expected_found.expected, - if expected_found.expected == 1 { "" } else { "s" }); + let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| { + self.tcx.hir.span_if_local(did) + }); - err.span_label(span, &format!("expected closure that takes {} parameter{}", - expected_found.expected, - if expected_found.expected == 1 { - "" - } else { - "s" - })); - let closure_span = expected_trait_ty.ty_to_def_id().and_then(|did| { - self.tcx.hir.span_if_local(did) - }); - if let Some(span) = closure_span { - err.span_label(span, &format!("takes {} parameter{}", - expected_found.found, - if expected_found.found == 1 { - "" - } else { - "s" - })); - } - err + if let &TypeError::TupleSize(ref expected_found) = e { + // Expected `|x| { }`, found `|x, y| { }` + self.report_arg_count_mismatch(span, + found_span, + expected_found.expected, + expected_found.found, + expected_trait_ty.is_closure()) + } else if let &TypeError::Sorts(ref expected_found) = e { + let expected = if let ty::TyTuple(tys, _) = expected_found.expected.sty { + tys.len() } else { - let mut err = struct_span_err!(self.tcx.sess, span, E0594, - "closure mismatch: `{}` implements the trait `{}`, \ - but the trait `{}` is required", - expected_trait_ty, - expected_trait_ref, - actual_trait_ref); + 1 + }; + let found = if let ty::TyTuple(tys, _) = expected_found.found.sty { + tys.len() + } else { + 1 + }; - let closure_span = expected_trait_ty.ty_to_def_id().and_then(|did| { - self.tcx.hir.span_if_local(did) - }); - if let Some(span) = closure_span { - err.span_label(span, &format!("{}", e)); - } else { - err.note(&format!("{}", e)); - } - err + if expected != found { + // Expected `|| { }`, found `|x, y| { }` + // Expected `fn(x) -> ()`, found `|| { }` + self.report_arg_count_mismatch(span, + found_span, + expected, + found, + expected_trait_ty.is_closure()) + } else { + self.report_type_argument_mismatch(span, + found_span, + expected_trait_ty, + expected_trait_ref, + actual_trait_ref, + e) } } else { - struct_span_err!(self.tcx.sess, span, E0281, - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ty, - expected_trait_ref, - actual_trait_ref, - e) + self.report_type_argument_mismatch(span, + found_span, + expected_trait_ty, + expected_trait_ref, + actual_trait_ref, + e) } } @@ -731,6 +722,60 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.note_obligation_cause(&mut err, obligation); err.emit(); } + + fn report_type_argument_mismatch(&self, + span: Span, + found_span: Option, + expected_ty: Ty<'tcx>, + expected_ref: ty::PolyTraitRef<'tcx>, + found_ref: ty::PolyTraitRef<'tcx>, + type_error: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> + { + let mut err = struct_span_err!(self.tcx.sess, span, E0281, + "type mismatch: `{}` implements the trait `{}`, but the trait `{}` is required", + expected_ty, + expected_ref, + found_ref); + + err.span_label(span, &format!("{}", type_error)); + + if let Some(sp) = found_span { + err.span_label(span, &format!("requires `{}`", found_ref)); + err.span_label(sp, &format!("implements `{}`", expected_ref)); + } + + err + } + + fn report_arg_count_mismatch(&self, + span: Span, + found_span: Option, + expected: usize, + found: usize, + is_closure: bool) + -> DiagnosticBuilder<'tcx> + { + let mut err = struct_span_err!(self.tcx.sess, span, E0593, + "{} takes {} argument{} but {} argument{} {} required", + if is_closure { "closure" } else { "function" }, + found, + if found == 1 { "" } else { "s" }, + expected, + if expected == 1 { "" } else { "s" }, + if expected == 1 { "is" } else { "are" }); + + err.span_label(span, &format!("expected {} that takes {} argument{}", + if is_closure { "closure" } else { "function" }, + expected, + if expected == 1 { "" } else { "s" })); + if let Some(span) = found_span { + err.span_label(span, &format!("takes {} argument{}", + found, + if found == 1 { "" } else { "s" })); + } + err + } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/test/compile-fail/E0281.rs b/src/test/compile-fail/E0281.rs index d468cd3ff1bf..abb66c99fab9 100644 --- a/src/test/compile-fail/E0281.rs +++ b/src/test/compile-fail/E0281.rs @@ -8,9 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(x: F) { } +fn foo(x: F) { } fn main() { - foo(|y| { }); //~ ERROR E0281 - //~^ ERROR E0281 + foo(|y: String| { }); + //~^ ERROR E0281 + //~| ERROR E0281 + //~| NOTE implements + //~| NOTE implements + //~| NOTE requires + //~| NOTE requires + //~| NOTE expected usize, found struct `std::string::String` + //~| NOTE expected usize, found struct `std::string::String` + //~| NOTE required by `foo` + //~| NOTE required by `foo` } diff --git a/src/test/compile-fail/fn-variance-1.rs b/src/test/compile-fail/fn-variance-1.rs index d0d911b6eb93..4bea8177b7c5 100644 --- a/src/test/compile-fail/fn-variance-1.rs +++ b/src/test/compile-fail/fn-variance-1.rs @@ -19,9 +19,13 @@ fn apply(t: T, f: F) where F: FnOnce(T) { fn main() { apply(&3, takes_imm); apply(&3, takes_mut); - //~^ ERROR (types differ in mutability) + //~^ ERROR type mismatch + //~| NOTE types differ in mutability + //~| NOTE required by `apply` apply(&mut 3, takes_mut); apply(&mut 3, takes_imm); - //~^ ERROR (types differ in mutability) + //~^ ERROR type mismatch + //~| NOTE types differ in mutability + //~| NOTE required by `apply` } diff --git a/src/test/compile-fail/issue-36053-2.rs b/src/test/compile-fail/issue-36053-2.rs index 7da529487aa8..7e489621e210 100644 --- a/src/test/compile-fail/issue-36053-2.rs +++ b/src/test/compile-fail/issue-36053-2.rs @@ -18,4 +18,11 @@ fn main() { //~^ ERROR no method named `count` //~| ERROR E0281 //~| ERROR E0281 + //~| NOTE expected &str, found str + //~| NOTE expected &str, found str + //~| NOTE implements + //~| NOTE implements + //~| NOTE requires + //~| NOTE requires + //~| NOTE the method `count` exists but the following trait bounds } diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs index 28e8b8db2a46..7400a27fb6bc 100644 --- a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs +++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs @@ -20,8 +20,16 @@ fn call_itisize>(y: isize, mut f: F) -> isize { pub fn main() { let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); + //~^ NOTE implements + //~| NOTE implements let z = call_it(3, f); //~^ ERROR type mismatch //~| ERROR type mismatch + //~| NOTE expected isize, found usize + //~| NOTE expected isize, found usize + //~| NOTE requires + //~| NOTE requires + //~| NOTE required by `call_it` + //~| NOTE required by `call_it` println!("{}", z); } diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index fbe36cd8fd26..284f82d86eb9 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -9,6 +9,7 @@ // except according to those terms. fn main() { + [1, 2, 3].sort_by(|| panic!()); [1, 2, 3].sort_by(|tuple| panic!()); [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); } diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index f45734d675b8..c1b880b61627 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -1,43 +1,59 @@ -error[E0593]: closure takes 1 parameter but 2 parameters are required here +error[E0593]: closure takes 0 arguments but 2 arguments are required --> $DIR/closure-arg-count.rs:12:15 | -12 | [1, 2, 3].sort_by(|tuple| panic!()); - | ^^^^^^^ ---------------- takes 1 parameter +12 | [1, 2, 3].sort_by(|| panic!()); + | ^^^^^^^ ----------- takes 0 arguments | | - | expected closure that takes 2 parameters + | expected closure that takes 2 arguments -error[E0593]: closure takes 1 parameter but 2 parameters are required here +error[E0593]: closure takes 0 arguments but 2 arguments are required --> $DIR/closure-arg-count.rs:12:15 | -12 | [1, 2, 3].sort_by(|tuple| panic!()); - | ^^^^^^^ ---------------- takes 1 parameter +12 | [1, 2, 3].sort_by(|| panic!()); + | ^^^^^^^ ----------- takes 0 arguments | | - | expected closure that takes 2 parameters + | expected closure that takes 2 arguments + +error[E0593]: closure takes 1 argument but 2 arguments are required + --> $DIR/closure-arg-count.rs:13:15 + | +13 | [1, 2, 3].sort_by(|tuple| panic!()); + | ^^^^^^^ ---------------- takes 1 argument + | | + | expected closure that takes 2 arguments + +error[E0593]: closure takes 1 argument but 2 arguments are required + --> $DIR/closure-arg-count.rs:13:15 + | +13 | [1, 2, 3].sort_by(|tuple| panic!()); + | ^^^^^^^ ---------------- takes 1 argument + | | + | expected closure that takes 2 arguments error[E0308]: mismatched types - --> $DIR/closure-arg-count.rs:13:24 + --> $DIR/closure-arg-count.rs:14:24 | -13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); +14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); | ^^^^^^^^^^^^^^^ expected &{integer}, found tuple | = note: expected type `&{integer}` found type `(_, _)` -error[E0593]: closure takes 1 parameter but 2 parameters are required here - --> $DIR/closure-arg-count.rs:13:15 +error[E0593]: closure takes 1 argument but 2 arguments are required + --> $DIR/closure-arg-count.rs:14:15 | -13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); - | ^^^^^^^ -------------------------- takes 1 parameter +14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^ -------------------------- takes 1 argument | | - | expected closure that takes 2 parameters + | expected closure that takes 2 arguments -error[E0593]: closure takes 1 parameter but 2 parameters are required here - --> $DIR/closure-arg-count.rs:13:15 +error[E0593]: closure takes 1 argument but 2 arguments are required + --> $DIR/closure-arg-count.rs:14:15 | -13 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); - | ^^^^^^^ -------------------------- takes 1 parameter +14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^ -------------------------- takes 1 argument | | - | expected closure that takes 2 parameters + | expected closure that takes 2 arguments -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index 09e31b263bc3..5b3eb5931896 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -8,11 +8,14 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.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` -error[E0594]: closure mismatch: `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r (),)>` is required +error[E0281]: type mismatch: `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r (),)>` is required --> $DIR/closure-mismatch.rs:18:5 | 18 | baz(|_| ()); - | ^^^ ------ expected concrete lifetime, found bound lifetime parameter + | ^^^ ------ implements `std::ops::Fn<(_,)>` + | | + | requires `for<'r> std::ops::Fn<(&'r (),)>` + | expected concrete lifetime, found bound lifetime parameter | = 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` From 76397aea50a506ac177b74d352a0ebbe99d4cdc6 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Mon, 24 Apr 2017 16:46:05 -0700 Subject: [PATCH 705/905] Reference tracking issue for more_io_inner_methods. --- .../src/library-features/more-io-inner-methods.md | 4 +++- src/libstd/io/mod.rs | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/doc/unstable-book/src/library-features/more-io-inner-methods.md b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md index 1b56a8b395c6..c84f40e7ee55 100644 --- a/src/doc/unstable-book/src/library-features/more-io-inner-methods.md +++ b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md @@ -1,6 +1,8 @@ # `more_io_inner_methods` -The tracking issue for this feature is: None. +The tracking issue for this feature is: [#41519] + +[#41519]: https://github.com/rust-lang/rust/issues/41519 ------------------------ diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index cf548346b176..a30246ae88b6 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1515,7 +1515,7 @@ impl Chain { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "more_io_inner_methods", issue="0")] + #[unstable(feature = "more_io_inner_methods", issue="41519")] pub fn into_inner(self) -> (T, U) { (self.first, self.second) } @@ -1540,7 +1540,7 @@ impl Chain { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "more_io_inner_methods", issue="0")] + #[unstable(feature = "more_io_inner_methods", issue="41519")] pub fn get_ref(&self) -> (&T, &U) { (&self.first, &self.second) } @@ -1565,7 +1565,7 @@ impl Chain { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "more_io_inner_methods", issue="0")] + #[unstable(feature = "more_io_inner_methods", issue="41519")] pub fn get_mut(&mut self) -> (&mut T, &mut U) { (&mut self.first, &mut self.second) } @@ -1706,7 +1706,7 @@ impl Take { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "more_io_inner_methods", issue="0")] + #[unstable(feature = "more_io_inner_methods", issue="41519")] pub fn get_ref(&self) -> &T { &self.inner } @@ -1733,7 +1733,7 @@ impl Take { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "more_io_inner_methods", issue="0")] + #[unstable(feature = "more_io_inner_methods", issue="41519")] pub fn get_mut(&mut self) -> &mut T { &mut self.inner } From c168d8bb07392ca6c5e30c2cde1458c9e32bf03b Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Mon, 24 Apr 2017 16:46:21 -0700 Subject: [PATCH 706/905] Add cautions to io::get_mut method documentation. --- src/libstd/io/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index a30246ae88b6..d08ba591de01 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1547,6 +1547,10 @@ impl Chain { /// Gets mutable references to the underlying readers in this `Chain`. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// /// # Examples /// /// ``` @@ -1713,6 +1717,10 @@ impl Take { /// Gets a mutable reference to the underlying reader. /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// /// # Examples /// /// ``` From 93d57d64b86d574efa35e2fb354d8dc92153b8a7 Mon Sep 17 00:00:00 2001 From: kennytm Date: Tue, 18 Apr 2017 00:07:36 +0800 Subject: [PATCH 707/905] Pass `--format-version 1` to `cargo metadata`. Suppress warning introduced by rust-lang/cargo#3841. --- src/bootstrap/metadata.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 5918fe41e7c8..7b6b01655df5 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -58,6 +58,7 @@ fn build_krate(build: &mut Build, krate: &str) { // the dependency graph and what `-p` arguments there are. let mut cargo = Command::new(&build.cargo); cargo.arg("metadata") + .arg("--format-version").arg("1") .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); let output = output(&mut cargo); let output: Output = json::decode(&output).unwrap(); From 00dff0aa59ce2d71957ca16a4444c303910686a3 Mon Sep 17 00:00:00 2001 From: kennytm Date: Tue, 18 Apr 2017 04:22:16 +0800 Subject: [PATCH 708/905] Support AddressSanitizer and ThreadSanitizer on x86_64-apple-darwin. ASan and TSan are supported on macOS, and this commit enables their support. The sanitizers are always built as *.dylib on Apple platforms, so they cannot be statically linked into the corresponding `rustc_?san.rlib`. The dylibs are directly copied to `lib/rustlib/x86_64-apple-darwin/lib/` instead. Note, although Xcode also ships with their own copies of ASan/TSan dylibs, we cannot use them due to version mismatch. There is a caveat: the sanitizer libraries are linked as @rpath, so the user needs to additionally pass `-C rpath`: rustc -Z sanitizer=address -C rpath file.rs ^~~~~~~~ Otherwise there will be a runtime error: dyld: Library not loaded: @rpath/libclang_rt.asan_osx_dynamic.dylib Referenced from: /path/to/executable Reason: image not found Abort trap: 6 The next commit includes a temporary change in compiler to force the linker to emit a usable @rpath. --- .travis.yml | 4 +-- src/bootstrap/compile.rs | 19 ++++++++++++++ src/build_helper/lib.rs | 21 +++++++++++++++- src/librustc/session/config.rs | 2 +- src/librustc_asan/build.rs | 5 ++-- src/librustc_lsan/build.rs | 5 ++-- src/librustc_metadata/creader.rs | 25 +++++++++++++++---- src/librustc_msan/build.rs | 5 ++-- src/librustc_tsan/build.rs | 5 ++-- src/libstd/Cargo.toml | 4 +++ src/test/run-make/sanitizer-address/Makefile | 22 ++++++++++------ .../sanitizer-invalid-target/Makefile | 2 +- src/test/run-make/sanitizer-leak/Makefile | 8 +++--- src/test/run-make/sanitizer-memory/Makefile | 8 +++--- 14 files changed, 98 insertions(+), 37 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d56379dcceb..c5372609e9bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ matrix: # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - env: > RUST_CHECK_TARGET=check - RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin + RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers" SRC=. RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log @@ -98,7 +98,7 @@ matrix: install: *osx_install_sccache - env: > RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended" + RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index cd87b27d4f1a..6f1de62d07ee 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -115,6 +115,13 @@ pub fn std_link(build: &Build, if target.contains("musl") && !target.contains("mips") { copy_musl_third_party_objects(build, target, &libdir); } + + if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { + // The sanitizers are only built in stage1 or above, so the dylibs will + // be missing in stage0 and causes panic. See the `std()` function above + // for reason why the sanitizers are not built in stage0. + copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir); + } } /// Copies the crt(1,i,n).o startup objects @@ -126,6 +133,18 @@ fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) { } } +fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) { + for &sanitizer in &["asan", "tsan"] { + let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform); + let mut src_path = native_dir.join(sanitizer); + src_path.push("build"); + src_path.push("lib"); + src_path.push("darwin"); + src_path.push(&filename); + copy(&src_path, &into.join(filename)); + } +} + /// Build and prepare startup objects like rsbegin.o and rsend.o /// /// These are primarily used on Windows right now for linking executables/dlls. diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index cb58a916fb79..da00b970da97 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -198,7 +198,11 @@ pub fn native_lib_boilerplate(src_name: &str, let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap()); let out_dir = PathBuf::from(out_dir).join(out_name); t!(create_dir_racy(&out_dir)); - println!("cargo:rustc-link-lib=static={}", link_name); + if link_name.contains('=') { + println!("cargo:rustc-link-lib={}", link_name); + } else { + println!("cargo:rustc-link-lib=static={}", link_name); + } println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display()); let timestamp = out_dir.join("rustbuild.timestamp"); @@ -209,6 +213,21 @@ pub fn native_lib_boilerplate(src_name: &str, } } +pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result { + let (link_name, search_path) = match &*env::var("TARGET").unwrap() { + "x86_64-unknown-linux-gnu" => ( + format!("clang_rt.{}-x86_64", sanitizer_name), + "build/lib/linux", + ), + "x86_64-apple-darwin" => ( + format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name), + "build/lib/darwin", + ), + _ => return Err(()), + }; + native_lib_boilerplate("compiler-rt", sanitizer_name, &link_name, search_path) +} + fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool { t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { let meta = t!(e.metadata()); diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index fadb1844008c..462fd57cbf17 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -51,7 +51,7 @@ pub struct Config { pub uint_type: UintTy, } -#[derive(Clone, Hash)] +#[derive(Clone, Hash, Debug)] pub enum Sanitizer { Address, Leak, diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs index 2df2e001e6ff..3a80baa0485f 100644 --- a/src/librustc_asan/build.rs +++ b/src/librustc_asan/build.rs @@ -12,14 +12,13 @@ extern crate build_helper; extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "asan", "clang_rt.asan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("asan") { Ok(native) => native, _ => return, }; diff --git a/src/librustc_lsan/build.rs b/src/librustc_lsan/build.rs index 005163f41026..da53571a2439 100644 --- a/src/librustc_lsan/build.rs +++ b/src/librustc_lsan/build.rs @@ -12,14 +12,13 @@ extern crate build_helper; extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "lsan", "clang_rt.lsan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("lsan") { Ok(native) => native, _ => return, }; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7bc0e8a512be..966e814e3379 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -799,11 +799,26 @@ impl<'a> CrateLoader<'a> { fn inject_sanitizer_runtime(&mut self) { if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer { - // Sanitizers can only be used with x86_64 Linux executables linked - // to `std` - if self.sess.target.target.llvm_target != "x86_64-unknown-linux-gnu" { - self.sess.err(&format!("Sanitizers only work with the \ - `x86_64-unknown-linux-gnu` target.")); + // Sanitizers can only be used on some tested platforms with + // executables linked to `std` + const ASAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu", + "x86_64-apple-darwin"]; + const TSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu", + "x86_64-apple-darwin"]; + const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"]; + const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"]; + + let supported_targets = match *sanitizer { + Sanitizer::Address => ASAN_SUPPORTED_TARGETS, + Sanitizer::Thread => TSAN_SUPPORTED_TARGETS, + Sanitizer::Leak => LSAN_SUPPORTED_TARGETS, + Sanitizer::Memory => MSAN_SUPPORTED_TARGETS, + }; + if !supported_targets.contains(&&*self.sess.target.target.llvm_target) { + self.sess.err(&format!("{:?}Sanitizer only works with the `{}` target", + sanitizer, + supported_targets.join("` or `") + )); return } diff --git a/src/librustc_msan/build.rs b/src/librustc_msan/build.rs index c438b5250463..dcadbe86966e 100644 --- a/src/librustc_msan/build.rs +++ b/src/librustc_msan/build.rs @@ -12,14 +12,13 @@ extern crate build_helper; extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "msan", "clang_rt.msan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("msan") { Ok(native) => native, _ => return, }; diff --git a/src/librustc_tsan/build.rs b/src/librustc_tsan/build.rs index 055b344d2e94..5ea52f17a0fd 100644 --- a/src/librustc_tsan/build.rs +++ b/src/librustc_tsan/build.rs @@ -12,14 +12,13 @@ extern crate build_helper; extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "tsan", "clang_rt.tsan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("tsan") { Ok(native) => native, _ => return, }; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 46511452a723..717892be2aba 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -23,6 +23,10 @@ compiler_builtins = { path = "../libcompiler_builtins" } std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } +[target.x86_64-apple-darwin.dependencies] +rustc_asan = { path = "../librustc_asan" } +rustc_tsan = { path = "../librustc_tsan" } + [target.x86_64-unknown-linux-gnu.dependencies] rustc_asan = { path = "../librustc_asan" } rustc_lsan = { path = "../librustc_lsan" } diff --git a/src/test/run-make/sanitizer-address/Makefile b/src/test/run-make/sanitizer-address/Makefile index 5931145f3a47..61b25df1451b 100644 --- a/src/test/run-make/sanitizer-address/Makefile +++ b/src/test/run-make/sanitizer-address/Makefile @@ -1,11 +1,19 @@ -include ../tools.mk -# NOTE the address sanitizer only supports x86_64 linux -ifdef SANITIZER_SUPPORT -all: - $(RUSTC) -g -Z sanitizer=address -Z print-link-args overflow.rs | grep -q librustc_asan - $(TMPDIR)/overflow 2>&1 | grep -q stack-buffer-overflow -else -all: +# NOTE the address sanitizer only supports x86_64 linux and macOS +ifeq ($(TARGET),x86_64-apple-darwin) +ASAN_SUPPORT=$(SANITIZER_SUPPORT) +EXTRA_RUSTFLAG=-C rpath +else +ifeq ($(TARGET),x86_64-unknown-linux-gnu) +ASAN_SUPPORT=$(SANITIZER_SUPPORT) +EXTRA_RUSTFLAG= +endif +endif + +all: +ifeq ($(ASAN_SUPPORT),1) + $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | grep -q librustc_asan + $(TMPDIR)/overflow 2>&1 | grep -q stack-buffer-overflow endif diff --git a/src/test/run-make/sanitizer-invalid-target/Makefile b/src/test/run-make/sanitizer-invalid-target/Makefile index 6a1ce8bab2fb..82e32f099520 100644 --- a/src/test/run-make/sanitizer-invalid-target/Makefile +++ b/src/test/run-make/sanitizer-invalid-target/Makefile @@ -1,4 +1,4 @@ -include ../tools.mk all: - $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | grep -q 'Sanitizers only work with the `x86_64-unknown-linux-gnu` target' + $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | grep -q 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` target' diff --git a/src/test/run-make/sanitizer-leak/Makefile b/src/test/run-make/sanitizer-leak/Makefile index f02d948fdc84..b18dd1d45eda 100644 --- a/src/test/run-make/sanitizer-leak/Makefile +++ b/src/test/run-make/sanitizer-leak/Makefile @@ -1,10 +1,10 @@ -include ../tools.mk -ifdef SANITIZER_SUPPORT all: +ifeq ($(TARGET),x86_64-unknown-linux-gnu) +ifdef SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks' -else -all: - endif +endif + diff --git a/src/test/run-make/sanitizer-memory/Makefile b/src/test/run-make/sanitizer-memory/Makefile index 08682e5975e5..7502ef0e7a7b 100644 --- a/src/test/run-make/sanitizer-memory/Makefile +++ b/src/test/run-make/sanitizer-memory/Makefile @@ -1,10 +1,10 @@ -include ../tools.mk -ifdef SANITIZER_SUPPORT all: +ifeq ($(TARGET),x86_64-unknown-linux-gnu) +ifdef SANITIZER_SUPPORT $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | grep -q librustc_msan $(TMPDIR)/uninit 2>&1 | grep -q use-of-uninitialized-value -else -all: - endif +endif + From 86747a9952d9d112f64dd2671cfa8694a7822158 Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 20 Apr 2017 08:31:43 +0800 Subject: [PATCH 709/905] Force link with an absolute rpath when using sanitizer on macOS. --- src/librustc_trans/back/link.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 7c0522a9c8cf..e42e69d2a76e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -1122,6 +1122,19 @@ fn add_upstream_rust_crates(cmd: &mut Linker, cnum: CrateNum) { let src = sess.cstore.used_crate_source(cnum); let cratepath = &src.rlib.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); From 715811d0be05dcdc55b44f97d9fd2cd1eb7eee05 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 24 Apr 2017 09:56:54 +0000 Subject: [PATCH 710/905] support `default impl` for specialization pr review --- cargo | 2 +- rls | 2 +- src/compiler-rt | 2 +- src/doc/book | 2 +- src/doc/reference | 2 +- src/grammar/parser-lalr.y | 28 +++-- src/jemalloc | 2 +- src/liblibc | 2 +- src/librustc/hir/lowering.rs | 3 + src/librustc/ich/impls_hir.rs | 2 +- src/librustc/middle/cstore.rs | 2 + src/librustc/traits/project.rs | 25 +---- src/librustc/traits/util.rs | 21 ++++ src/librustc_metadata/cstore_impl.rs | 7 +- src/librustc_metadata/schema.rs | 1 + src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_typeck/check/mod.rs | 16 +-- src/librustc_typeck/collect.rs | 6 +- src/libsyntax/parse/parser.rs | 14 ++- src/rt/hoedown | 1 + ...zation-no-default-trait-implementations.rs | 19 ++++ .../specialization-basics-unsafe.rs | 106 ++++++++++++++++++ 22 files changed, 202 insertions(+), 65 deletions(-) create mode 160000 src/rt/hoedown create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs diff --git a/cargo b/cargo index c416fb60b11e..8326a3683a90 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 diff --git a/rls b/rls index 016cbc514cf4..6ecff95fdc3e 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 +Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce diff --git a/src/compiler-rt b/src/compiler-rt index a8fc4c169fac..d30da544a8af 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 +Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 diff --git a/src/doc/book b/src/doc/book index beea82b9230c..ad7de198561b 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 +Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 diff --git a/src/doc/reference b/src/doc/reference index b060f732145f..6b0de90d87dd 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d +Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 3aa76d168df0..69ba0c9098be 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -89,6 +89,7 @@ extern char *yytext; %token TRAIT %token TYPE %token UNSAFE +%token DEFAULT %token USE %token WHILE %token CONTINUE @@ -534,6 +535,11 @@ maybe_unsafe | %empty { $$ = mk_none(); } ; +maybe_default_impl +: IMPL { $$ = mk_none(); } +| DEFAULT IMPL { $$ = $1 } +; + trait_method : type_method { $$ = mk_node("Required", 1, $1); } | method { $$ = mk_node("Provided", 1, $1); } @@ -588,27 +594,27 @@ impl_method // they are ambiguous with traits. We do the same here, regrettably, // by splitting ty into ty and ty_prim. item_impl -: maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +: maybe_unsafe maybe_default_impl generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); + $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8, $2); } -| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_impl generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); + $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10, $2); } -| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_impl generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); + $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10, $2); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); + $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11, $2); } -| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' +| maybe_unsafe maybe_default_impl generic_params trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' +| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); } @@ -1935,4 +1941,4 @@ brackets_delimited_token_trees $2, mk_node("TTTok", 1, mk_atom("]"))); } -; +; \ No newline at end of file diff --git a/src/jemalloc b/src/jemalloc index e058ca661692..11bfb0dcf85f 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968 +Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 diff --git a/src/liblibc b/src/liblibc index 05a2d197356e..c34a802d1eb0 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f +Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d072340d8c88..8dda297e897b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1362,6 +1362,9 @@ impl<'a> LoweringContext<'a> { } ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } + + // [1] `defaultness.has_value()` is necer called for an `impl`, always `true` in order to + // not cause an assertion failure inside the `lower_defaultness` function } fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 82e03a9fddc3..3aeee1c1b981 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -933,7 +933,7 @@ impl_stable_hash_for!(enum hir::Item_ { ItemUnion(variant_data, generics), ItemTrait(unsafety, generics, bounds, item_refs), ItemDefaultImpl(unsafety, trait_ref), - ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) + ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) }); impl_stable_hash_for!(struct hir::TraitItemRef { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 3251addcb328..60171f1a4289 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -195,6 +195,7 @@ pub trait CrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -329,6 +330,7 @@ impl CrateStore for DummyCrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } // impl info + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index f417ad5b3d9d..7675b2d00ebb 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,7 +33,6 @@ use ty::subst::Subst; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; -use hir::{self}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -924,28 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - let is_default = match selcx.tcx() - .map - .as_local_node_id(node_item.node.def_id()) { - Some(node_id) => { - let item = selcx.tcx().map.expect_item(node_id); - if let hir::ItemImpl(_, _, defaultness, ..) = item.node { - defaultness.is_default() - } else { - false - } - } - None => { - selcx.tcx() - .global_tcx() - .sess - .cstore - .impl_defaultness(node_item.node.def_id()) - .is_default() - } - }; - - node_item.item.defaultness.is_default() || is_default + node_item.item.defaultness.is_default() || + selcx.tcx().impl_is_default(node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index d4245ec9b247..4aa7950de8f1 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -13,6 +13,7 @@ use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use ty::outlives::Component; use util::nodemap::FxHashSet; +use hir::{self}; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -504,6 +505,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; ty::Binder((trait_ref, sig.skip_binder().output())) } + + pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { + match self.hir.as_local_node_id(node_item_def_id) { + Some(node_id) => { + let item = self.hir.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_default() + } else { + false + } + } + None => { + self.global_tcx() + .sess + .cstore + .impl_defaultness(node_item_def_id) + .is_default() + } + } + } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 618c1711dad4..767114a37be4 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -90,7 +90,6 @@ provide! { <'tcx> tcx, def_id, cdata associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_polarity => { cdata.get_impl_polarity(def_id.index) } - impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); @@ -179,6 +178,12 @@ impl CrateStore for cstore::CStore { result } + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness + { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).get_impl_defaultness(def.index) + } + fn impl_parent(&self, impl_def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(impl_def)); self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index) diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 933c3482474b..5870903e7718 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -416,6 +416,7 @@ pub struct ImplData<'tcx> { impl_stable_hash_for!(struct ImplData<'tcx> { polarity, + defaultness, parent_impl, coerce_unsized_info, trait_ref diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 36e59b4774ad..507ac1efc2c6 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -429,7 +429,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } None => { - if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { trait_id = self.lookup_def_id(ty.id); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 74886e503a85..a00d1ad0eae6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1142,21 +1142,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(parent) = parent { if parent.item.is_final() { - let is_final = match tcx.map.as_local_node_id(parent.node.def_id()) { - Some(node_id) => { - let item = tcx.map.expect_item(node_id); - if let hir::ItemImpl(_, _, defaultness, ..) = item.node { - defaultness.is_final() - } else { - true - } - } - None => { - tcx.global_tcx().sess.cstore.impl_defaultness(parent.node.def_id()).is_final() - } - }; - - if is_final { + if !tcx.impl_is_default(parent.node.def_id()) { report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 660ce837043c..0203c3b6299f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -309,7 +309,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -825,7 +825,7 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) => generics, + ItemImpl(_, _, _, ref generics, ..) => generics, ItemTy(_, ref generics) | ItemEnum(_, ref generics) | @@ -1236,7 +1236,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 58f81c8b3d75..2c10fff03dbe 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4918,6 +4918,14 @@ impl<'a> Parser<'a> { allowed to have generics"); } + match defaultness { + ast::Defaultness::Default => { + self.span_err(impl_span, "`default impl` is not allowed for \ + default trait implementations"); + } + _ => {} + } + self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::CloseDelim(token::Brace))?; Ok((keywords::Invalid.ident(), @@ -5760,13 +5768,13 @@ impl<'a> Parser<'a> { } if (self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) || - (self.check_keyword(keywords::Default) && - self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) && + (self.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Default)) && self.look_ahead(2, |t| t.is_keyword(keywords::Impl))) { // IMPL ITEM - let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Impl)?; let (ident, item_, diff --git a/src/rt/hoedown b/src/rt/hoedown new file mode 160000 index 000000000000..da282f1bb727 --- /dev/null +++ b/src/rt/hoedown @@ -0,0 +1 @@ +Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs new file mode 100644 index 000000000000..c1746d765dd9 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.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. + +#![feature(specialization)] +#![feature(optin_builtin_traits)] + +trait Foo {} + +default impl Foo for .. {} +//~^ ERROR `default impl` is not allowed for default trait implementations + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs new file mode 100644 index 000000000000..9376d0db2df6 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs @@ -0,0 +1,106 @@ +// 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(specialization)] + +// Tests a variety of basic specialization scenarios and method +// dispatch for them. + +unsafe trait Foo { + fn foo(&self) -> &'static str; +} + +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +unsafe default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +unsafe default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +unsafe default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +unsafe default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +unsafe default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +unsafe impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +unsafe impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +unsafe impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +unsafe trait MyMarker {} +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} + +#[derive(Clone)] +struct MarkedAndClone; +unsafe impl MyMarker for MarkedAndClone {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); +} From c558a2ae37052dc1f12aa4e40578eb4ae9aca3b9 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Sun, 9 Apr 2017 02:03:31 -0400 Subject: [PATCH 711/905] Add Hexagon support This requires an updated LLVM with D31999 and D32000 to build libcore. A basic hello world builds and runs successfully on the hexagon simulator. --- src/librustc_llvm/build.rs | 2 +- src/librustc_llvm/lib.rs | 6 +++++ src/librustc_trans/abi.rs | 2 ++ src/librustc_trans/cabi_hexagon.rs | 43 ++++++++++++++++++++++++++++++ src/librustc_trans/lib.rs | 1 + src/rustllvm/PassWrapper.cpp | 9 ++++++- 6 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/librustc_trans/cabi_hexagon.rs diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 4871f60466df..3c88ae886d6f 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -94,7 +94,7 @@ fn main() { let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430", - "sparc", "nvptx"]; + "sparc", "nvptx", "hexagon"]; // FIXME: surely we don't need all these components, right? Stuff like mcjit // or interpreter the compiler itself never uses. diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 7c52ceae459c..c9b3a7ff3f3a 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -382,6 +382,12 @@ pub fn initialize_available_targets() { LLVMInitializeNVPTXTarget, LLVMInitializeNVPTXTargetMC, LLVMInitializeNVPTXAsmPrinter); + init_target!(llvm_component = "hexagon", + LLVMInitializeHexagonTargetInfo, + LLVMInitializeHexagonTarget, + LLVMInitializeHexagonTargetMC, + LLVMInitializeHexagonAsmPrinter, + LLVMInitializeHexagonAsmParser); } pub fn last_error() -> Option { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 998e392b1f90..a6b0eb473eb8 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -29,6 +29,7 @@ use cabi_sparc; use cabi_sparc64; use cabi_nvptx; use cabi_nvptx64; +use cabi_hexagon; use machine::llalign_of_min; use type_::Type; use type_of; @@ -896,6 +897,7 @@ impl<'a, 'tcx> FnType<'tcx> { "sparc64" => cabi_sparc64::compute_abi_info(ccx, self), "nvptx" => cabi_nvptx::compute_abi_info(ccx, self), "nvptx64" => cabi_nvptx64::compute_abi_info(ccx, self), + "hexagon" => cabi_hexagon::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } diff --git a/src/librustc_trans/cabi_hexagon.rs b/src/librustc_trans/cabi_hexagon.rs new file mode 100644 index 000000000000..1acda72675c3 --- /dev/null +++ b/src/librustc_trans/cabi_hexagon.rs @@ -0,0 +1,43 @@ +// 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. + +#![allow(non_upper_case_globals)] + +use abi::{FnType, ArgType, LayoutExt}; +use context::CrateContext; + +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 64 { + ret.make_indirect(ccx); + } else { + ret.extend_integer_width_to(32); + } +} + +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 64 { + arg.make_indirect(ccx); + } else { + arg.extend_integer_width_to(32); + } +} + +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { + continue; + } + classify_arg_ty(ccx, arg); + } +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 117d8568500b..d5fc2ee5e25e 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -97,6 +97,7 @@ mod builder; mod cabi_aarch64; mod cabi_arm; mod cabi_asmjs; +mod cabi_hexagon; mod cabi_mips; mod cabi_mips64; mod cabi_msp430; diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index c410a6b1349d..b938f94cda2c 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -147,6 +147,12 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) { #define SUBTARGET_SPARC #endif +#ifdef LLVM_COMPONENT_HEXAGON +#define SUBTARGET_HEXAGON SUBTARGET(Hexagon) +#else +#define SUBTARGET_HEXAGON +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ @@ -155,7 +161,8 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) { SUBTARGET_PPC \ SUBTARGET_SYSTEMZ \ SUBTARGET_MSP430 \ - SUBTARGET_SPARC + SUBTARGET_SPARC \ + SUBTARGET_HEXAGON #define SUBTARGET(x) \ namespace llvm { \ From 0e920fde4f686e2924ea3378ac55d26217b53eaf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 24 Mar 2017 17:31:41 +0100 Subject: [PATCH 712/905] Minimize single span suggestions into a note --- src/librustc_errors/diagnostic.rs | 24 ++++++++++------------- src/librustc_errors/diagnostic_builder.rs | 10 +++++----- src/librustc_errors/emitter.rs | 22 +++++++++++++++++---- src/librustc_errors/lib.rs | 1 + src/librustc_typeck/check/mod.rs | 4 +--- src/libsyntax/json.rs | 14 +++++++++++-- 6 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 9715ace3e2e2..38fa35ecb126 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -11,7 +11,6 @@ use CodeSuggestion; use Level; use RenderSpan; -use RenderSpan::Suggestion; use std::fmt; use syntax_pos::{MultiSpan, Span}; use snippet::Style; @@ -24,6 +23,7 @@ pub struct Diagnostic { pub code: Option, pub span: MultiSpan, pub children: Vec, + pub suggestion: Option, } /// For example a note attached to an error. @@ -87,6 +87,7 @@ impl Diagnostic { code: code, span: MultiSpan::new(), children: vec![], + suggestion: None, } } @@ -202,19 +203,14 @@ impl Diagnostic { /// Prints out a message with a suggested edit of the code. /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut Self { - self.sub(Level::Help, - msg, - MultiSpan::new(), - Some(Suggestion(CodeSuggestion { - msp: sp.into(), - substitutes: vec![suggestion], - }))); + /// See `diagnostic::CodeSuggestion` for more information. + pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { + assert!(self.suggestion.is_none()); + self.suggestion = Some(CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + msg: msg.to_owned(), + }); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7b27f13951b6..9dfd47b8464d 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -141,11 +141,11 @@ impl<'a> DiagnosticBuilder<'a> { sp: S, msg: &str) -> &mut Self); - forward!(pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut Self); + forward!(pub fn span_suggestion(&mut self, + sp: Span, + msg: &str, + suggestion: String) + -> &mut Self); forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: String) -> &mut Self); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 64652bb308bd..8855859d7c4a 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -34,6 +34,22 @@ impl Emitter for EmitterWriter { fn emit(&mut self, db: &DiagnosticBuilder) { let mut primary_span = db.span.clone(); let mut children = db.children.clone(); + + if let Some(sugg) = db.suggestion.clone() { + assert_eq!(sugg.msp.primary_spans().len(), sugg.substitutes.len()); + if sugg.substitutes.len() == 1 { + let msg = format!("{} `{}`", sugg.msg, sugg.substitutes[0]); + primary_span.push_span_label(sugg.msp.primary_spans()[0], msg); + } else { + children.push(SubDiagnostic { + level: Level::Help, + message: Vec::new(), + span: MultiSpan::new(), + render_span: Some(Suggestion(sugg)), + }); + } + } + self.fix_multispans_in_std_macros(&mut primary_span, &mut children); self.emit_messages_default(&db.level, &db.styled_message(), @@ -756,7 +772,7 @@ impl EmitterWriter { /// displayed, keeping the provided highlighting. fn msg_to_buffer(&self, buffer: &mut StyledBuffer, - msg: &Vec<(String, Style)>, + msg: &[(String, Style)], padding: usize, label: &str, override_style: Option