From 03acea646c025846e9421e33d77a5b19782762db Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 31 Jul 2017 17:14:16 +0000 Subject: [PATCH 01/88] Implement `RefCell::replace` and `RefCell::swap` --- src/libcore/cell.rs | 53 +++++++++++++++++++++++++++++++++++++++ src/libcore/tests/cell.rs | 17 +++++++++++++ src/libcore/tests/lib.rs | 1 + 3 files changed, 71 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 35744f3f16b3..b250bf49e0c0 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -543,6 +543,59 @@ impl RefCell { debug_assert!(self.borrow.get() == UNUSED); unsafe { self.value.into_inner() } } + + /// Replaces the wrapped value with a new one, returning the old value, + /// without deinitializing either one. + /// + /// This function corresponds to [`std::mem::replace`](../mem/fn.replace.html). + /// + /// # Example + /// + /// ``` + /// #![feature(refcell_replace_swap)] + /// use std::cell::RefCell; + /// let c = RefCell::new(5); + /// let u = c.replace(6); + /// assert_eq!(u, 5); + /// assert_eq!(c, RefCell::new(6)); + /// ``` + /// + /// # Panics + /// + /// This function will panic if the `RefCell` has any outstanding borrows, + /// whether or not they are full mutable borrows. + #[inline] + #[unstable(feature = "refcell_replace_swap", issue="43570")] + pub fn replace(&self, t: T) -> T { + mem::replace(&mut *self.borrow_mut(), t) + } + + /// Swaps the wrapped value of `self` with the wrapped value of `other`, + /// without deinitializing either one. + /// + /// This function corresponds to [`std::mem::swap`](../mem/fn.swap.html). + /// + /// # Example + /// + /// ``` + /// #![feature(refcell_replace_swap)] + /// use std::cell::RefCell; + /// let c = RefCell::new(5); + /// let d = RefCell::new(6); + /// c.swap(&d); + /// assert_eq!(c, RefCell::new(6)); + /// assert_eq!(d, RefCell::new(5)); + /// ``` + /// + /// # Panics + /// + /// This function will panic if the `RefCell` has any outstanding borrows, + /// whether or not they are full mutable borrows. + #[inline] + #[unstable(feature = "refcell_replace_swap", issue="43570")] + pub fn swap(&self, other: &Self) { + mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut()) + } } impl RefCell { diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index 8585f2f08711..cc0ef6a6f17e 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -287,3 +287,20 @@ fn refcell_ref_coercion() { assert_eq!(&*coerced, comp); } } + +#[test] +#[should_panic] +fn refcell_swap_borrows() { + let x = RefCell::new(0); + let _b = x.borrow(); + let y = RefCell::new(1); + x.swap(&y); +} + +#[test] +#[should_panic] +fn refcell_replace_borrows() { + let x = RefCell::new(0); + let _b = x.borrow(); + x.replace(1); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index a85c347146b0..84a3be99c275 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -31,6 +31,7 @@ #![feature(ord_max_min)] #![feature(rand)] #![feature(raw)] +#![feature(refcell_replace_swap)] #![feature(sip_hash_13)] #![feature(slice_patterns)] #![feature(slice_rotate)] From dc76247a0a7778a0f38d63bcc3ae5428327bfcf1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 2 Aug 2017 10:58:27 -0700 Subject: [PATCH 02/88] Change "Example" to "Examples" in the doc comments --- src/libcore/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b250bf49e0c0..675fcef5e5ab 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -549,7 +549,7 @@ impl RefCell { /// /// This function corresponds to [`std::mem::replace`](../mem/fn.replace.html). /// - /// # Example + /// # Examples /// /// ``` /// #![feature(refcell_replace_swap)] @@ -575,7 +575,7 @@ impl RefCell { /// /// This function corresponds to [`std::mem::swap`](../mem/fn.swap.html). /// - /// # Example + /// # Examples /// /// ``` /// #![feature(refcell_replace_swap)] From 63fc1faf8298d2bd4e9385a2e0286b2ee0db6866 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 00:52:51 +0200 Subject: [PATCH 03/88] Revise documentation in core::ops::arith Part of #29365. * Replaced examples for Mul-/Div-/RemAssign with more illustrative ones * Made summary senteces for the trait methods use third person singular * Moved some explanations from Examples section to main explanation * Switched around argument order for the vector-scalar multiplication example such that the vector is on the left side (as it would be expected if one were to switch from `*` to `*=`) * Replaced mostly redundant example introductions with headings in traits with more than one example (where it made sense) * Cleaned up some examples to derive `PartialEq` instead of implementing it manually when that wasn't needed * Removed explicit `fn main()`s in examples where they weren't necessary * Rephrased some things * Added some missing periods * Fixed some formatting/punctuation in examples --- src/libcore/ops/arith.rs | 300 +++++++++++++++------------------------ 1 file changed, 118 insertions(+), 182 deletions(-) diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index d898f9146cd1..97fd8651b047 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -10,15 +10,20 @@ /// The addition operator `+`. /// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [`std::time::SystemTime`] implements `Add`, which permits +/// operations of the form `SystemTime = SystemTime + Duration`. +/// +/// [`std::time::SystemTime`]: ../../std/time/struct.SystemTime.html +/// /// # Examples /// -/// This example creates a `Point` struct that implements the `Add` trait, and -/// then demonstrates adding two `Point`s. +/// ## `Add`able points /// /// ``` /// use std::ops::Add; /// -/// #[derive(Debug)] +/// #[derive(Debug, PartialEq)] /// struct Point { /// x: i32, /// y: i32, @@ -35,31 +40,25 @@ /// } /// } /// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, -/// Point { x: 3, y: 3 }); -/// } +/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, +/// Point { x: 3, y: 3 }); /// ``` /// +/// ## Implementing `Add` with generics +/// /// Here is an example of the same `Point` struct implementing the `Add` trait /// using generics. /// /// ``` /// use std::ops::Add; /// -/// #[derive(Debug)] +/// #[derive(Debug, PartialEq)] /// struct Point { /// x: T, /// y: T, /// } /// -/// // Notice that the implementation uses the `Output` associated type +/// // Notice that the implementation uses the associated type `Output`. /// impl> Add for Point { /// type Output = Point; /// @@ -71,32 +70,18 @@ /// } /// } /// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, -/// Point { x: 3, y: 3 }); -/// } +/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, +/// Point { x: 3, y: 3 }); /// ``` -/// -/// Note that `RHS = Self` by default, but this is not mandatory. For example, -/// [std::time::SystemTime] implements `Add`, which permits -/// operations of the form `SystemTime = SystemTime + Duration`. -/// -/// [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 + /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `+` operator + /// Performs the `+` operation. #[stable(feature = "rust1", since = "1.0.0")] fn add(self, rhs: RHS) -> Self::Output; } @@ -120,15 +105,20 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The subtraction operator `-`. /// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [std::time::SystemTime] implements `Sub`, which permits +/// operations of the form `SystemTime = SystemTime - Duration`. +/// +/// [`std::time::SystemTime`]: ../../std/time/struct.SystemTime.html +/// /// # Examples /// -/// This example creates a `Point` struct that implements the `Sub` trait, and -/// then demonstrates subtracting two `Point`s. +/// ## `Sub`tractable points /// /// ``` /// use std::ops::Sub; /// -/// #[derive(Debug)] +/// #[derive(Debug, PartialEq)] /// struct Point { /// x: i32, /// y: i32, @@ -145,31 +135,25 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// } /// } /// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Point { x: 3, y: 3 } - Point { x: 2, y: 3 }, -/// Point { x: 1, y: 0 }); -/// } +/// assert_eq!(Point { x: 3, y: 3 } - Point { x: 2, y: 3 }, +/// Point { x: 1, y: 0 }); /// ``` /// +/// ## Implementing `Sub` with generics +/// /// Here is an example of the same `Point` struct implementing the `Sub` trait /// using generics. /// /// ``` /// use std::ops::Sub; /// -/// #[derive(Debug)] +/// #[derive(Debug, PartialEq)] /// struct Point { /// x: T, /// y: T, /// } /// -/// // Notice that the implementation uses the `Output` associated type +/// // Notice that the implementation uses the associated type `Output`. /// impl> Sub for Point { /// type Output = Point; /// @@ -181,32 +165,18 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// } /// } /// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Point { x: 2, y: 3 } - Point { x: 1, y: 0 }, -/// Point { x: 1, y: 3 }); -/// } +/// assert_eq!(Point { x: 2, y: 3 } - Point { x: 1, y: 0 }, +/// Point { x: 1, y: 3 }); /// ``` -/// -/// Note that `RHS = Self` by default, but this is not mandatory. For example, -/// [std::time::SystemTime] implements `Sub`, which permits -/// operations of the form `SystemTime = SystemTime - Duration`. -/// -/// [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 + /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `-` operator + /// Performs the `-` operation. #[stable(feature = "rust1", since = "1.0.0")] fn sub(self, rhs: RHS) -> Self::Output; } @@ -230,17 +200,19 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The multiplication operator `*`. /// +/// Note that `RHS = Self` by default, but this is not mandatory. +/// /// # Examples /// -/// Implementing a `Mul`tipliable rational number struct: +/// ## `Mul`tipliable rational numbers /// /// ``` /// use std::ops::Mul; /// -/// // The uniqueness of rational numbers in lowest terms is a consequence of -/// // the fundamental theorem of arithmetic. -/// #[derive(Eq)] -/// #[derive(PartialEq, Debug)] +/// // By the fundamental theorem of arithmetic, rational numbers in lowest +/// // terms are unique. So, by keeping `Rational`s in reduced form, we can +/// // derive `Eq` and `PartialEq`. +/// #[derive(Debug, Eq, PartialEq)] /// struct Rational { /// nominator: usize, /// denominator: usize, @@ -291,45 +263,37 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// Rational::new(1, 2)); /// ``` /// -/// Note that `RHS = Self` by default, but this is not mandatory. Here is an -/// implementation which enables multiplication of vectors by scalars, as is -/// done in linear algebra. +/// ## Multiplying vectors by scalars as in linear algebra /// /// ``` /// use std::ops::Mul; /// -/// struct Scalar {value: usize}; +/// struct Scalar { value: usize } /// -/// #[derive(Debug)] -/// struct Vector {value: Vec}; +/// #[derive(Debug, PartialEq)] +/// struct Vector { value: Vec } /// -/// impl Mul for Scalar { +/// impl Mul for Vector { /// type Output = Vector; /// -/// fn mul(self, rhs: Vector) -> Vector { -/// Vector {value: rhs.value.iter().map(|v| self.value * v).collect()} +/// fn mul(self, rhs: Scalar) -> Vector { +/// Vector { value: self.value.iter().map(|v| v * rhs.value).collect() } /// } /// } /// -/// impl PartialEq for Vector { -/// fn eq(&self, other: &Self) -> bool { -/// self.value == other.value -/// } -/// } -/// -/// let scalar = Scalar{value: 3}; -/// let vector = Vector{value: vec![2, 4, 6]}; -/// assert_eq!(scalar * vector, Vector{value: vec![6, 12, 18]}); +/// let vector = Vector { value: vec![2, 4, 6] }; +/// let scalar = Scalar { value: 3 }; +/// assert_eq!(vector * scalar, Vector { value: vec![6, 12, 18] }); /// ``` #[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 + /// The resulting type after applying the `*` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `*` operator + /// Performs the `*` operation. #[stable(feature = "rust1", since = "1.0.0")] fn mul(self, rhs: RHS) -> Self::Output; } @@ -353,17 +317,19 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The division operator `/`. /// +/// Note that `RHS = Self` by default, but this is not mandatory. +/// /// # Examples /// -/// Implementing a `Div`idable rational number struct: +/// ## `Div`idable rational numbers /// /// ``` /// use std::ops::Div; /// -/// // The uniqueness of rational numbers in lowest terms is a consequence of -/// // the fundamental theorem of arithmetic. -/// #[derive(Eq)] -/// #[derive(PartialEq, Debug)] +/// // By the fundamental theorem of arithmetic, rational numbers in lowest +/// // terms are unique. So, by keeping `Rational`s in reduced form, we can +/// // derive `Eq` and `PartialEq`. +/// #[derive(Debug, Eq, PartialEq)] /// struct Rational { /// nominator: usize, /// denominator: usize, @@ -413,52 +379,42 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// x /// } /// -/// fn main() { -/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); -/// assert_eq!(Rational::new(1, 2) / Rational::new(3, 4), -/// Rational::new(2, 3)); -/// } +/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); +/// assert_eq!(Rational::new(1, 2) / Rational::new(3, 4), +/// Rational::new(2, 3)); /// ``` /// -/// Note that `RHS = Self` by default, but this is not mandatory. Here is an -/// implementation which enables division of vectors by scalars, as is done in -/// linear algebra. +/// ## Dividing vectors by scalars as in linear algebra /// /// ``` /// use std::ops::Div; /// -/// struct Scalar {value: f32}; +/// struct Scalar { value: f32 } /// -/// #[derive(Debug)] -/// struct Vector {value: Vec}; +/// #[derive(Debug, PartialEq)] +/// struct Vector { value: Vec } /// /// impl Div for Vector { /// type Output = Vector; /// /// fn div(self, rhs: Scalar) -> Vector { -/// Vector {value: self.value.iter().map(|v| v / rhs.value).collect()} +/// Vector { value: self.value.iter().map(|v| v / rhs.value).collect() } /// } /// } /// -/// impl PartialEq for Vector { -/// fn eq(&self, other: &Self) -> bool { -/// self.value == other.value -/// } -/// } -/// -/// let scalar = Scalar{value: 2f32}; -/// let vector = Vector{value: vec![2f32, 4f32, 6f32]}; -/// assert_eq!(vector / scalar, Vector{value: vec![1f32, 2f32, 3f32]}); +/// let scalar = Scalar { value: 2f32 }; +/// let vector = Vector { value: vec![2f32, 4f32, 6f32] }; +/// assert_eq!(vector / scalar, Vector { value: vec![1f32, 2f32, 3f32] }); /// ``` #[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 + /// The resulting type after applying the `/` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `/` operator + /// Performs the `/` operation. #[stable(feature = "rust1", since = "1.0.0")] fn div(self, rhs: RHS) -> Self::Output; } @@ -526,7 +482,7 @@ div_impl_float! { f32 f64 } /// } /// /// // If we were to divide &[0, 1, 2, 3, 4, 5, 6, 7] into slices of size 3, -/// // the remainder would be &[6, 7] +/// // the remainder would be &[6, 7]. /// assert_eq!(SplitSlice { slice: &[0, 1, 2, 3, 4, 5, 6, 7] } % 3, /// SplitSlice { slice: &[6, 7] }); /// ``` @@ -534,11 +490,11 @@ div_impl_float! { f32 f64 } #[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 + /// The resulting type after applying the `%` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output = Self; - /// The method for the `%` operator + /// Performs the `%` operation. #[stable(feature = "rust1", since = "1.0.0")] fn rem(self, rhs: RHS) -> Self::Output; } @@ -607,21 +563,21 @@ rem_impl_float! { f32 f64 } /// } /// } /// -/// // a negative positive is a negative +/// // A negative positive is a negative. /// assert_eq!(-Sign::Positive, Sign::Negative); -/// // a double negative is a positive +/// // A double negative is a positive. /// assert_eq!(-Sign::Negative, Sign::Positive); -/// // zero is its own negation +/// // Zero is its own negation. /// assert_eq!(-Sign::Zero, Sign::Zero); /// ``` #[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Neg { - /// The resulting type after applying the `-` operator + /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the unary `-` operator + /// Performs the unary `-` operation. #[stable(feature = "rust1", since = "1.0.0")] fn neg(self) -> Self::Output; } @@ -668,7 +624,7 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } /// ``` /// use std::ops::AddAssign; /// -/// #[derive(Debug)] +/// #[derive(Debug, PartialEq)] /// struct Point { /// x: i32, /// y: i32, @@ -683,12 +639,6 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } /// } /// } /// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// /// let mut point = Point { x: 1, y: 0 }; /// point += Point { x: 2, y: 3 }; /// assert_eq!(point, Point { x: 3, y: 3 }); @@ -697,7 +647,7 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } #[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 + /// Performs the `+=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn add_assign(&mut self, rhs: Rhs); } @@ -725,7 +675,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` /// use std::ops::SubAssign; /// -/// #[derive(Debug)] +/// #[derive(Debug, PartialEq)] /// struct Point { /// x: i32, /// y: i32, @@ -740,12 +690,6 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// } /// } /// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// /// let mut point = Point { x: 3, y: 3 }; /// point -= Point { x: 2, y: 3 }; /// assert_eq!(point, Point {x: 1, y: 0}); @@ -754,7 +698,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"] pub trait SubAssign { - /// The method for the `-=` operator + /// Performs the `-=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn sub_assign(&mut self, rhs: Rhs); } @@ -776,31 +720,27 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `MulAssign`. When `Foo *= Foo` happens, it ends up -/// calling `mul_assign`, and therefore, `main` prints `Multiplying!`. -/// /// ``` /// use std::ops::MulAssign; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Frequency { hertz: f64 } /// -/// impl MulAssign for Foo { -/// fn mul_assign(&mut self, _rhs: Foo) { -/// println!("Multiplying!"); +/// impl MulAssign for Frequency { +/// fn mul_assign(&mut self, rhs: f64) { +/// self.hertz *= rhs; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo *= Foo; -/// } +/// let mut frequency = Frequency { hertz: 50.0 }; +/// frequency *= 4.0; +/// assert_eq!(Frequency { hertz: 200.0 }, frequency); /// ``` #[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 + /// Performs the `*=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn mul_assign(&mut self, rhs: Rhs); } @@ -822,31 +762,27 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `DivAssign`. When `Foo /= Foo` happens, it ends up -/// calling `div_assign`, and therefore, `main` prints `Dividing!`. -/// /// ``` /// use std::ops::DivAssign; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Frequency { hertz: f64 } /// -/// impl DivAssign for Foo { -/// fn div_assign(&mut self, _rhs: Foo) { -/// println!("Dividing!"); +/// impl DivAssign for Frequency { +/// fn div_assign(&mut self, rhs: f64) { +/// self.hertz /= rhs; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo /= Foo; -/// } +/// let mut frequency = Frequency { hertz: 200.0 }; +/// frequency /= 4.0; +/// assert_eq!(Frequency { hertz: 50.0 }, frequency); /// ``` #[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 + /// Performs the `/=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn div_assign(&mut self, rhs: Rhs); } @@ -867,31 +803,31 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// /// # Examples /// -/// A trivial implementation of `RemAssign`. When `Foo %= Foo` happens, it ends up -/// calling `rem_assign`, and therefore, `main` prints `Remainder-ing!`. -/// /// ``` /// use std::ops::RemAssign; /// -/// struct Foo; +/// struct CookieJar { cookies: u32 } /// -/// impl RemAssign for Foo { -/// fn rem_assign(&mut self, _rhs: Foo) { -/// println!("Remainder-ing!"); +/// impl RemAssign for CookieJar { +/// fn rem_assign(&mut self, piles: u32) { +/// self.cookies %= piles; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo %= Foo; -/// } +/// let mut jar = CookieJar { cookies: 31 }; +/// let piles = 4; +/// +/// println!("Splitting up {} cookies into {} even piles!", jar.cookies, piles); +/// +/// jar %= piles; +/// +/// println!("{} cookies remain in the cookie jar!", jar.cookies); /// ``` #[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 + /// Performs the `%=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn rem_assign(&mut self, rhs: Rhs); } From f2ff646f5f71fd89b19ec11d7bb03128156f1af9 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 13:49:11 +0200 Subject: [PATCH 04/88] Revise documentation in core::ops::bit Part of #29365. * Added "real" examples for `BitOrAssign`, `BitXorAssign`, `ShlAssign`, and `ShrAssign` * Rewrote method summary senteces to be in 3rd person singular * Rephrased example introductions to be less redundant ("in this example" etc.) and to not use "trivial" * Removed superfluous explicit `fn main()`s in examples * Added some missing periods --- src/libcore/ops/bit.rs | 272 ++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 150 deletions(-) diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index 8743be3557cc..e6fadf616b02 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -41,11 +41,11 @@ #[lang = "not"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Not { - /// The resulting type after applying the `!` operator + /// The resulting type after applying the `!` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the unary `!` operator + /// Performs the unary `!` operation. #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; } @@ -70,7 +70,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// # Examples /// -/// In this example, the `&` operator is lifted to a trivial `Scalar` type. +/// An implementation of `BitAnd` for a wrapper around `bool`. /// /// ``` /// use std::ops::BitAnd; @@ -87,16 +87,13 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// } /// } /// -/// fn main() { -/// assert_eq!(Scalar(true) & Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(true) & Scalar(false), Scalar(false)); -/// assert_eq!(Scalar(false) & Scalar(true), Scalar(false)); -/// assert_eq!(Scalar(false) & Scalar(false), Scalar(false)); -/// } +/// assert_eq!(Scalar(true) & Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(true) & Scalar(false), Scalar(false)); +/// assert_eq!(Scalar(false) & Scalar(true), Scalar(false)); +/// assert_eq!(Scalar(false) & Scalar(false), Scalar(false)); /// ``` /// -/// In this example, the `BitAnd` trait is implemented for a `BooleanVector` -/// struct. +/// An implementation of `BitAnd` for a wrapper around `Vec`. /// /// ``` /// use std::ops::BitAnd; @@ -114,22 +111,20 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// } /// } /// -/// fn main() { -/// let bv1 = BooleanVector(vec![true, true, false, false]); -/// let bv2 = BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![true, false, false, false]); -/// assert_eq!(bv1 & bv2, expected); -/// } +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, false, false, false]); +/// assert_eq!(bv1 & bv2, expected); /// ``` #[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 + /// The resulting type after applying the `&` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `&` operator + /// Performs the `&` operation. #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: RHS) -> Self::Output; } @@ -154,7 +149,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// # Examples /// -/// In this example, the `|` operator is lifted to a trivial `Scalar` type. +/// An implementation of `BitOr` for a wrapper around `bool`. /// /// ``` /// use std::ops::BitOr; @@ -171,16 +166,13 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// } /// } /// -/// fn main() { -/// assert_eq!(Scalar(true) | Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(true) | Scalar(false), Scalar(true)); -/// assert_eq!(Scalar(false) | Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(false) | Scalar(false), Scalar(false)); -/// } +/// assert_eq!(Scalar(true) | Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(true) | Scalar(false), Scalar(true)); +/// assert_eq!(Scalar(false) | Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(false) | Scalar(false), Scalar(false)); /// ``` /// -/// In this example, the `BitOr` trait is implemented for a `BooleanVector` -/// struct. +/// An implementation of `BitOr` for a wrapper around `Vec`. /// /// ``` /// use std::ops::BitOr; @@ -198,22 +190,20 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// } /// } /// -/// fn main() { -/// let bv1 = BooleanVector(vec![true, true, false, false]); -/// let bv2 = BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![true, true, true, false]); -/// assert_eq!(bv1 | bv2, expected); -/// } +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, true, true, false]); +/// assert_eq!(bv1 | bv2, expected); /// ``` #[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 + /// The resulting type after applying the `|` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `|` operator + /// Performs the `|` operation. #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: RHS) -> Self::Output; } @@ -238,7 +228,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// # Examples /// -/// In this example, the `^` operator is lifted to a trivial `Scalar` type. +/// An implementation of `BitXor` that lifts `^` to a wrapper around `bool`. /// /// ``` /// use std::ops::BitXor; @@ -255,16 +245,13 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// } /// } /// -/// fn main() { -/// assert_eq!(Scalar(true) ^ Scalar(true), Scalar(false)); -/// assert_eq!(Scalar(true) ^ Scalar(false), Scalar(true)); -/// assert_eq!(Scalar(false) ^ Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(false) ^ Scalar(false), Scalar(false)); -/// } +/// assert_eq!(Scalar(true) ^ Scalar(true), Scalar(false)); +/// assert_eq!(Scalar(true) ^ Scalar(false), Scalar(true)); +/// assert_eq!(Scalar(false) ^ Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(false) ^ Scalar(false), Scalar(false)); /// ``` /// -/// In this example, the `BitXor` trait is implemented for a `BooleanVector` -/// struct. +/// An implementation of `BitXor` trait for a wrapper around `Vec`. /// /// ``` /// use std::ops::BitXor; @@ -285,22 +272,20 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// } /// } /// -/// fn main() { -/// let bv1 = BooleanVector(vec![true, true, false, false]); -/// let bv2 = BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![false, true, true, false]); -/// assert_eq!(bv1 ^ bv2, expected); -/// } +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![false, true, true, false]); +/// assert_eq!(bv1 ^ bv2, expected); /// ``` #[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 + /// The resulting type after applying the `^` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `^` operator + /// Performs the `^` operation. #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: RHS) -> Self::Output; } @@ -326,7 +311,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// # Examples /// /// An implementation of `Shl` that lifts the `<<` operation on integers to a -/// `Scalar` struct. +/// wrapper around `usize`. /// /// ``` /// use std::ops::Shl; @@ -342,9 +327,8 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// Scalar(lhs << rhs) /// } /// } -/// fn main() { -/// assert_eq!(Scalar(4) << Scalar(2), Scalar(16)); -/// } +/// +/// assert_eq!(Scalar(4) << Scalar(2), Scalar(16)); /// ``` /// /// An implementation of `Shl` that spins a vector leftward by a given amount. @@ -361,7 +345,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// type Output = Self; /// /// fn shl(self, rhs: usize) -> SpinVector { -/// // rotate the vector by `rhs` places +/// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(rhs); /// let mut spun_vector: Vec = vec![]; /// spun_vector.extend_from_slice(b); @@ -370,20 +354,18 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// } /// } /// -/// fn main() { -/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } << 2, -/// SpinVector { vec: vec![2, 3, 4, 0, 1] }); -/// } +/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } << 2, +/// SpinVector { vec: vec![2, 3, 4, 0, 1] }); /// ``` #[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 + /// The resulting type after applying the `<<` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `<<` operator + /// Performs the `<<` operation. #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: RHS) -> Self::Output; } @@ -430,7 +412,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// # Examples /// /// An implementation of `Shr` that lifts the `>>` operation on integers to a -/// `Scalar` struct. +/// wrapper around `usize`. /// /// ``` /// use std::ops::Shr; @@ -446,9 +428,8 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// Scalar(lhs >> rhs) /// } /// } -/// fn main() { -/// assert_eq!(Scalar(16) >> Scalar(2), Scalar(4)); -/// } +/// +/// assert_eq!(Scalar(16) >> Scalar(2), Scalar(4)); /// ``` /// /// An implementation of `Shr` that spins a vector rightward by a given amount. @@ -465,7 +446,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// type Output = Self; /// /// fn shr(self, rhs: usize) -> SpinVector { -/// // rotate the vector by `rhs` places +/// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(self.vec.len() - rhs); /// let mut spun_vector: Vec = vec![]; /// spun_vector.extend_from_slice(b); @@ -474,20 +455,18 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// } /// } /// -/// fn main() { -/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } >> 2, -/// SpinVector { vec: vec![3, 4, 0, 1, 2] }); -/// } +/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } >> 2, +/// SpinVector { vec: vec![3, 4, 0, 1, 2] }); /// ``` #[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 + /// The resulting type after applying the `>>` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; - /// The method for the `>>` operator + /// Performs the `>>` operation. #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: RHS) -> Self::Output; } @@ -533,7 +512,8 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// /// # Examples /// -/// In this example, the `&=` operator is lifted to a trivial `Scalar` type. +/// An implementation of `BitAndAssign` that lifts the `&=` operator to a +/// wrapper around `bool`. /// /// ``` /// use std::ops::BitAndAssign; @@ -548,27 +528,25 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// } /// } /// -/// fn main() { -/// let mut scalar = Scalar(true); -/// scalar &= Scalar(true); -/// assert_eq!(scalar, Scalar(true)); +/// let mut scalar = Scalar(true); +/// scalar &= Scalar(true); +/// assert_eq!(scalar, Scalar(true)); /// -/// let mut scalar = Scalar(true); -/// scalar &= Scalar(false); -/// assert_eq!(scalar, Scalar(false)); +/// let mut scalar = Scalar(true); +/// scalar &= Scalar(false); +/// assert_eq!(scalar, Scalar(false)); /// -/// let mut scalar = Scalar(false); -/// scalar &= Scalar(true); -/// assert_eq!(scalar, Scalar(false)); +/// let mut scalar = Scalar(false); +/// scalar &= Scalar(true); +/// assert_eq!(scalar, Scalar(false)); /// -/// let mut scalar = Scalar(false); -/// scalar &= Scalar(false); -/// assert_eq!(scalar, Scalar(false)); -/// } +/// let mut scalar = Scalar(false); +/// scalar &= Scalar(false); +/// assert_eq!(scalar, Scalar(false)); /// ``` /// -/// In this example, the `BitAndAssign` trait is implemented for a -/// `BooleanVector` struct. +/// Here, the `BitAndAssign` trait is implemented for a wrapper around +/// `Vec`. /// /// ``` /// use std::ops::BitAndAssign; @@ -577,7 +555,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// struct BooleanVector(Vec); /// /// impl BitAndAssign for BooleanVector { -/// // rhs is the "right-hand side" of the expression `a &= b` +/// // `rhs` is the "right-hand side" of the expression `a &= b`. /// fn bitand_assign(&mut self, rhs: Self) { /// assert_eq!(self.0.len(), rhs.0.len()); /// *self = BooleanVector(self.0 @@ -588,18 +566,16 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// } /// } /// -/// fn main() { -/// let mut bv = BooleanVector(vec![true, true, false, false]); -/// bv &= BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![true, false, false, false]); -/// assert_eq!(bv, expected); -/// } +/// let mut bv = BooleanVector(vec![true, true, false, false]); +/// bv &= BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, false, false, false]); +/// assert_eq!(bv, expected); /// ``` #[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 + /// Performs the `&=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitand_assign(&mut self, rhs: Rhs); } @@ -620,31 +596,31 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// # Examples /// -/// A trivial implementation of `BitOrAssign`. When `Foo |= Foo` happens, it ends up -/// calling `bitor_assign`, and therefore, `main` prints `Bitwise Or-ing!`. -/// /// ``` /// use std::ops::BitOrAssign; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct PersonalPreferences { +/// likes_cats: bool, +/// likes_dogs: bool, +/// } /// -/// impl BitOrAssign for Foo { -/// fn bitor_assign(&mut self, _rhs: Foo) { -/// println!("Bitwise Or-ing!"); +/// impl BitOrAssign for PersonalPreferences { +/// fn bitor_assign(&mut self, rhs: Self) { +/// self.likes_cats |= rhs.likes_cats; +/// self.likes_dogs |= rhs.likes_dogs; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo |= Foo; -/// } +/// let mut prefs = PersonalPreferences { likes_cats: true, likes_dogs: false }; +/// prefs |= PersonalPreferences { likes_cats: false, likes_dogs: true }; +/// assert_eq!(prefs, PersonalPreferences { likes_cats: true, likes_dogs: true }); /// ``` #[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 + /// Performs the `|=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitor_assign(&mut self, rhs: Rhs); } @@ -665,31 +641,31 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// # Examples /// -/// A trivial implementation of `BitXorAssign`. When `Foo ^= Foo` happens, it ends up -/// calling `bitxor_assign`, and therefore, `main` prints `Bitwise Xor-ing!`. -/// /// ``` /// use std::ops::BitXorAssign; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Personality { +/// has_soul: bool, +/// likes_knitting: bool, +/// } /// -/// impl BitXorAssign for Foo { -/// fn bitxor_assign(&mut self, _rhs: Foo) { -/// println!("Bitwise Xor-ing!"); +/// impl BitXorAssign for Personality { +/// fn bitxor_assign(&mut self, rhs: Self) { +/// self.has_soul ^= rhs.has_soul; +/// self.likes_knitting ^= rhs.likes_knitting; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo ^= Foo; -/// } +/// let mut personality = Personality { has_soul: false, likes_knitting: true }; +/// personality ^= Personality { has_soul: true, likes_knitting: true }; +/// assert_eq!(personality, Personality { has_soul: true, likes_knitting: false}); /// ``` #[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 + /// Performs the `^=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitxor_assign(&mut self, rhs: Rhs); } @@ -710,31 +686,29 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// # Examples /// -/// A trivial implementation of `ShlAssign`. When `Foo <<= Foo` happens, it ends up -/// calling `shl_assign`, and therefore, `main` prints `Shifting left!`. +/// An implementation of `ShlAssign` for a wrapper around `usize`. /// /// ``` /// use std::ops::ShlAssign; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Scalar(usize); /// -/// impl ShlAssign for Foo { -/// fn shl_assign(&mut self, _rhs: Foo) { -/// println!("Shifting left!"); +/// impl ShlAssign for Scalar { +/// fn shl_assign(&mut self, rhs: usize) { +/// self.0 <<= rhs; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo <<= Foo; -/// } +/// let mut scalar = Scalar(4); +/// scalar <<= 2; +/// assert_eq!(scalar, Scalar(16)); /// ``` #[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 + /// Performs the `<<=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shl_assign(&mut self, rhs: Rhs); } @@ -776,31 +750,29 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// /// # Examples /// -/// A trivial implementation of `ShrAssign`. When `Foo >>= Foo` happens, it ends up -/// calling `shr_assign`, and therefore, `main` prints `Shifting right!`. +/// An implementation of `ShrAssign` for a wrapper around `usize`. /// /// ``` /// use std::ops::ShrAssign; /// -/// struct Foo; +/// #[derive(Debug, PartialEq)] +/// struct Scalar(usize); /// -/// impl ShrAssign for Foo { -/// fn shr_assign(&mut self, _rhs: Foo) { -/// println!("Shifting right!"); +/// impl ShrAssign for Scalar { +/// fn shr_assign(&mut self, rhs: usize) { +/// self.0 >>= rhs; /// } /// } /// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo >>= Foo; -/// } +/// let mut scalar = Scalar(16); +/// scalar >>= 2; +/// assert_eq!(scalar, Scalar(4)); /// ``` #[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 + /// Performs the `>>=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shr_assign(&mut self, rhs: Rhs); } From 5990be523d00edaf69cfd6d3e28d9fb78eb67bcd Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 17:09:43 +0200 Subject: [PATCH 05/88] Expand docs on `Deref` and `DerefMut` Part of #29365. * Expanded the explanaition sections, adapting some parts from the book, the reference, as well as the API guidelines. As such, the docs now explicitly state that `Deref` and `DerefMut` should only be implemented for smart pointers and that they should not fail. Additionally, there is now a short primer on `Deref` coercion. * Added links to `DerefMut` from `Deref` and vice versa * Added links to relevant reference sections * Removed "stuttering" in summary sentences * Changed summary sentences of `Deref::deref` and `Deref::deref_mut` to be in 3rd person singular * Removed explicit uses of `fn main()` in the examples --- src/libcore/ops/deref.rs | 98 +++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 18cf20ac411d..ac5ff1556f4d 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -8,16 +8,44 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// The `Deref` trait is used to specify the functionality of dereferencing -/// operations, like `*v`. +/// Used for immutable dereferencing operations, like `*v`. /// -/// `Deref` also enables ['`Deref` coercions'][coercions]. +/// In addition to being used for explicit dereferencing operations with the +/// (unary) `*` operator in immutable contexts, `Deref` is also used implicitly +/// by the compiler in many circumstances. This mechanism is called +/// ['`Deref` coercion'][more]. In mutable contexts, [`DerefMut`] is used. /// -/// [coercions]: ../../book/first-edition/deref-coercions.html +/// Implementing `Deref` for smart pointers makes accessing the data behind them +/// convenient, which is why they implement `Deref`. On the other hand, the +/// rules regarding `Deref` and [`DerefMut`] were designed specifically to +/// accomodate smart pointers. Because of this, **`Deref` should only be +/// implemented for smart pointers** to avoid confusion. +/// +/// For similar reasons, **this trait should never fail**. Failure during +/// dereferencing can be extremely confusing when `Deref` is invoked implicitly. +/// +/// # More on `Deref` coercion +/// +/// If `T` implements `Deref`, and `x` is a value of type `T`, then: +/// * In immutable contexts, `*x` on non-pointer types is equivalent to +/// `*Deref::deref(&x)`. +/// * Values of type `&T` are coerced to values of type `&U` +/// * `T` implicitly implements all the (immutable) methods of the type `U`. +/// +/// For more details, visit [the chapter in *The Rust Programming Language*] +/// [book] as well as the reference sections on [the dereference operator] +/// [ref-deref-op], [the `Deref` trait][ref-deref-trait], and [type coercions]. +/// +/// [book]: ../../book/second-edition/ch15-02-deref.html +/// [`DerefMut`]: trait.DerefMut.html +/// [more]: #more-on-deref-coercion +/// [ref-deref-op]: ../../reference/expressions.html#the-dereference-operator +/// [ref-deref-trait]: ../../reference/the-deref-trait.html +/// [type coercions]: ../../reference/type-coercions.html /// /// # Examples /// -/// A struct with a single field which is accessible via dereferencing the +/// A struct with a single field which is accessible by dereferencing the /// struct. /// /// ``` @@ -35,19 +63,17 @@ /// } /// } /// -/// fn main() { -/// let x = DerefExample { value: 'a' }; -/// assert_eq!('a', *x); -/// } +/// let x = DerefExample { value: 'a' }; +/// assert_eq!('a', *x); /// ``` #[lang = "deref"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Deref { - /// The resulting type after dereferencing + /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] type Target: ?Sized; - /// The method called to dereference a value + /// Dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] fn deref(&self) -> &Self::Target; } @@ -66,16 +92,46 @@ impl<'a, T: ?Sized> Deref for &'a mut T { fn deref(&self) -> &T { *self } } -/// The `DerefMut` trait is used to specify the functionality of dereferencing -/// mutably like `*v = 1;` +/// Used for mutable dereferencing operations, like in `*v = 1;`. /// -/// `DerefMut` also enables ['`Deref` coercions'][coercions]. +/// In addition to being used for explicit dereferencing operations with the +/// (unary) `*` operator in mutable contexts, `DerefMut` is also used implicitly +/// by the compiler in many circumstances. This mechanism is called +/// ['`Deref` coercion'][more]. In immutable contexts, [`Deref`] is used. /// -/// [coercions]: ../../book/first-edition/deref-coercions.html +/// Implementing `DerefMut` for smart pointers makes mutating the data behind +/// them convenient, which is why they implement `DerefMut`. On the other hand, +/// the rules regarding [`Deref`] and `DerefMut` were designed specifically to +/// accomodate smart pointers. Because of this, **`DerefMut` should only be +/// implemented for smart pointers** to avoid confusion. +/// +/// For similar reasons, **this trait should never fail**. Failure during +/// dereferencing can be extremely confusing when `DerefMut` is invoked +/// implicitly. +/// +/// # More on `Deref` coercion +/// +/// If `T` implements `MutDeref`, and `x` is a value of type `T`, +/// then: +/// * In mutable contexts, `*x` on non-pointer types is equivalent to +/// `*Deref::deref(&x)`. +/// * Values of type `&mut T` are coerced to values of type `&mut U` +/// * `T` implicitly implements all the (mutable) methods of the type `U`. +/// +/// For more details, visit [the chapter in *The Rust Programming Language*] +/// [book] as well as the reference sections on [the dereference operator] +/// [ref-deref-op], [the `Deref` trait][ref-deref-trait], and [type coercions]. +/// +/// [book]: ../../book/second-edition/ch15-02-deref.html +/// [`Deref`]: trait.Deref.html +/// [more]: #more-on-deref-coercion +/// [ref-deref-op]: ../../reference/expressions.html#the-dereference-operator +/// [ref-deref-trait]: ../../reference/the-deref-trait.html +/// [type coercions]: ../../reference/type-coercions.html /// /// # Examples /// -/// A struct with a single field which is modifiable via dereferencing the +/// A struct with a single field which is modifiable by dereferencing the /// struct. /// /// ``` @@ -99,16 +155,14 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// } /// } /// -/// fn main() { -/// let mut x = DerefMutExample { value: 'a' }; -/// *x = 'b'; -/// assert_eq!('b', *x); -/// } +/// let mut x = DerefMutExample { value: 'a' }; +/// *x = 'b'; +/// assert_eq!('b', *x); /// ``` #[lang = "deref_mut"] #[stable(feature = "rust1", since = "1.0.0")] pub trait DerefMut: Deref { - /// The method called to mutably dereference a value + /// Mutably dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] fn deref_mut(&mut self) -> &mut Self::Target; } From 4b945fd9fe9bc168e385532af1d2b7b30edef1cb Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 19:32:34 +0200 Subject: [PATCH 06/88] Revise `Drop` docs Part of #29365. * Removed "stuttering" in summary sentence. * Copy-edited the explanaition sections * Added sub-headings in Examples section to aid linking * Actually implement `Drop` in the `PrintOnDrop` exampl * Add link to Drop chapter in TRPL * Changed `drop` summary sentence to be in 3rd person singular * Added missing link to `panic!` --- src/libcore/ops/drop.rs | 64 ++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/src/libcore/ops/drop.rs b/src/libcore/ops/drop.rs index 92f3cb256c83..70ab7b2f3b7e 100644 --- a/src/libcore/ops/drop.rs +++ b/src/libcore/ops/drop.rs @@ -8,20 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// The `Drop` trait is used to run some code when a value goes out of scope. +/// Used to run some code when a value goes out of scope. /// This is sometimes called a 'destructor'. /// -/// When a value goes out of scope, if it implements this trait, it will have -/// its `drop` method called. Then any fields the value contains will also +/// When a value goes out of scope, it will have its `drop` method called if +/// its type implements `Drop`. Then, any fields the value contains will also /// be dropped recursively. /// -/// Because of the recursive dropping, you do not need to implement this trait +/// Because of this recursive dropping, you do not need to implement this trait /// unless your type needs its own destructor logic. /// +/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book] +/// for some more elaboration. +/// +/// [book]: ../../book/second-edition/ch15-03-drop.html +/// /// # Examples /// -/// A trivial implementation of `Drop`. The `drop` method is called when `_x` -/// goes out of scope, and therefore `main` prints `Dropping!`. +/// ## Implementing `Drop` +/// +/// The `drop` method is called when `_x` goes out of scope, and therefore +/// `main` prints `Dropping!`. /// /// ``` /// struct HasDrop; @@ -37,9 +44,11 @@ /// } /// ``` /// -/// Showing the recursive nature of `Drop`. When `outer` goes out of scope, the -/// `drop` method will be called first for `Outer`, then for `Inner`. Therefore -/// `main` prints `Dropping Outer!` and then `Dropping Inner!`. +/// ## Dropping is done recursively +/// +/// When `outer` goes out of scope, the `drop` method will be called first for +/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and +/// then `Dropping Inner!`. /// /// ``` /// struct Inner; @@ -62,12 +71,20 @@ /// } /// ``` /// -/// Because variables are dropped in the reverse order they are declared, -/// `main` will print `Declared second!` and then `Declared first!`. +/// ## Variables are dropped in reverse order of declaration +/// +/// `_first` is declared first and `_second` is declared second, so `main` will +/// print `Declared second!` and then `Declared first!`. /// /// ``` /// struct PrintOnDrop(&'static str); /// +/// impl Drop for PrintOnDrop { +/// fn drop(&mut self) { +/// println!("{}", self.0); +/// } +/// } +/// /// fn main() { /// let _first = PrintOnDrop("Declared first!"); /// let _second = PrintOnDrop("Declared second!"); @@ -76,24 +93,25 @@ #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Drop { - /// A method called when the value goes out of scope. + /// Executes the destructor for this type. /// - /// When this method has been called, `self` has not yet been deallocated. - /// If it were, `self` would be a dangling reference. - /// - /// After this function is over, the memory of `self` will be deallocated. - /// - /// This function cannot be called explicitly. This is compiler error - /// [E0040]. However, the [`std::mem::drop`] function in the prelude can be + /// This method is called implilcitly when the value goes out of scope, + /// and cannot be called explicitly (this is compiler error [E0040]). + /// However, the [`std::mem::drop`] function in the prelude can be /// used to call the argument's `Drop` implementation. /// - /// [E0040]: ../../error-index.html#E0040 - /// [`std::mem::drop`]: ../../std/mem/fn.drop.html + /// When this method has been called, `self` has not yet been deallocated. + /// That only happens after the method is over. + /// If this wasn't the case, `self` would be a dangling reference. /// /// # Panics /// - /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in - /// a `drop()` implementation will likely abort. + /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`] + /// in a `drop` implementation will likely abort. + /// + /// [E0040]: ../../error-index.html#E0040 + /// [`panic!`]: ../macro.panic.html + /// [`std::mem::drop`]: ../../std/mem/fn.drop.html #[stable(feature = "rust1", since = "1.0.0")] fn drop(&mut self); } From ffa327b3a44315bc664b726e01c04b13768ebee4 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 19:57:32 +0200 Subject: [PATCH 07/88] Revise `Index` and `IndexMut` docs. Part of #29365. * Shortened summary sentences, removing "stuttering" * Small copyediting * Changed method summary sentences to be in 3rd person singular * Removed extraneous explicit `fn main()` in example for `IndexMut` --- src/libcore/ops/index.rs | 45 +++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index b16b95677874..0652421511aa 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// The `Index` trait is used to specify the functionality of indexing operations -/// like `container[index]` when used in an immutable context. +/// Used for indexing operations (`container[index]`) in immutable contexts. /// /// `container[index]` is actually syntactic sugar for `*container.index(index)`, /// but only when used as an immutable value. If a mutable value is requested, /// [`IndexMut`] is used instead. This allows nice things such as -/// `let value = v[index]` if `value` implements [`Copy`]. +/// `let value = v[index]` if the type of `value` implements [`Copy`]. /// /// [`IndexMut`]: ../../std/ops/trait.IndexMut.html /// [`Copy`]: ../../std/marker/trait.Copy.html @@ -64,22 +63,22 @@ #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Index { - /// The returned type after indexing + /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] type Output: ?Sized; - /// The method for the indexing (`container[index]`) operation + /// Performs the indexing (`container[index]`) operation. #[stable(feature = "rust1", since = "1.0.0")] fn index(&self, index: Idx) -> &Self::Output; } -/// The `IndexMut` trait is used to specify the functionality of indexing -/// operations like `container[index]` when used in a mutable context. +/// Used for indexing operations (`container[index]`) in mutable contexts. /// /// `container[index]` is actually syntactic sugar for /// `*container.index_mut(index)`, but only when used as a mutable value. If /// an immutable value is requested, the [`Index`] trait is used instead. This -/// allows nice things such as `v[index] = value` if `value` implements [`Copy`]. +/// allows nice things such as `v[index] = value` if the type of `value` +/// implements [`Copy`]. /// /// [`Index`]: ../../std/ops/trait.Index.html /// [`Copy`]: ../../std/marker/trait.Copy.html @@ -106,7 +105,7 @@ pub trait Index { /// /// struct Balance { /// pub left: Weight, -/// pub right:Weight, +/// pub right: Weight, /// } /// /// impl Index for Balance { @@ -131,28 +130,26 @@ pub trait Index { /// } /// } /// -/// fn main() { -/// let mut balance = Balance { -/// right: Weight::Kilogram(2.5), -/// left: Weight::Pound(1.5), -/// }; +/// let mut balance = Balance { +/// right: Weight::Kilogram(2.5), +/// left: Weight::Pound(1.5), +/// }; /// -/// // In this case balance[Side::Right] is sugar for -/// // *balance.index(Side::Right), since we are only reading -/// // balance[Side::Right], not writing it. -/// assert_eq!(balance[Side::Right],Weight::Kilogram(2.5)); +/// // In this case, `balance[Side::Right]` is sugar for +/// // `*balance.index(Side::Right)`, since we are only *reading* +/// // `balance[Side::Right]`, not writing it. +/// assert_eq!(balance[Side::Right], Weight::Kilogram(2.5)); /// -/// // However in this case balance[Side::Left] is sugar for -/// // *balance.index_mut(Side::Left), since we are writing -/// // balance[Side::Left]. -/// balance[Side::Left] = Weight::Kilogram(3.0); -/// } +/// // However, in this case `balance[Side::Left]` is sugar for +/// // `*balance.index_mut(Side::Left)`, since we are writing +/// // `balance[Side::Left]`. +/// balance[Side::Left] = Weight::Kilogram(3.0); /// ``` #[lang = "index_mut"] #[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] pub trait IndexMut: Index { - /// The method for the mutable indexing (`container[index]`) operation + /// Performs the mutable indexing (`container[index]`) operation. #[stable(feature = "rust1", since = "1.0.0")] fn index_mut(&mut self, index: Idx) -> &mut Self::Output; } From 5414c856891da94e0389aace71b514c6338343a6 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 21:27:47 +0200 Subject: [PATCH 08/88] Revise `Fn`/`FnMut`/`FnOnce` documentation Part of #29365. * Moved explanations out of Examples section and expanded on them. * Made the super-/subtrait relationships more explicit. * Added links to the other traits, TRPL and the nomicon where appropriate * Changed method summaries to be in 3rd person singular * General copyediting --- src/libcore/ops/function.rs | 95 +++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index 62bf69336a39..5a61e9b68b86 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -10,24 +10,37 @@ /// A version of the call operator that takes an immutable receiver. /// -/// # Examples +/// Closures only taking immutable references to captured variables +/// automatically implement this trait, which allows them to be invoked. +/// For mutably referenced captures, see [`FnMut`], and for consuming the +/// capture, see [`FnOnce`]. /// -/// Closures automatically implement this trait, which allows them to be -/// invoked. Note, however, that `Fn` takes an immutable reference to any -/// captured variables. To take a mutable capture, implement [`FnMut`], and to -/// consume the capture, implement [`FnOnce`]. +/// You can use the [`Fn`] traits when you want to accept a closure as a +/// parameter. Since both [`FnMut`] and [`FnOnce`] are supertraits of `Fn`, any +/// instance of `Fn` can be used where a [`FnMut`] or [`FnOnce`] is expected. /// +/// See the [chapter on closures in *The Rust Programming Language*][book] for +/// more information about closures in general. +/// +/// Also of note is the special syntax for `Fn` traits (e.g. +/// `Fn(usize, bool) -> usize`). Those interested in the technical details of +/// this can refer to [the relevant section in *The Rustonomicon*][nomicon]. +/// +/// [book]: ../../book/second-edition/ch13-01-closures.html /// [`FnMut`]: trait.FnMut.html /// [`FnOnce`]: trait.FnOnce.html +/// [nomicon]: ../../nomicon/hrtb.html +/// +/// # Examples +/// +/// ## Calling a closure /// /// ``` /// let square = |x| x * x; /// assert_eq!(square(5), 25); /// ``` /// -/// Closures can also be passed to higher-level functions through a `Fn` -/// parameter (or a `FnMut` or `FnOnce` parameter, which are supertraits of -/// `Fn`). +/// ## Using a `Fn` parameter /// /// ``` /// fn call_with_one(func: F) -> usize @@ -43,17 +56,39 @@ #[rustc_paren_sugar] #[fundamental] // so that regex can rely that `&str: !FnMut` pub trait Fn : FnMut { - /// This is called when the call operator is used. + /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] extern "rust-call" fn call(&self, args: Args) -> Self::Output; } /// A version of the call operator that takes a mutable receiver. /// +/// Closures that might mutably reference captured variables automatically +/// implement this trait, which allows them to be invoked. For immutably +/// referenced captures, see [`Fn`], and for consuming the captures, see +/// [`FnOnce`]. +/// +/// You can use the [`Fn`] traits when you want to accept a closure as a +/// parameter. Since [`FnOnce`] is a supertrait of `FnMut`, any instance of +/// `FnMut` can be used where a [`FnOnce`] is expected, and since [`Fn`] is a +/// subtrait of `FnMut`, any instance of [`Fn`] can be used where [`FnMut`] is +/// expected. +/// +/// See the [chapter on closures in *The Rust Programming Language*][book] for +/// more information about closures in general. +/// +/// Also of note is the special syntax for `Fn` traits (e.g. +/// `Fn(usize, bool) -> usize`). Those interested in the technical details of +/// this can refer to [the relevant section in *The Rustonomicon*][nomicon]. +/// +/// [book]: ../../book/second-edition/ch13-01-closures.html +/// [`Fn`]: trait.Fnhtml +/// [`FnOnce`]: trait.FnOnce.html +/// [nomicon]: ../../nomicon/hrtb.html +/// /// # Examples /// -/// Closures that mutably capture variables automatically implement this trait, -/// which allows them to be invoked. +/// ## Calling a mutably capturing closure /// /// ``` /// let mut x = 5; @@ -64,8 +99,7 @@ pub trait Fn : FnMut { /// assert_eq!(x, 25); /// ``` /// -/// Closures can also be passed to higher-level functions through a `FnMut` -/// parameter (or a `FnOnce` parameter, which is a supertrait of `FnMut`). +/// ## Using a `FnMut` parameter /// /// ``` /// fn do_twice(mut func: F) @@ -88,17 +122,37 @@ pub trait Fn : FnMut { #[rustc_paren_sugar] #[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnMut : FnOnce { - /// This is called when the call operator is used. + /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } /// A version of the call operator that takes a by-value receiver. /// +/// Closures that might take ownership of captured variables automatically +/// implement this trait, which allows them to be invoked. For immutably +/// referenced captures, see [`Fn`], and for mutably referenced captures, +/// see [`FnMut`]. +/// +/// You can use the [`Fn`] traits when you want to accept a closure as a +/// parameter. Since both [`Fn`] and [`FnMut`] are subtraits of `FnOnce`, any +/// instance of [`Fn`] or [`FnMut`] can be used where a `FnOnce` is expected. +/// +/// See the [chapter on closures in *The Rust Programming Language*][book] for +/// more information about closures in general. +/// +/// Also of note is the special syntax for `Fn` traits (e.g. +/// `Fn(usize, bool) -> usize`). Those interested in the technical details of +/// this can refer to [the relevant section in *The Rustonomicon*][nomicon]. +/// +/// [book]: ../../book/second-edition/ch13-01-closures.html +/// [`Fn`]: trait.Fn.html +/// [`FnMut`]: trait.FnMut.html +/// [nomicon]: ../../nomicon/hrtb.html +/// /// # Examples /// -/// By-value closures automatically implement this trait, which allows them to -/// be invoked. +/// ## Calling a by-value closure /// /// ``` /// let x = 5; @@ -106,21 +160,20 @@ pub trait FnMut : FnOnce { /// assert_eq!(square_x(), 25); /// ``` /// -/// By-value Closures can also be passed to higher-level functions through a -/// `FnOnce` parameter. +/// ## Using a `FnOnce` parameter /// /// ``` /// fn consume_with_relish(func: F) /// where F: FnOnce() -> String /// { /// // `func` consumes its captured variables, so it cannot be run more -/// // than once +/// // than once. /// println!("Consumed: {}", func()); /// /// println!("Delicious!"); /// /// // Attempting to invoke `func()` again will throw a `use of moved -/// // value` error for `func` +/// // value` error for `func`. /// } /// /// let x = String::from("x"); @@ -138,7 +191,7 @@ pub trait FnOnce { #[stable(feature = "fn_once_output", since = "1.12.0")] type Output; - /// This is called when the call operator is used. + /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } From f1cc7d6c142247de355d65d87578ccd1469b1304 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 22:55:20 +0200 Subject: [PATCH 09/88] Revised core::ops::range::* docs Part of #29365. * Strenghtened summary/explanation split, making phrasings more parallel * Added links throughout * Fixed some example formatting & removed extraneous `fn main()`s (or hid then when needed because of `#![features]`. * Emphasized note on `RangeFrom`'s `Iterator` implementation * Added summary sentences to (unstable) `contains` methods --- src/libcore/ops/range.rs | 211 ++++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 93 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 33258b7a875c..6a405cfdb980 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -10,10 +10,10 @@ use fmt; -/// An unbounded range. Use `..` (two dots) for its shorthand. +/// An unbounded range (`..`). /// -/// Its primary use case is slicing index. It cannot serve as an iterator -/// because it doesn't have a starting point. +/// `RangeFull` is primarily used as a [slicing index], it's shorthand is `..`. +/// It cannot serve as an [`Iterator`] because it doesn't have a starting point. /// /// # Examples /// @@ -23,8 +23,8 @@ use fmt; /// assert_eq!((..), std::ops::RangeFull); /// ``` /// -/// It does not have an `IntoIterator` implementation, so you can't use it in a -/// `for` loop directly. This won't compile: +/// It does not have an [`IntoIterator`] implementation, so you can't use it in +/// a `for` loop directly. This won't compile: /// /// ```compile_fail,E0277 /// for i in .. { @@ -32,7 +32,7 @@ use fmt; /// } /// ``` /// -/// Used as a slicing index, `RangeFull` produces the full array as a slice. +/// Used as a [slicing index], `RangeFull` produces the full array as a slice. /// /// ``` /// let arr = [0, 1, 2, 3]; @@ -41,6 +41,10 @@ use fmt; /// assert_eq!(arr[1.. ], [ 1,2,3]); /// assert_eq!(arr[1..3], [ 1,2 ]); /// ``` +/// +/// [`IntoIterator`]: ../iter/trait.Iterator.html +/// [`Iterator`]: ../iter/trait.IntoIterator.html +/// [slicing index]: ../slice/trait.SliceIndex.html #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -52,24 +56,23 @@ impl fmt::Debug for RangeFull { } } -/// A (half-open) range which is bounded at both ends: { x | start <= x < end }. -/// Use `start..end` (two dots) for its shorthand. +/// A (half-open) range bounded inclusively below and exclusively above +/// (`start..end`). /// -/// See the [`contains`](#method.contains) method for its characterization. +/// The `Range` `start..end` contains all values with `x >= start` and +/// `x < end`. /// /// # Examples /// /// ``` -/// fn main() { -/// assert_eq!((3..5), std::ops::Range{ start: 3, end: 5 }); -/// assert_eq!(3+4+5, (3..6).sum()); +/// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); +/// assert_eq!(3 + 4 + 5, (3..6).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); // Range -/// } +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); +/// assert_eq!(arr[ ..3], [0,1,2 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3]); +/// assert_eq!(arr[1..3], [ 1,2 ]); // Range /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -91,49 +94,51 @@ impl fmt::Debug for Range { #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> Range { + /// Returns `true` if `item` is contained in the range. + /// /// # Examples /// /// ``` /// #![feature(range_contains)] - /// fn main() { - /// assert!( ! (3..5).contains(2)); - /// assert!( (3..5).contains(3)); - /// assert!( (3..5).contains(4)); - /// assert!( ! (3..5).contains(5)); /// - /// assert!( ! (3..3).contains(3)); - /// assert!( ! (3..2).contains(3)); - /// } + /// # fn main() { + /// assert!(!(3..5).contains(2)); + /// assert!( (3..5).contains(3)); + /// assert!( (3..5).contains(4)); + /// assert!(!(3..5).contains(5)); + /// + /// assert!(!(3..3).contains(3)); + /// assert!(!(3..2).contains(3)); + /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (self.start <= item) && (item < self.end) } } -/// A range which is only bounded below: { x | start <= x }. -/// Use `start..` for its shorthand. +/// A range only bounded inclusively below (`start..`). /// -/// See the [`contains`](#method.contains) method for its characterization. +/// The `RangeFrom` `start..` contains all values with `x >= start`. /// -/// Note: Currently, no overflow checking is done for the iterator +/// *Note*: Currently, no overflow checking is done for the [`Iterator`] /// implementation; if you use an integer range and the integer overflows, it -/// might panic in debug mode or create an endless loop in release mode. This -/// overflow behavior might change in the future. +/// might panic in debug mode or create an endless loop in release mode. **This +/// overflow behavior might change in the future.** /// /// # Examples /// /// ``` -/// fn main() { -/// assert_eq!((2..), std::ops::RangeFrom{ start: 2 }); -/// assert_eq!(2+3+4, (2..).take(3).sum()); +/// assert_eq!((2..), std::ops::RangeFrom { start: 2 }); +/// assert_eq!(2 + 3 + 4, (2..).take(3).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); // RangeFrom -/// assert_eq!(arr[1..3], [ 1,2 ]); -/// } +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); +/// assert_eq!(arr[ ..3], [0,1,2 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3]); // RangeFrom +/// assert_eq!(arr[1..3], [ 1,2 ]); /// ``` +/// +/// [`Iterator`]: ../iter/trait.IntoIterator.html #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom { @@ -151,38 +156,39 @@ impl fmt::Debug for RangeFrom { #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeFrom { + /// Returns `true` if `item` is contained in the range. + /// /// # Examples /// /// ``` /// #![feature(range_contains)] - /// fn main() { - /// assert!( ! (3..).contains(2)); - /// assert!( (3..).contains(3)); - /// assert!( (3..).contains(1_000_000_000)); - /// } + /// + /// # fn main() { + /// assert!(!(3..).contains(2)); + /// assert!( (3..).contains(3)); + /// assert!( (3..).contains(1_000_000_000)); + /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (self.start <= item) } } -/// A range which is only bounded above: { x | x < end }. -/// Use `..end` (two dots) for its shorthand. +/// A range only bounded exclusively above (`..end`). /// -/// See the [`contains`](#method.contains) method for its characterization. -/// -/// It cannot serve as an iterator because it doesn't have a starting point. +/// The `RangeTo` `..end` contains all values with `x < end`. +/// It cannot serve as an [`Iterator`] because it doesn't have a starting point. /// /// # Examples /// -/// The `..{integer}` syntax is a `RangeTo`: +/// The `..end` syntax is a `RangeTo`: /// /// ``` -/// assert_eq!((..5), std::ops::RangeTo{ end: 5 }); +/// assert_eq!((..5), std::ops::RangeTo { end: 5 }); /// ``` /// -/// It does not have an `IntoIterator` implementation, so you can't use it in a -/// `for` loop directly. This won't compile: +/// It does not have an [`IntoIterator`] implementation, so you can't use it in +/// a `for` loop directly. This won't compile: /// /// ```compile_fail,E0277 /// for i in ..5 { @@ -190,7 +196,7 @@ impl> RangeFrom { /// } /// ``` /// -/// When used as a slicing index, `RangeTo` produces a slice of all array +/// When used as a [slicing index], `RangeTo` produces a slice of all array /// elements before the index indicated by `end`. /// /// ``` @@ -200,6 +206,10 @@ impl> RangeFrom { /// assert_eq!(arr[1.. ], [ 1,2,3]); /// assert_eq!(arr[1..3], [ 1,2 ]); /// ``` +/// +/// [`IntoIterator`]: ../iter/trait.Iterator.html +/// [`Iterator`]: ../iter/trait.IntoIterator.html +/// [slicing index]: ../slice/trait.SliceIndex.html #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo { @@ -217,38 +227,42 @@ impl fmt::Debug for RangeTo { #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeTo { + /// Returns `true` if `item` is contained in the range. + /// /// # Examples /// /// ``` /// #![feature(range_contains)] - /// fn main() { - /// assert!( (..5).contains(-1_000_000_000)); - /// assert!( (..5).contains(4)); - /// assert!( ! (..5).contains(5)); - /// } + /// + /// # fn main() { + /// assert!( (..5).contains(-1_000_000_000)); + /// assert!( (..5).contains(4)); + /// assert!(!(..5).contains(5)); + /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (item < self.end) } } -/// An inclusive range which is bounded at both ends: { x | start <= x <= end }. -/// Use `start...end` (three dots) for its shorthand. +/// An range bounded inclusively below and above (`start...end`). /// -/// See the [`contains`](#method.contains) method for its characterization. +/// The `RangeInclusive` `start...end` contains all values with `x >= start` +/// and `x <= end`. /// /// # Examples /// /// ``` /// #![feature(inclusive_range,inclusive_range_syntax)] -/// fn main() { -/// assert_eq!((3...5), std::ops::RangeInclusive{ start: 3, end: 5 }); -/// assert_eq!(3+4+5, (3...5).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ...2], [0,1,2 ]); -/// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive -/// } +/// # fn main() { +/// assert_eq!((3...5), std::ops::RangeInclusive { start: 3, end: 5 }); +/// assert_eq!(3 + 4 + 5, (3...5).sum()); +/// +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ ...2], [0,1,2 ]); +/// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive +/// # } /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -274,43 +288,44 @@ impl fmt::Debug for RangeInclusive { #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeInclusive { + /// Returns `true` if `item` is contained in the range. + /// /// # Examples /// /// ``` /// #![feature(range_contains,inclusive_range_syntax)] - /// fn main() { - /// assert!( ! (3...5).contains(2)); - /// assert!( (3...5).contains(3)); - /// assert!( (3...5).contains(4)); - /// assert!( (3...5).contains(5)); - /// assert!( ! (3...5).contains(6)); /// - /// assert!( (3...3).contains(3)); - /// assert!( ! (3...2).contains(3)); - /// } + /// # fn main() { + /// assert!(!(3...5).contains(2)); + /// assert!( (3...5).contains(3)); + /// assert!( (3...5).contains(4)); + /// assert!( (3...5).contains(5)); + /// assert!(!(3...5).contains(6)); + /// + /// assert!( (3...3).contains(3)); + /// assert!(!(3...2).contains(3)); + /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end } } -/// An inclusive range which is only bounded above: { x | x <= end }. -/// Use `...end` (three dots) for its shorthand. +/// A range only bounded inclusively above (`...end`). /// -/// See the [`contains`](#method.contains) method for its characterization. -/// -/// It cannot serve as an iterator because it doesn't have a starting point. +/// The `RangeToInclusive` `...end` contains all values with `x <= end`. +/// It cannot serve as an [`Iterator`] because it doesn't have a starting point. /// /// # Examples /// -/// The `...{integer}` syntax is a `RangeToInclusive`: +/// The `...end` syntax is a `RangeToInclusive`: /// /// ``` /// #![feature(inclusive_range,inclusive_range_syntax)] /// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 }); /// ``` /// -/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// It does not have an [`IntoIterator`] implementation, so you can't use it in a /// `for` loop directly. This won't compile: /// /// ```compile_fail,E0277 @@ -320,15 +335,22 @@ impl> RangeInclusive { /// } /// ``` /// -/// When used as a slicing index, `RangeToInclusive` produces a slice of all +/// When used as a [slicing index], `RangeToInclusive` produces a slice of all /// array elements up to and including the index indicated by `end`. /// /// ``` /// #![feature(inclusive_range_syntax)] +/// +/// # fn main() { /// let arr = [0, 1, 2, 3]; /// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive /// assert_eq!(arr[1...2], [ 1,2 ]); +/// # } /// ``` +/// +/// [`IntoIterator`]: ../iter/trait.Iterator.html +/// [`Iterator`]: ../iter/trait.IntoIterator.html +/// [slicing index]: ../slice/trait.SliceIndex.html #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] pub struct RangeToInclusive { @@ -348,15 +370,18 @@ impl fmt::Debug for RangeToInclusive { #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeToInclusive { + /// Returns `true` if `item` is contained in the range. + /// /// # Examples /// /// ``` /// #![feature(range_contains,inclusive_range_syntax)] - /// fn main() { - /// assert!( (...5).contains(-1_000_000_000)); - /// assert!( (...5).contains(5)); - /// assert!( ! (...5).contains(6)); - /// } + /// + /// # fn main() { + /// assert!( (...5).contains(-1_000_000_000)); + /// assert!( (...5).contains(5)); + /// assert!(!(...5).contains(6)); + /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (item <= self.end) From 99e44d8680f91e908c39ab3d5f0be2c11558af01 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 7 Aug 2017 23:07:34 +0200 Subject: [PATCH 10/88] Added to core::ops module docs Part of #29365. * Added paragraph adapted from API guidelines that operator implementations should be unsurprising * Modified Point example to be more clear when just reading it --- src/libcore/ops/mod.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index a78f4fe28a6b..b5e6912b10d6 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -21,6 +21,12 @@ //! custom operators are required, you should look toward macros or compiler //! plugins to extend Rust's syntax. //! +//! Implementations of operator traits should be unsurprising in their +//! respective contexts, keeping in mind their usual meanings and +//! [operator precedence]. For example, when implementing [`Mul`], the operation +//! should have some resemblance to multiplication (and share expected +//! properties like associativity). +//! //! Note that the `&&` and `||` operators short-circuit, i.e. they only //! evaluate their second operand if it contributes to the result. Since this //! behavior is not enforceable by traits, `&&` and `||` are not supported as @@ -46,7 +52,7 @@ //! ```rust //! use std::ops::{Add, Sub}; //! -//! #[derive(Debug)] +//! #[derive(Debug, PartialEq)] //! struct Point { //! x: i32, //! y: i32, @@ -67,10 +73,9 @@ //! Point {x: self.x - other.x, y: self.y - other.y} //! } //! } -//! fn main() { -//! println!("{:?}", Point {x: 1, y: 0} + Point {x: 2, y: 3}); -//! println!("{:?}", Point {x: 1, y: 0} - Point {x: 2, y: 3}); -//! } +//! +//! assert_eq!(Point {x: 3, y: 3}, Point {x: 1, y: 0} + Point {x: 2, y: 3}); +//! assert_eq!(Point {x: -1, y: -3}, Point {x: 1, y: 0} - Point {x: 2, y: 3}); //! ``` //! //! See the documentation for each trait for an example implementation. @@ -143,7 +148,9 @@ //! [`FnOnce`]: trait.FnOnce.html //! [`Add`]: trait.Add.html //! [`Sub`]: trait.Sub.html +//! [`Mul`]: trait.Mul.html //! [`clone`]: ../clone/trait.Clone.html#tymethod.clone +//! [operator precedence]: ../../reference/expressions.html#operator-precedence #![stable(feature = "rust1", since = "1.0.0")] From c62a8c5694b5f7fe4f4a27885aabdd85c6e8e821 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Tue, 8 Aug 2017 12:22:48 +0100 Subject: [PATCH 11/88] rustdoc: Don't add external impls to implementors js Otherwise impls from not documented crates appear. --- src/librustdoc/html/render.rs | 12 ++++++++++++ src/test/rustdoc/issue-43701.rs | 15 +++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/test/rustdoc/issue-43701.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index fc0adef70baa..44f2dece3540 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -762,6 +762,7 @@ fn write_shared(cx: &Context, } }; + let mut have_impls = false; let mut implementors = format!(r#"implementors["{}"] = ["#, krate.name); for imp in imps { // If the trait and implementation are in the same crate, then @@ -769,10 +770,21 @@ fn write_shared(cx: &Context, // going on). If they're in different crates then the crate defining // the trait will be interested in our implementation. if imp.def_id.krate == did.krate { continue } + // If the implementation is from another crate then that crate + // should add it. + if !imp.def_id.is_local() { continue } + have_impls = true; write!(implementors, "{},", as_json(&imp.impl_.to_string())).unwrap(); } implementors.push_str("];"); + // Only create a js file if we have impls to add to it. If the trait is + // documented locally though we always create the file to avoid dead + // links. + if !have_impls && !cache.paths.contains_key(&did) { + continue; + } + let mut mydst = dst.clone(); for part in &remote_path[..remote_path.len() - 1] { mydst.push(part); diff --git a/src/test/rustdoc/issue-43701.rs b/src/test/rustdoc/issue-43701.rs new file mode 100644 index 000000000000..791d83195990 --- /dev/null +++ b/src/test/rustdoc/issue-43701.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. + +#![crate_name = "foo"] + +pub use std::vec::Vec; + +// @!has implementors/core/clone/trait.Clone.js From 846d373ddf31aeb76dabedb81a4ae9200d9da1cd Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 8 Aug 2017 09:53:51 -0700 Subject: [PATCH 12/88] Clarify the language around `RefCell::swap` --- src/libcore/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 675fcef5e5ab..f0a94a634f5c 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -589,7 +589,7 @@ impl RefCell { /// /// # Panics /// - /// This function will panic if the `RefCell` has any outstanding borrows, + /// This function will panic if either `RefCell` has any outstanding borrows, /// whether or not they are full mutable borrows. #[inline] #[unstable(feature = "refcell_replace_swap", issue="43570")] From 8f935fbb5b7e8ea5a320082cb9e28095aa0b5759 Mon Sep 17 00:00:00 2001 From: kennytm Date: Wed, 19 Jul 2017 16:09:22 +0800 Subject: [PATCH 13/88] Strip out function implementation when documenting. This prevents compilation failure we want to document a platform-specific module. Every function is replaced by `loop {}` using the same construct as `--unpretty everybody_loops`. Note also a workaround to #43636 is included: `const fn` will retain their bodies, since the standard library has quite a number of them. --- src/librustc_driver/pretty.rs | 62 ++++++++++++++++++----------------- src/librustdoc/core.rs | 3 ++ src/librustdoc/test.rs | 4 +++ 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 269363fdd2f9..ef6a4b209290 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -44,6 +44,7 @@ use std::io::{self, Write}; use std::option; use std::path::Path; use std::str::FromStr; +use std::mem; use rustc::hir::map as hir_map; use rustc::hir::map::blocks; @@ -618,52 +619,53 @@ impl UserIdentifiedItem { } } -struct ReplaceBodyWithLoop { +// Note: Also used by librustdoc, see PR #43348. Consider moving this struct elsewhere. +pub struct ReplaceBodyWithLoop { within_static_or_const: bool, } impl ReplaceBodyWithLoop { - fn new() -> ReplaceBodyWithLoop { + pub fn new() -> ReplaceBodyWithLoop { ReplaceBodyWithLoop { within_static_or_const: false } } + + fn run R>(&mut self, is_const: bool, action: F) -> R { + let old_const = mem::replace(&mut self.within_static_or_const, is_const); + let ret = action(self); + self.within_static_or_const = old_const; + ret + } } impl fold::Folder for ReplaceBodyWithLoop { fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { - match i { - ast::ItemKind::Static(..) | - ast::ItemKind::Const(..) => { - self.within_static_or_const = true; - let ret = fold::noop_fold_item_kind(i, self); - self.within_static_or_const = false; - return ret; - } - _ => fold::noop_fold_item_kind(i, self), - } + let is_const = match i { + ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, + ast::ItemKind::Fn(_, _, ref constness, _, _, _) => + constness.node == ast::Constness::Const, + _ => false, + }; + self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) } fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector { - match i.node { - ast::TraitItemKind::Const(..) => { - self.within_static_or_const = true; - let ret = fold::noop_fold_trait_item(i, self); - self.within_static_or_const = false; - return ret; - } - _ => fold::noop_fold_trait_item(i, self), - } + let is_const = match i.node { + ast::TraitItemKind::Const(..) => true, + ast::TraitItemKind::Method(ast::MethodSig { ref constness, .. }, _) => + constness.node == ast::Constness::Const, + _ => false, + }; + self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) } fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector { - match i.node { - ast::ImplItemKind::Const(..) => { - self.within_static_or_const = true; - let ret = fold::noop_fold_impl_item(i, self); - self.within_static_or_const = false; - return ret; - } - _ => fold::noop_fold_impl_item(i, self), - } + let is_const = match i.node { + ast::ImplItemKind::Const(..) => true, + ast::ImplItemKind::Method(ast::MethodSig { ref constness, .. }, _) => + constness.node == ast::Constness::Const, + _ => false, + }; + self.run(is_const, |s| fold::noop_fold_impl_item(i, s)) } fn fold_block(&mut self, b: P) -> P { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index e101e29fc6fb..9bb7e4e3a09d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -10,6 +10,7 @@ use rustc_lint; use rustc_driver::{driver, target_features, abort_on_err}; +use rustc_driver::pretty::ReplaceBodyWithLoop; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; use rustc::hir::def_id::DefId; @@ -26,6 +27,7 @@ use rustc_metadata::cstore::CStore; use syntax::{ast, codemap}; use syntax::feature_gate::UnstableFeatures; +use syntax::fold::Folder; use errors; use errors::emitter::ColorConfig; @@ -158,6 +160,7 @@ pub fn run_core(search_paths: SearchPaths, let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input)); + let krate = ReplaceBodyWithLoop::new().fold_crate(krate); let name = link::find_crate_name(Some(&sess), &krate.attrs, &input); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index b1e92b5190f3..8e24a3b58792 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -32,6 +32,7 @@ use rustc_back::dynamic_lib::DynamicLibrary; use rustc_back::tempdir::TempDir; use rustc_driver::{self, driver, Compilation}; use rustc_driver::driver::phase_2_configure_and_expand; +use rustc_driver::pretty::ReplaceBodyWithLoop; use rustc_metadata::cstore::CStore; use rustc_resolve::MakeGlobMap; use rustc_trans; @@ -39,6 +40,7 @@ use rustc_trans::back::link; use syntax::ast; use syntax::codemap::CodeMap; use syntax::feature_gate::UnstableFeatures; +use syntax::fold::Folder; use syntax_pos::{BytePos, DUMMY_SP, Pos, Span}; use errors; use errors::emitter::ColorConfig; @@ -72,6 +74,7 @@ pub fn run(input: &str, crate_types: vec![config::CrateTypeDylib], externs: externs.clone(), unstable_features: UnstableFeatures::from_environment(), + lint_cap: Some(::rustc::lint::Level::Allow), actually_rustdoc: true, ..config::basic_options().clone() }; @@ -94,6 +97,7 @@ pub fn run(input: &str, let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input)); + let krate = ReplaceBodyWithLoop::new().fold_crate(krate); let driver::ExpansionResult { defs, mut hir_forest, .. } = { phase_2_configure_and_expand( &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(()) From a2b888675accccedec7601cc3bd67ca028b4757c Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 5 Aug 2017 14:38:52 +0800 Subject: [PATCH 14/88] Implemented #[doc(cfg(...))]. This attribute has two effects: 1. Items with this attribute and their children will have the "This is supported on **** only" message attached in the documentation. 2. The items' doc tests will be skipped if the configuration does not match. --- .../src/language-features/doc-cfg.md | 42 + src/librustdoc/clean/cfg.rs | 889 ++++++++++++++++++ src/librustdoc/clean/mod.rs | 69 +- src/librustdoc/html/render.rs | 8 + src/librustdoc/html/static/styles/main.css | 1 + src/librustdoc/lib.rs | 1 + src/librustdoc/passes/mod.rs | 6 + src/librustdoc/passes/propagate_doc_cfg.rs | 47 + src/librustdoc/test.rs | 10 +- src/libsyntax/feature_gate.rs | 13 + src/test/compile-fail/feature-gate-doc_cfg.rs | 12 + src/test/rustdoc/doc-cfg.rs | 47 + 12 files changed, 1129 insertions(+), 16 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/doc-cfg.md create mode 100644 src/librustdoc/clean/cfg.rs create mode 100644 src/librustdoc/passes/propagate_doc_cfg.rs create mode 100644 src/test/compile-fail/feature-gate-doc_cfg.rs create mode 100644 src/test/rustdoc/doc-cfg.rs diff --git a/src/doc/unstable-book/src/language-features/doc-cfg.md b/src/doc/unstable-book/src/language-features/doc-cfg.md new file mode 100644 index 000000000000..ddc538e12144 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/doc-cfg.md @@ -0,0 +1,42 @@ +# `doc_cfg` + +The tracking issue for this feature is: [#43781] + +------ + +The `doc_cfg` feature allows an API be documented as only available in some specific platforms. +This attribute has two effects: + +1. In the annotated item's documentation, there will be a message saying "This is supported on + (platform) only". + +2. The item's doc-tests will only run on the specific platform. + +This feature was introduced as part of PR [#43348] to allow the platform-specific parts of the +standard library be documented. + +```rust +#![feature(doc_cfg)] + +#[cfg(any(windows, feature = "documentation"))] +#[doc(cfg(windows))] +/// The application's icon in the notification area (a.k.a. system tray). +/// +/// # Examples +/// +/// ```no_run +/// extern crate my_awesome_ui_library; +/// use my_awesome_ui_library::current_app; +/// use my_awesome_ui_library::windows::notification; +/// +/// let icon = current_app().get::(); +/// icon.show(); +/// icon.show_message("Hello"); +/// ``` +pub struct Icon { + // ... +} +``` + +[#43781]: https://github.com/rust-lang/rust/issues/43781 +[#43348]: https://github.com/rust-lang/rust/issues/43348 \ No newline at end of file diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs new file mode 100644 index 000000000000..da8c3a5cf206 --- /dev/null +++ b/src/librustdoc/clean/cfg.rs @@ -0,0 +1,889 @@ +// 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. + +//! Representation of a `#[doc(cfg(...))]` attribute. + +// FIXME: Once RFC #1868 is implemented, switch to use those structures instead. + +use std::mem; +use std::fmt::{self, Write}; +use std::ops; +use std::ascii::AsciiExt; + +use syntax::symbol::Symbol; +use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind, LitKind}; +use syntax::parse::ParseSess; +use syntax::feature_gate::Features; + +use syntax_pos::Span; + +use html::escape::Escape; + +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq)] +pub enum Cfg { + /// Accepts all configurations. + True, + /// Denies all configurations. + False, + /// A generic configration option, e.g. `test` or `target_os = "linux"`. + Cfg(Symbol, Option), + /// Negate a configuration requirement, i.e. `not(x)`. + Not(Box), + /// Union of a list of configuration requirements, i.e. `any(...)`. + Any(Vec), + /// Intersection of a list of configuration requirements, i.e. `all(...)`. + All(Vec), +} + +#[derive(PartialEq, Debug)] +pub struct InvalidCfgError { + pub msg: &'static str, + pub span: Span, +} + +impl Cfg { + /// Parses a `NestedMetaItem` into a `Cfg`. + fn parse_nested(nested_cfg: &NestedMetaItem) -> Result { + match nested_cfg.node { + NestedMetaItemKind::MetaItem(ref cfg) => Cfg::parse(cfg), + NestedMetaItemKind::Literal(ref lit) => Err(InvalidCfgError { + msg: "unexpected literal", + span: lit.span, + }), + } + } + + /// Parses a `MetaItem` into a `Cfg`. + /// + /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g. `unix` or + /// `target_os = "redox"`. + /// + /// If the content is not properly formatted, it will return an error indicating what and where + /// the error is. + pub fn parse(cfg: &MetaItem) -> Result { + let name = cfg.name(); + match cfg.node { + MetaItemKind::Word => Ok(Cfg::Cfg(name, None)), + MetaItemKind::NameValue(ref lit) => match lit.node { + LitKind::Str(value, _) => Ok(Cfg::Cfg(name, Some(value))), + _ => Err(InvalidCfgError { + // FIXME: if the main #[cfg] syntax decided to support non-string literals, + // this should be changed as well. + msg: "value of cfg option should be a string literal", + span: lit.span, + }), + }, + MetaItemKind::List(ref items) => { + let mut sub_cfgs = items.iter().map(Cfg::parse_nested); + match &*name.as_str() { + "all" => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)), + "any" => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)), + "not" => if sub_cfgs.len() == 1 { + Ok(!sub_cfgs.next().unwrap()?) + } else { + Err(InvalidCfgError { + msg: "expected 1 cfg-pattern", + span: cfg.span, + }) + }, + _ => Err(InvalidCfgError { + msg: "invalid predicate", + span: cfg.span, + }), + } + } + } + } + + /// Checks whether the given configuration can be matched in the current session. + /// + /// Equivalent to `attr::cfg_matches`. + // FIXME: Actually make use of `features`. + pub fn matches(&self, parse_sess: &ParseSess, features: Option<&Features>) -> bool { + match *self { + Cfg::False => false, + Cfg::True => true, + Cfg::Not(ref child) => !child.matches(parse_sess, features), + Cfg::All(ref sub_cfgs) => { + sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(parse_sess, features)) + }, + Cfg::Any(ref sub_cfgs) => { + sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(parse_sess, features)) + }, + Cfg::Cfg(name, value) => parse_sess.config.contains(&(name, value)), + } + } + + /// Whether the configuration consists of just `Cfg` or `Not`. + fn is_simple(&self) -> bool { + match *self { + Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) => true, + Cfg::All(..) | Cfg::Any(..) => false, + } + } + + /// Whether the configuration consists of just `Cfg`, `Not` or `All`. + fn is_all(&self) -> bool { + match *self { + Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) | Cfg::All(..) => true, + Cfg::Any(..) => false, + } + } + + /// Renders the configuration for human display, as a short HTML description. + pub(crate) fn render_short_html(&self) -> String { + let mut msg = Html(self).to_string(); + if self.should_capitalize_first_letter() { + if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) { + msg[i .. i+1].make_ascii_uppercase(); + } + } + msg + } + + /// Renders the configuration for long display, as a long HTML description. + pub(crate) fn render_long_html(&self) -> String { + let mut msg = format!("This is supported on {}", Html(self)); + if self.should_append_only_to_description() { + msg.push_str(" only"); + } + msg.push('.'); + msg + } + + fn should_capitalize_first_letter(&self) -> bool { + match *self { + Cfg::False | Cfg::True | Cfg::Not(..) => true, + Cfg::Any(ref sub_cfgs) | Cfg::All(ref sub_cfgs) => { + sub_cfgs.first().map(Cfg::should_capitalize_first_letter).unwrap_or(false) + }, + Cfg::Cfg(name, _) => match &*name.as_str() { + "debug_assertions" | "target_endian" => true, + _ => false, + }, + } + } + + fn should_append_only_to_description(&self) -> bool { + match *self { + Cfg::False | Cfg::True => false, + Cfg::Any(..) | Cfg::All(..) | Cfg::Cfg(..) => true, + Cfg::Not(ref child) => match **child { + Cfg::Cfg(..) => true, + _ => false, + } + } + } +} + +impl ops::Not for Cfg { + type Output = Cfg; + fn not(self) -> Cfg { + match self { + Cfg::False => Cfg::True, + Cfg::True => Cfg::False, + Cfg::Not(cfg) => *cfg, + s => Cfg::Not(Box::new(s)), + } + } +} + +impl ops::BitAndAssign for Cfg { + fn bitand_assign(&mut self, other: Cfg) { + match (self, other) { + (&mut Cfg::False, _) | (_, Cfg::True) => {}, + (s, Cfg::False) => *s = Cfg::False, + (s @ &mut Cfg::True, b) => *s = b, + (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => a.append(b), + (&mut Cfg::All(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)), + (s, Cfg::All(mut a)) => { + let b = mem::replace(s, Cfg::True); + a.push(b); + *s = Cfg::All(a); + }, + (s, b) => { + let a = mem::replace(s, Cfg::True); + *s = Cfg::All(vec![a, b]); + }, + } + } +} + +impl ops::BitAnd for Cfg { + type Output = Cfg; + fn bitand(mut self, other: Cfg) -> Cfg { + self &= other; + self + } +} + +impl ops::BitOrAssign for Cfg { + fn bitor_assign(&mut self, other: Cfg) { + match (self, other) { + (&mut Cfg::True, _) | (_, Cfg::False) => {}, + (s, Cfg::True) => *s = Cfg::True, + (s @ &mut Cfg::False, b) => *s = b, + (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => a.append(b), + (&mut Cfg::Any(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)), + (s, Cfg::Any(mut a)) => { + let b = mem::replace(s, Cfg::True); + a.push(b); + *s = Cfg::Any(a); + }, + (s, b) => { + let a = mem::replace(s, Cfg::True); + *s = Cfg::Any(vec![a, b]); + }, + } + } +} + +impl ops::BitOr for Cfg { + type Output = Cfg; + fn bitor(mut self, other: Cfg) -> Cfg { + self |= other; + self + } +} + +struct Html<'a>(&'a Cfg); + +fn write_with_opt_paren( + fmt: &mut fmt::Formatter, + has_paren: bool, + obj: T, +) -> fmt::Result { + if has_paren { + fmt.write_char('(')?; + } + obj.fmt(fmt)?; + if has_paren { + fmt.write_char(')')?; + } + Ok(()) +} + + +impl<'a> fmt::Display for Html<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self.0 { + Cfg::Not(ref child) => match **child { + Cfg::Any(ref sub_cfgs) => { + let separator = if sub_cfgs.iter().all(Cfg::is_simple) { + " nor " + } else { + ", nor " + }; + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { + fmt.write_str(if i == 0 { "neither " } else { separator })?; + write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?; + } + Ok(()) + } + ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple)), + ref c => write!(fmt, "not ({})", Html(c)), + }, + + Cfg::Any(ref sub_cfgs) => { + let separator = if sub_cfgs.iter().all(Cfg::is_simple) { + " or " + } else { + ", or " + }; + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { + if i != 0 { + fmt.write_str(separator)?; + } + write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?; + } + Ok(()) + }, + + Cfg::All(ref sub_cfgs) => { + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { + if i != 0 { + fmt.write_str(" and ")?; + } + write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg))?; + } + Ok(()) + }, + + Cfg::True => fmt.write_str("everywhere"), + Cfg::False => fmt.write_str("nowhere"), + + Cfg::Cfg(name, value) => { + let n = &*name.as_str(); + let human_readable = match (n, value) { + ("unix", None) => "Unix", + ("windows", None) => "Windows", + ("debug_assertions", None) => "debug-assertions enabled", + ("target_os", Some(os)) => match &*os.as_str() { + "android" => "Android", + "bitrig" => "Bitrig", + "dragonfly" => "DragonFly BSD", + "emscripten" => "Emscripten", + "freebsd" => "FreeBSD", + "fuchsia" => "Fuchsia", + "haiku" => "Haiku", + "ios" => "iOS", + "l4re" => "L4Re", + "linux" => "Linux", + "macos" => "macOS", + "nacl" => "NaCl", + "netbsd" => "NetBSD", + "openbsd" => "OpenBSD", + "redox" => "Redox", + "solaris" => "Solaris", + "windows" => "Windows", + _ => "", + }, + ("target_arch", Some(arch)) => match &*arch.as_str() { + "aarch64" => "AArch64", + "arm" => "ARM", + "asmjs" => "asm.js", + "mips" => "MIPS", + "mips64" => "MIPS-64", + "msp430" => "MSP430", + "powerpc" => "PowerPC", + "powerpc64" => "PowerPC-64", + "s390x" => "s390x", + "sparc64" => "SPARC64", + "wasm32" => "WebAssembly", + "x86" => "x86", + "x86_64" => "x86-64", + _ => "", + }, + ("target_vendor", Some(vendor)) => match &*vendor.as_str() { + "apple" => "Apple", + "pc" => "PC", + "rumprun" => "Rumprun", + "sun" => "Sun", + _ => "" + }, + ("target_env", Some(env)) => match &*env.as_str() { + "gnu" => "GNU", + "msvc" => "MSVC", + "musl" => "musl", + "newlib" => "Newlib", + "uclibc" => "uClibc", + _ => "", + }, + ("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian), + ("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits), + _ => "", + }; + if !human_readable.is_empty() { + fmt.write_str(human_readable) + } else if let Some(v) = value { + write!(fmt, "{}=\"{}\"", Escape(n), Escape(&*v.as_str())) + } else { + write!(fmt, "{}", Escape(n)) + } + } + } + } +} + +#[cfg(test)] +mod test { + use super::Cfg; + + use syntax::symbol::Symbol; + use syntax::ast::*; + use syntax::codemap::dummy_spanned; + use syntax_pos::DUMMY_SP; + + fn word_cfg(s: &str) -> Cfg { + Cfg::Cfg(Symbol::intern(s), None) + } + + fn name_value_cfg(name: &str, value: &str) -> Cfg { + Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value))) + } + + #[test] + fn test_cfg_not() { + assert_eq!(!Cfg::False, Cfg::True); + assert_eq!(!Cfg::True, Cfg::False); + assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test")))); + assert_eq!( + !Cfg::All(vec![word_cfg("a"), word_cfg("b")]), + Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")]))) + ); + assert_eq!( + !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]), + Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")]))) + ); + assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test")); + } + + #[test] + fn test_cfg_and() { + let mut x = Cfg::False; + x &= Cfg::True; + assert_eq!(x, Cfg::False); + + x = word_cfg("test"); + x &= Cfg::False; + assert_eq!(x, Cfg::False); + + x = word_cfg("test2"); + x &= Cfg::True; + assert_eq!(x, word_cfg("test2")); + + x = Cfg::True; + x &= word_cfg("test3"); + assert_eq!(x, word_cfg("test3")); + + x &= word_cfg("test4"); + assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")])); + + x &= word_cfg("test5"); + assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")])); + + x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]); + assert_eq!(x, Cfg::All(vec![ + word_cfg("test3"), + word_cfg("test4"), + word_cfg("test5"), + word_cfg("test6"), + word_cfg("test7"), + ])); + + let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]); + y &= x; + assert_eq!(y, Cfg::All(vec![ + word_cfg("test3"), + word_cfg("test4"), + word_cfg("test5"), + word_cfg("test6"), + word_cfg("test7"), + Cfg::Any(vec![word_cfg("a"), word_cfg("b")]), + ])); + + assert_eq!( + word_cfg("a") & word_cfg("b") & word_cfg("c"), + Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")]) + ); + } + + #[test] + fn test_cfg_or() { + let mut x = Cfg::True; + x |= Cfg::False; + assert_eq!(x, Cfg::True); + + x = word_cfg("test"); + x |= Cfg::True; + assert_eq!(x, Cfg::True); + + x = word_cfg("test2"); + x |= Cfg::False; + assert_eq!(x, word_cfg("test2")); + + x = Cfg::False; + x |= word_cfg("test3"); + assert_eq!(x, word_cfg("test3")); + + x |= word_cfg("test4"); + assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")])); + + x |= word_cfg("test5"); + assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")])); + + x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]); + assert_eq!(x, Cfg::Any(vec![ + word_cfg("test3"), + word_cfg("test4"), + word_cfg("test5"), + word_cfg("test6"), + word_cfg("test7"), + ])); + + let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]); + y |= x; + assert_eq!(y, Cfg::Any(vec![ + word_cfg("test3"), + word_cfg("test4"), + word_cfg("test5"), + word_cfg("test6"), + word_cfg("test7"), + Cfg::All(vec![word_cfg("a"), word_cfg("b")]), + ])); + + assert_eq!( + word_cfg("a") | word_cfg("b") | word_cfg("c"), + Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")]) + ); + } + + #[test] + fn test_parse_ok() { + let mi = MetaItem { + name: Symbol::intern("all"), + node: MetaItemKind::Word, + span: DUMMY_SP, + }; + assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); + + let mi = MetaItem { + name: Symbol::intern("all"), + node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str( + Symbol::intern("done"), + StrStyle::Cooked, + ))), + span: DUMMY_SP, + }; + assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done"))); + + let mi = MetaItem { + name: Symbol::intern("all"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("b"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b"))); + + let mi = MetaItem { + name: Symbol::intern("any"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("b"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b"))); + + let mi = MetaItem { + name: Symbol::intern("not"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a"))); + + let mi = MetaItem { + name: Symbol::intern("not"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("any"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("all"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("b"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("c"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c"))))); + + let mi = MetaItem { + name: Symbol::intern("all"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("b"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("c"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c"))); + } + + #[test] + fn test_parse_err() { + let mi = MetaItem { + name: Symbol::intern("foo"), + node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))), + span: DUMMY_SP, + }; + assert!(Cfg::parse(&mi).is_err()); + + let mi = MetaItem { + name: Symbol::intern("not"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("b"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert!(Cfg::parse(&mi).is_err()); + + let mi = MetaItem { + name: Symbol::intern("not"), + node: MetaItemKind::List(vec![]), + span: DUMMY_SP, + }; + assert!(Cfg::parse(&mi).is_err()); + + let mi = MetaItem { + name: Symbol::intern("foo"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert!(Cfg::parse(&mi).is_err()); + + let mi = MetaItem { + name: Symbol::intern("all"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("foo"), + node: MetaItemKind::List(vec![]), + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("b"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert!(Cfg::parse(&mi).is_err()); + + let mi = MetaItem { + name: Symbol::intern("any"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("a"), + node: MetaItemKind::Word, + span: DUMMY_SP, + })), + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("foo"), + node: MetaItemKind::List(vec![]), + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert!(Cfg::parse(&mi).is_err()); + + let mi = MetaItem { + name: Symbol::intern("not"), + node: MetaItemKind::List(vec![ + dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem { + name: Symbol::intern("foo"), + node: MetaItemKind::List(vec![]), + span: DUMMY_SP, + })), + ]), + span: DUMMY_SP, + }; + assert!(Cfg::parse(&mi).is_err()); + } + + #[test] + fn test_render_short_html() { + assert_eq!( + word_cfg("unix").render_short_html(), + "Unix" + ); + assert_eq!( + name_value_cfg("target_os", "macos").render_short_html(), + "macOS" + ); + assert_eq!( + name_value_cfg("target_pointer_width", "16").render_short_html(), + "16-bit" + ); + assert_eq!( + name_value_cfg("target_endian", "little").render_short_html(), + "Little-endian" + ); + assert_eq!( + (!word_cfg("windows")).render_short_html(), + "Non-Windows" + ); + assert_eq!( + (word_cfg("unix") & word_cfg("windows")).render_short_html(), + "Unix and Windows" + ); + assert_eq!( + (word_cfg("unix") | word_cfg("windows")).render_short_html(), + "Unix or Windows" + ); + assert_eq!( + ( + word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions") + ).render_short_html(), + "Unix and Windows and debug-assertions enabled" + ); + assert_eq!( + ( + word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions") + ).render_short_html(), + "Unix or Windows or debug-assertions enabled" + ); + assert_eq!( + ( + !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")) + ).render_short_html(), + "Neither Unix nor Windows nor debug-assertions enabled" + ); + assert_eq!( + ( + (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) | + (word_cfg("windows") & name_value_cfg("target_pointer_width", "64")) + ).render_short_html(), + "Unix and x86-64, or Windows and 64-bit" + ); + assert_eq!( + (!(word_cfg("unix") & word_cfg("windows"))).render_short_html(), + "Not (Unix and Windows)" + ); + assert_eq!( + ( + (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix") + ).render_short_html(), + "(Debug-assertions enabled or Windows) and Unix" + ); + } + + #[test] + fn test_render_long_html() { + assert_eq!( + word_cfg("unix").render_long_html(), + "This is supported on Unix only." + ); + assert_eq!( + name_value_cfg("target_os", "macos").render_long_html(), + "This is supported on macOS only." + ); + assert_eq!( + name_value_cfg("target_pointer_width", "16").render_long_html(), + "This is supported on 16-bit only." + ); + assert_eq!( + name_value_cfg("target_endian", "little").render_long_html(), + "This is supported on little-endian only." + ); + assert_eq!( + (!word_cfg("windows")).render_long_html(), + "This is supported on non-Windows only." + ); + assert_eq!( + (word_cfg("unix") & word_cfg("windows")).render_long_html(), + "This is supported on Unix and Windows only." + ); + assert_eq!( + (word_cfg("unix") | word_cfg("windows")).render_long_html(), + "This is supported on Unix or Windows only." + ); + assert_eq!( + ( + word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions") + ).render_long_html(), + "This is supported on Unix and Windows and debug-assertions enabled \ + only." + ); + assert_eq!( + ( + word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions") + ).render_long_html(), + "This is supported on Unix or Windows or debug-assertions enabled \ + only." + ); + assert_eq!( + ( + !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")) + ).render_long_html(), + "This is supported on neither Unix nor Windows nor debug-assertions \ + enabled." + ); + assert_eq!( + ( + (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) | + (word_cfg("windows") & name_value_cfg("target_pointer_width", "64")) + ).render_long_html(), + "This is supported on Unix and x86-64, or Windows and 64-bit only." + ); + assert_eq!( + (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(), + "This is supported on not (Unix and Windows)." + ); + assert_eq!( + ( + (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix") + ).render_long_html(), + "This is supported on (debug-assertions enabled or Windows) and Unix \ + only." + ); + } +} \ No newline at end of file diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a9636c7e2fd7..57e72c3a40bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -52,8 +52,11 @@ use visit_ast; use html::item_type::ItemType; pub mod inline; +pub mod cfg; mod simplify; +use self::cfg::Cfg; + // extract the stability index for a node from tcx, if possible fn get_stability(cx: &DocContext, def_id: DefId) -> Option { cx.tcx.lookup_stability(def_id).clean(cx) @@ -536,31 +539,67 @@ impl> NestedAttributesExt for I { pub struct Attributes { pub doc_strings: Vec, pub other_attrs: Vec, + pub cfg: Option>, pub span: Option, } impl Attributes { - pub fn from_ast(attrs: &[ast::Attribute]) -> Attributes { - let mut doc_strings = vec![]; - let mut sp = None; - let other_attrs = attrs.iter().filter_map(|attr| { - attr.with_desugared_doc(|attr| { - if let Some(value) = attr.value_str() { - if attr.check_name("doc") { - doc_strings.push(value.to_string()); - if sp.is_none() { - sp = Some(attr.span); + /// Extracts the content from an attribute `#[doc(cfg(content))]`. + fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { + use syntax::ast::NestedMetaItemKind::MetaItem; + + if let ast::MetaItemKind::List(ref nmis) = mi.node { + if nmis.len() == 1 { + if let MetaItem(ref cfg_mi) = nmis[0].node { + if cfg_mi.check_name("cfg") { + if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node { + if cfg_nmis.len() == 1 { + if let MetaItem(ref content_mi) = cfg_nmis[0].node { + return Some(content_mi); + } + } } - return None; } } + } + } + None + } + + pub fn from_ast(diagnostic: &::errors::Handler, attrs: &[ast::Attribute]) -> Attributes { + let mut doc_strings = vec![]; + let mut sp = None; + let mut cfg = Cfg::True; + + let other_attrs = attrs.iter().filter_map(|attr| { + attr.with_desugared_doc(|attr| { + if attr.check_name("doc") { + if let Some(mi) = attr.meta() { + if let Some(value) = mi.value_str() { + // Extracted #[doc = "..."] + doc_strings.push(value.to_string()); + if sp.is_none() { + sp = Some(attr.span); + } + return None; + } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { + // Extracted #[doc(cfg(...))] + match Cfg::parse(cfg_mi) { + Ok(new_cfg) => cfg &= new_cfg, + Err(e) => diagnostic.span_err(e.span, e.msg), + } + return None; + } + } + } Some(attr.clone()) }) }).collect(); Attributes { - doc_strings: doc_strings, - other_attrs: other_attrs, + doc_strings, + other_attrs, + cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) }, span: sp, } } @@ -579,8 +618,8 @@ impl AttributesExt for Attributes { } impl Clean for [ast::Attribute] { - fn clean(&self, _cx: &DocContext) -> Attributes { - Attributes::from_ast(self) + fn clean(&self, cx: &DocContext) -> Attributes { + Attributes::from_ast(cx.sess().diagnostic(), self) } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index fc0adef70baa..95aa8e97dbba 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1950,6 +1950,14 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}", text)) } + if let Some(ref cfg) = item.attrs.cfg { + stability.push(format!("
{}
", if show_reason { + cfg.render_long_html() + } else { + cfg.render_short_html() + })); + } + stability } diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index 034c5307fc08..08bf5a10fe9d 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -152,6 +152,7 @@ a.test-arrow { .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } +.stab.portability { background: #C4ECFF; border-color: #7BA5DB; } #help > div { background: #e9e9e9; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 64240d26894d..9264015ed9ed 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -26,6 +26,7 @@ #![feature(test)] #![feature(unicode)] #![feature(vec_remove_item)] +#![feature(ascii_ctype)] extern crate arena; extern crate getopts; diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 41fd9efe61e0..146629486fab 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -33,6 +33,9 @@ pub use self::strip_priv_imports::strip_priv_imports; mod unindent_comments; pub use self::unindent_comments::unindent_comments; +mod propagate_doc_cfg; +pub use self::propagate_doc_cfg::propagate_doc_cfg; + type Pass = (&'static str, // name fn(clean::Crate) -> plugins::PluginResult, // fn &'static str); // description @@ -49,6 +52,8 @@ pub const PASSES: &'static [Pass] = &[ implies strip-priv-imports"), ("strip-priv-imports", strip_priv_imports, "strips all private import statements (`use`, `extern crate`) from a crate"), + ("propagate-doc-cfg", propagate_doc_cfg, + "propagates `#[doc(cfg(...))]` to child items"), ]; pub const DEFAULT_PASSES: &'static [&'static str] = &[ @@ -56,6 +61,7 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[ "strip-private", "collapse-docs", "unindent-comments", + "propagate-doc-cfg", ]; diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs new file mode 100644 index 000000000000..9e65fff5e2ac --- /dev/null +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -0,0 +1,47 @@ +// 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::rc::Rc; + +use clean::{Crate, Item}; +use clean::cfg::Cfg; +use fold::DocFolder; +use plugins::PluginResult; + +pub fn propagate_doc_cfg(cr: Crate) -> PluginResult { + CfgPropagator { parent_cfg: None }.fold_crate(cr) +} + +struct CfgPropagator { + parent_cfg: Option>, +} + +impl DocFolder for CfgPropagator { + fn fold_item(&mut self, mut item: Item) -> Option { + let old_parent_cfg = self.parent_cfg.clone(); + + let new_cfg = match (self.parent_cfg.take(), item.attrs.cfg.take()) { + (None, None) => None, + (Some(rc), None) | (None, Some(rc)) => Some(rc), + (Some(mut a), Some(b)) => { + let b = Rc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc)); + *Rc::make_mut(&mut a) &= b; + Some(a) + } + }; + self.parent_cfg = new_cfg.clone(); + item.attrs.cfg = new_cfg; + + let result = self.fold_item_recur(item); + self.parent_cfg = old_parent_cfg; + + result + } +} diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 8e24a3b58792..fff047c99c03 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -125,6 +125,7 @@ pub fn run(input: &str, let map = hir::map::map_crate(&mut hir_forest, defs); let krate = map.krate(); let mut hir_collector = HirCollector { + sess: &sess, collector: &mut collector, map: &map }; @@ -578,6 +579,7 @@ impl Collector { } struct HirCollector<'a, 'hir: 'a> { + sess: &'a session::Session, collector: &'a mut Collector, map: &'a hir::map::Map<'hir> } @@ -587,12 +589,18 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { name: String, attrs: &[ast::Attribute], nested: F) { + let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs); + if let Some(ref cfg) = attrs.cfg { + if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features.borrow())) { + return; + } + } + let has_name = !name.is_empty(); if has_name { self.collector.names.push(name); } - let mut attrs = Attributes::from_ast(attrs); attrs.collapse_doc_comments(); attrs.unindent_doc_comments(); if let Some(doc) = attrs.doc_value() { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index aeb574bc3af3..668732e6855b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -364,6 +364,9 @@ declare_features! ( // global allocators and their internals (active, global_allocator, "1.20.0", None), (active, allocator_internals, "1.20.0", None), + + // #[doc(cfg(...))] + (active, doc_cfg, "1.21.0", Some(43781)), ); declare_features! ( @@ -1157,6 +1160,16 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { self.context.check_attribute(attr, false); } + if attr.check_name("doc") { + if let Some(content) = attr.meta_item_list() { + if content.len() == 1 && content[0].check_name("cfg") { + gate_feature_post!(&self, doc_cfg, attr.span, + "#[doc(cfg(...))] is experimental" + ); + } + } + } + if self.context.features.proc_macro && attr::is_known(attr) { return } diff --git a/src/test/compile-fail/feature-gate-doc_cfg.rs b/src/test/compile-fail/feature-gate-doc_cfg.rs new file mode 100644 index 000000000000..1a77d9180145 --- /dev/null +++ b/src/test/compile-fail/feature-gate-doc_cfg.rs @@ -0,0 +1,12 @@ +// 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. + +#[doc(cfg(unix))] //~ ERROR: #[doc(cfg(...))] is experimental +fn main() {} diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs new file mode 100644 index 000000000000..cfb37912fe75 --- /dev/null +++ b/src/test/rustdoc/doc-cfg.rs @@ -0,0 +1,47 @@ +// 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(doc_cfg)] + +// @has doc_cfg/struct.Portable.html +// @!has - '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' '' +// @has - '//*[@id="method.unix_and_arm_only_function"]' 'fn unix_and_arm_only_function()' +// @has - '//*[@class="stab portability"]' 'This is supported on Unix and ARM only.' +pub struct Portable; + +// @has doc_cfg/unix_only/index.html \ +// '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ +// 'This is supported on Unix only.' +// @matches - '//*[@class=" module-item"]//*[@class="stab portability"]' '\AUnix\Z' +// @matches - '//*[@class=" module-item"]//*[@class="stab portability"]' '\AUnix and ARM\Z' +// @count - '//*[@class="stab portability"]' 3 +#[doc(cfg(unix))] +pub mod unix_only { + // @has doc_cfg/unix_only/fn.unix_only_function.html \ + // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ + // 'This is supported on Unix only.' + // @count - '//*[@class="stab portability"]' 1 + pub fn unix_only_function() { + content::should::be::irrelevant(); + } + + // @has doc_cfg/unix_only/trait.ArmOnly.html \ + // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ + // 'This is supported on Unix and ARM only.' + // @count - '//*[@class="stab portability"]' 2 + #[doc(cfg(target_arch = "arm"))] + pub trait ArmOnly { + fn unix_and_arm_only_function(); + } + + impl ArmOnly for super::Portable { + fn unix_and_arm_only_function() {} + } +} \ No newline at end of file From b4114ebe3a19d7d9bdacf700cc67bd2709eafe5b Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 5 Aug 2017 14:39:46 +0800 Subject: [PATCH 15/88] Exposed all platform-specific documentation. --- src/libstd/lib.rs | 1 + src/libstd/os/mod.rs | 42 +++++++++++++++++++------------ src/libstd/sys/mod.rs | 30 ++++++++++++++++++++++ src/libstd/sys/redox/ext/mod.rs | 1 + src/libstd/sys/unix/ext/mod.rs | 1 + src/libstd/sys/unix/mod.rs | 29 ++++++++++----------- src/libstd/sys/windows/ext/mod.rs | 1 + 7 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bd9c9c747848..cc24b7937c0e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -314,6 +314,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] +#![feature(doc_cfg)] #![cfg_attr(test, feature(update_panic_count))] #![default_lib_allocator] diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index e45af8670558..72eed549f62a 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -13,26 +13,36 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, bad_style, missing_debug_implementations)] -#[cfg(any(target_os = "redox", unix))] +#[cfg(all(not(dox), any(target_os = "redox", unix)))] #[stable(feature = "rust1", since = "1.0.0")] pub use sys::ext as unix; -#[cfg(windows)] +#[cfg(all(not(dox), windows))] #[stable(feature = "rust1", since = "1.0.0")] pub use sys::ext as windows; -#[cfg(target_os = "android")] pub mod android; -#[cfg(target_os = "bitrig")] pub mod bitrig; -#[cfg(target_os = "dragonfly")] pub mod dragonfly; -#[cfg(target_os = "freebsd")] pub mod freebsd; -#[cfg(target_os = "haiku")] pub mod haiku; -#[cfg(target_os = "ios")] pub mod ios; -#[cfg(target_os = "linux")] pub mod linux; -#[cfg(target_os = "macos")] pub mod macos; -#[cfg(target_os = "nacl")] pub mod nacl; -#[cfg(target_os = "netbsd")] pub mod netbsd; -#[cfg(target_os = "openbsd")] pub mod openbsd; -#[cfg(target_os = "solaris")] pub mod solaris; -#[cfg(target_os = "emscripten")] pub mod emscripten; -#[cfg(target_os = "fuchsia")] pub mod fuchsia; +#[cfg(dox)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use sys::unix_ext as unix; +#[cfg(dox)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use sys::windows_ext as windows; + +#[cfg(any(dox, target_os = "linux"))] +#[doc(cfg(target_os = "linux"))] +pub mod linux; + +#[cfg(all(not(dox), target_os = "android"))] pub mod android; +#[cfg(all(not(dox), target_os = "bitrig"))] pub mod bitrig; +#[cfg(all(not(dox), target_os = "dragonfly"))] pub mod dragonfly; +#[cfg(all(not(dox), target_os = "freebsd"))] pub mod freebsd; +#[cfg(all(not(dox), target_os = "haiku"))] pub mod haiku; +#[cfg(all(not(dox), target_os = "ios"))] pub mod ios; +#[cfg(all(not(dox), target_os = "macos"))] pub mod macos; +#[cfg(all(not(dox), target_os = "nacl"))] pub mod nacl; +#[cfg(all(not(dox), target_os = "netbsd"))] pub mod netbsd; +#[cfg(all(not(dox), target_os = "openbsd"))] pub mod openbsd; +#[cfg(all(not(dox), target_os = "solaris"))] pub mod solaris; +#[cfg(all(not(dox), target_os = "emscripten"))] pub mod emscripten; +#[cfg(all(not(dox), target_os = "fuchsia"))] pub mod fuchsia; pub mod raw; diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index ef4dc365dbef..d91c2073a23a 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -45,3 +45,33 @@ mod imp; #[cfg(target_os = "redox")] #[path = "redox/mod.rs"] mod imp; + + +// Import essential modules from both platforms when documenting. + +#[cfg(all(dox, not(unix)))] +use os::linux as platform; + +#[cfg(all(dox, not(any(unix, target_os = "redox"))))] +#[path = "unix/ext/mod.rs"] +pub mod unix_ext; + +#[cfg(all(dox, any(unix, target_os = "redox")))] +pub use self::ext as unix_ext; + + +#[cfg(all(dox, not(windows)))] +#[macro_use] +#[path = "windows/compat.rs"] +mod compat; + +#[cfg(all(dox, not(windows)))] +#[path = "windows/c.rs"] +mod c; + +#[cfg(all(dox, not(windows)))] +#[path = "windows/ext/mod.rs"] +pub mod windows_ext; + +#[cfg(all(dox, windows))] +pub use self::ext as windows_ext; diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs index 0c1bf9e95576..259cda5bcb3e 100644 --- a/src/libstd/sys/redox/ext/mod.rs +++ b/src/libstd/sys/redox/ext/mod.rs @@ -28,6 +28,7 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] +#![doc(cfg(target_os = "redox"))] pub mod ffi; pub mod fs; diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index 1be9f11b92c7..67fe46cc9c7a 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -28,6 +28,7 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] +#![doc(cfg(unix))] pub mod io; pub mod ffi; diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 46e5acdf3d22..4393aedf162a 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -13,20 +13,21 @@ use io::{self, ErrorKind}; use libc; -#[cfg(target_os = "android")] pub use os::android as platform; -#[cfg(target_os = "bitrig")] pub use os::bitrig as platform; -#[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform; -#[cfg(target_os = "freebsd")] pub use os::freebsd as platform; -#[cfg(target_os = "haiku")] pub use os::haiku as platform; -#[cfg(target_os = "ios")] pub use os::ios as platform; -#[cfg(target_os = "linux")] pub use os::linux as platform; -#[cfg(target_os = "macos")] pub use os::macos as platform; -#[cfg(target_os = "nacl")] pub use os::nacl as platform; -#[cfg(target_os = "netbsd")] pub use os::netbsd as platform; -#[cfg(target_os = "openbsd")] pub use os::openbsd as platform; -#[cfg(target_os = "solaris")] pub use os::solaris as platform; -#[cfg(target_os = "emscripten")] pub use os::emscripten as platform; -#[cfg(target_os = "fuchsia")] pub use os::fuchsia as platform; +#[cfg(any(dox, target_os = "linux"))] pub use os::linux as platform; + +#[cfg(all(not(dox), target_os = "android"))] pub use os::android as platform; +#[cfg(all(not(dox), target_os = "bitrig"))] pub use os::bitrig as platform; +#[cfg(all(not(dox), target_os = "dragonfly"))] pub use os::dragonfly as platform; +#[cfg(all(not(dox), target_os = "freebsd"))] pub use os::freebsd as platform; +#[cfg(all(not(dox), target_os = "haiku"))] pub use os::haiku as platform; +#[cfg(all(not(dox), target_os = "ios"))] pub use os::ios as platform; +#[cfg(all(not(dox), target_os = "macos"))] pub use os::macos as platform; +#[cfg(all(not(dox), target_os = "nacl"))] pub use os::nacl as platform; +#[cfg(all(not(dox), target_os = "netbsd"))] pub use os::netbsd as platform; +#[cfg(all(not(dox), target_os = "openbsd"))] pub use os::openbsd as platform; +#[cfg(all(not(dox), target_os = "solaris"))] pub use os::solaris as platform; +#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform; +#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform; #[macro_use] pub mod weak; diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index 11b1337a8aec..4b458d293bce 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -17,6 +17,7 @@ //! platform-agnostic idioms would not normally support. #![stable(feature = "rust1", since = "1.0.0")] +#![doc(cfg(windows))] pub mod ffi; pub mod fs; From 177cbe01bee8cd7ee0929253b5cab0e8f5df0ce1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 1 Aug 2017 14:30:46 +1200 Subject: [PATCH 16/88] Some tidying up around include! --- src/libsyntax/ext/source_util.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 3cdd3a4b2c31..4d385d5e9eef 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -183,13 +183,14 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke // resolve a file-system path to an absolute file-system path (if it // isn't already) fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf { - // NB: relative paths are resolved relative to the compilation unit + // Relative paths are resolved relative to the file in which they are found + // after macro expansion (that is, they are unhygienic). if !arg.is_absolute() { let callsite = sp.source_callsite(); - let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite)); - cu.pop(); - cu.push(arg); - cu + let mut path = PathBuf::from(&cx.codemap().span_to_filename(callsite)); + path.pop(); + path.push(arg); + path } else { arg.to_path_buf() } From 6d736df76bb37e019728cea50a4902c23fb09e1b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 10 Aug 2017 17:19:58 +1200 Subject: [PATCH 17/88] doc tests: use the filename from the source file for doc test programs, rather than a dummy name --- src/librustdoc/html/markdown.rs | 8 +++--- src/librustdoc/test.rs | 46 ++++++++++++++++++--------------- src/test/rustdoc/issue-43153.rs | 20 ++++++++++++++ 3 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 src/test/rustdoc/issue-43153.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 03da451fd9a0..4b40ee76b4bf 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -191,8 +191,8 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { .map(|l| map_line(l).for_code()) .collect::>().join("\n"); let krate = krate.as_ref().map(|s| &**s); - let test = test::maketest(&test, krate, false, - &Default::default()); + let test = test::make_test(&test, krate, false, + &Default::default()); let channel = if test.contains("#![feature(") { "&version=nightly" } else { @@ -585,8 +585,8 @@ pub fn render(w: &mut fmt::Formatter, .map(|l| map_line(l).for_code()) .collect::>().join("\n"); let krate = krate.as_ref().map(|s| &**s); - let test = test::maketest(&test, krate, false, - &Default::default()); + let test = test::make_test(&test, krate, false, + &Default::default()); let channel = if test.contains("#![feature(") { "&version=nightly" } else { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index f012fd974b57..247789726fc6 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -167,16 +167,16 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { opts } -fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, - externs: Externs, - should_panic: bool, no_run: bool, as_test_harness: bool, - compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option) { +fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec, libs: SearchPaths, + externs: Externs, + should_panic: bool, no_run: bool, as_test_harness: bool, + compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, + maybe_sysroot: Option) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` - let test = maketest(test, Some(cratename), as_test_harness, opts); + let test = make_test(test, Some(cratename), as_test_harness, opts); let input = config::Input::Str { - name: driver::anon_src(), + name: filename.to_owned(), input: test.to_owned(), }; let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); @@ -313,8 +313,11 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } } -pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, - opts: &TestOptions) -> String { +pub fn make_test(s: &str, + cratename: Option<&str>, + dont_insert_main: bool, + opts: &TestOptions) + -> String { let (crate_attrs, everything_else) = partition_source(s); let mut prog = String::new(); @@ -498,18 +501,19 @@ impl Collector { rustc_driver::in_rustc_thread(move || { io::set_panic(panic); io::set_print(print); - runtest(&test, - &cratename, - cfgs, - libs, - externs, - should_panic, - no_run, - as_test_harness, - compile_fail, - error_codes, - &opts, - maybe_sysroot) + run_test(&test, + &cratename, + &filename, + cfgs, + libs, + externs, + should_panic, + no_run, + as_test_harness, + compile_fail, + error_codes, + &opts, + maybe_sysroot) }) } { Ok(()) => (), diff --git a/src/test/rustdoc/issue-43153.rs b/src/test/rustdoc/issue-43153.rs new file mode 100644 index 000000000000..6ac341d8b022 --- /dev/null +++ b/src/test/rustdoc/issue-43153.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. + +// Test that `include!` in a doc test searches relative to the directory in +// which the test is declared. + +// compile-flags:--test + +/// ```rust +/// include!("auxiliary/empty.rs"); +/// fn main() {} +/// ``` +pub struct Foo; From 99e943c8b84cf2b077223271e4af7981b25f9064 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 10 Aug 2017 17:53:36 -0400 Subject: [PATCH 18/88] Document the doc attribute cc #42322 --- src/doc/rustdoc/src/SUMMARY.md | 2 +- src/doc/rustdoc/src/in-source-directives.md | 3 - src/doc/rustdoc/src/the-doc-attribute.md | 108 ++++++++++++++++++++ 3 files changed, 109 insertions(+), 4 deletions(-) delete mode 100644 src/doc/rustdoc/src/in-source-directives.md create mode 100644 src/doc/rustdoc/src/the-doc-attribute.md diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index cd6883a719c1..1049cc4284a0 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -2,7 +2,7 @@ - [What is rustdoc?](what-is-rustdoc.md) - [Command-line arguments](command-line-arguments.md) -- [In-source directives](in-source-directives.md) +- [The `#[doc]` attribute](the-doc-attribute.md) - [Documentation tests](documentation-tests.md) - [Plugins](plugins.md) - [Passes](passes.md) \ No newline at end of file diff --git a/src/doc/rustdoc/src/in-source-directives.md b/src/doc/rustdoc/src/in-source-directives.md deleted file mode 100644 index 83f677fa7f4c..000000000000 --- a/src/doc/rustdoc/src/in-source-directives.md +++ /dev/null @@ -1,3 +0,0 @@ -# In-source directives - -Coming soon! \ No newline at end of file diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md new file mode 100644 index 000000000000..18a1814938a0 --- /dev/null +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -0,0 +1,108 @@ +# The `#[doc]` attribute + +The `#[doc]` attribute lets you control various aspects of how `rustdoc` does +its job. + +The most basic job of `#[doc]` is to be the way that the text of the documentation +is handled. That is, `///` is syntax sugar for `#[doc]`. This means that these two +are the same: + +```rust,ignore +/// This is a doc comment. +#[doc = "This is a doc comment."] +``` + +In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is +when generating documentation in macros; the `collapse-docs` pass will combine multiple +`#[doc]` attributes into a single doc comment, letting you generate code like this: + +```rust,ignore +#[doc = "This is"] +#[doc = " a "] +#[doc = "doc comment"] +``` + +Which can feel more flexible. + +The `doc` attribute has more options though! These don't involve the text of +the output, but instead, various aspects of the presentation of the output. +We've split them into two kinds below: attributes that are useful at the +crate level, and ones that are useful at the item level. + +## At the crate level + +These options control how the docs look at a macro level. + +### `html_favicon_url` + +This form of the `doc` attribute lets you control the favicon of your docs. + +```rust,ignore +#![doc(html_favicon_url = "https://foo.com/favicon.ico")] +``` + +This will put `` into your docs, where +the string for the attribute goes into the `{}`. + +### `html_logo_url` + +This form of the `doc` attribute lets you control the logo in the upper +left hand side of the docs. + +```rust,ignore +#![doc(html_logo_url = "https://foo.com/logo.jpg")] +``` + +This will put `logo` into +your docs, where the string for the attribute goes into the `{}`. + +### `html_playground_url` + +This form of the `doc` attribute lets you control where the "run" buttons +on your documentation examples make requests to. + +```rust,ignore +#![doc(html_playground_url = "https://playground.foo.com/")] +``` + +Now, when you press "run", the button will make a request to this domain. + +### `issue_tracker_base_url` + +This form of the `doc` attribute is mostly only useful for the standard library; +When a feature is unstable, an issue number for tracking the feature must be +given. `rustdoc` uses this number, plus the base URL given here, to link to +the tracking issue. + +```rust,ignore +#![doc(issue_tracker_base_url = "https://github.com/foo/foo/issues/")] +``` + +### `html_no_source` + +By default, `rustdoc` will include the source code of your program, with links +to it in the docs. But if you include this: + +```rust,ignore +#![doc(html_no_source)] +``` + +it will not. + +## At the item level + +These forms of the `#[doc]` attribute are used on individual items, to control how +they are documented. + +## `#[doc(no_inline)]` + +## `#[doc(hidden)]` + +Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless +the `strip-hidden` pass is removed. + +## `#[doc(primitive)]` + +Since primitive types are defined in the compiler, there's no place to attach documentation +attributes. This attribute is used by the standard library to provide a way to generate +documentation for primitive types. \ No newline at end of file From 47cb3c5bc28e1bb2ac2d2efb7796ceb17b4ab7de Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Fri, 11 Aug 2017 00:16:18 +0200 Subject: [PATCH 19/88] Fix some typos --- src/liballoc/allocator.rs | 2 +- src/liballoc/btree/node.rs | 4 ++-- src/libcore/iter/mod.rs | 2 +- src/libcore/iter/traits.rs | 2 +- src/libcore/num/dec2flt/algorithm.rs | 2 +- src/libcore/tests/num/mod.rs | 2 +- src/librustc/traits/specialize/specialization_graph.rs | 2 +- src/librustc/ty/adjustment.rs | 4 ++-- src/librustc_data_structures/stable_hasher.rs | 2 +- src/librustc_mir/dataflow/impls/mod.rs | 2 +- src/librustc_mir/hair/mod.rs | 2 +- src/librustc_trans/base.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/constrained_type_params.rs | 2 +- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustdoc/clean/inline.rs | 2 +- src/libstd/panic.rs | 2 +- src/libstd/sys/redox/syscall/call.rs | 4 ++-- src/libstd/thread/mod.rs | 2 +- src/libsyntax/attr.rs | 2 +- src/libsyntax/parse/mod.rs | 2 +- 21 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index 42111301a9fe..3ea7d349c9cd 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -40,7 +40,7 @@ fn size_align() -> (usize, usize) { /// /// (Note however that layouts are *not* required to have positive /// size, even though many allocators require that all memory -/// requeusts have positive size. A caller to the `Alloc::alloc` +/// requests have positive size. A caller to the `Alloc::alloc` /// method must either ensure that conditions like this are met, or /// use specific allocators with looser requirements.) #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 06d3a113b947..7fe33c20e4f2 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -132,7 +132,7 @@ impl InternalNode { /// An owned pointer to a node. This basically is either `Box>` or /// `Box>`. However, it contains no information as to which of the two types -/// of nodes is acutally behind the box, and, partially due to this lack of information, has no +/// of nodes is actually behind the box, and, partially due to this lack of information, has no /// destructor. struct BoxedNode { ptr: Unique> @@ -264,7 +264,7 @@ impl Root { // correct variance. /// A reference to a node. /// -/// This type has a number of paramaters that controls how it acts: +/// This type has a number of parameters that controls how it acts: /// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`. /// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`, /// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`, diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 79e6b11beaca..22b997a768e6 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -1035,7 +1035,7 @@ unsafe impl TrustedLen for Zip /// Now consider this twist where we add a call to `rev`. This version will /// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, /// but the values of the counter still go in order. This is because `map()` is -/// still being called lazilly on each item, but we are popping items off the +/// still being called lazily on each item, but we are popping items off the /// back of the vector now, instead of shifting them from the front. /// /// ```rust diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index ccfeb91aff14..19098f036acd 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -345,7 +345,7 @@ pub trait Extend { /// In a similar fashion to the [`Iterator`] protocol, once a /// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again /// may or may not ever return `Some` again. `next()` and `next_back()` are -/// interchangable for this purpose. +/// interchangeable for this purpose. /// /// [`Iterator`]: trait.Iterator.html /// diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 42bc46c0c683..ccf3950c2ba3 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -336,7 +336,7 @@ pub fn algorithm_m(f: &Big, e: i16) -> T { round_by_remainder(v, rem, q, z) } -/// Skip over most AlgorithmM iterations by checking the bit length. +/// Skip over most Algorithm M iterations by checking the bit length. fn quick_start(u: &mut Big, v: &mut Big, k: &mut i16) { // The bit length is an estimate of the base two logarithm, and log(u / v) = log(u) - log(v). // The estimate is off by at most 1, but always an under-estimate, so the error on log(u) diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 046b81e19f70..400d53ce51a0 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -566,7 +566,7 @@ assume_usize_width! { ); } -/// Conversinos where neither the min nor the max of $source can be represented by +/// Conversions where neither the min nor the max of $source can be represented by /// $target, but max/min of the target can be represented by the source. macro_rules! test_impl_try_from_signed_to_unsigned_err { ($fn_name:ident, $source:ty, $target:ty) => { diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index f80caeec460f..611137562a90 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -31,7 +31,7 @@ use util::nodemap::{DefIdMap, FxHashMap}; /// /// - Parent extraction. In particular, the graph can give you the *immediate* /// parents of a given specializing impl, which is needed for extracting -/// default items amongst other thigns. In the simple "chain" rule, every impl +/// default items amongst other things. In the simple "chain" rule, every impl /// has at most one parent. pub struct Graph { // all impls have a parent; the "root" impls have as their parent the def_id diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 62d137475f90..514366607795 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -29,7 +29,7 @@ use ty::subst::Substs; /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is /// `false`. /// -/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start +/// 2. A thin-to-fat coercion involves unsizing the underlying data. We start /// with a thin pointer, deref a number of times, unsize the underlying data, /// then autoref. The 'unsize' phase may change a fixed length array to a /// dynamically sized one, a concrete object to a trait object, or statically @@ -52,7 +52,7 @@ use ty::subst::Substs; /// that case, we have the pointer we need coming in, so there are no /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. /// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> +/// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> -> /// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Adjustment<'tcx> { diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 5e291ea3c152..6801aa455e11 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -193,7 +193,7 @@ impl Hasher for StableHasher { /// Something that implements `HashStable` can be hashed in a way that is -/// stable across multiple compiliation sessions. +/// stable across multiple compilation sessions. pub trait HashStable { fn hash_stable(&self, hcx: &mut CTX, diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index d5bdc71a705c..e05a5a7341fd 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedLvals<'a, 'tcx> { /// you if an l-value *might* be uninitialized at a given point in the /// control flow. But `MovingOutStatements` also includes the added /// data of *which* particular statement causing the deinitialization -/// that the borrow checker's error meessage may need to report. +/// that the borrow checker's error message may need to report. #[allow(dead_code)] pub struct MovingOutStatements<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index bb11cce74875..e32de6b9768a 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -80,7 +80,7 @@ pub enum StmtKind<'tcx> { /// The Hair trait implementor translates their expressions (`&'tcx H::Expr`) /// into instances of this `Expr` enum. This translation can be done -/// basically as lazilly or as eagerly as desired: every recursive +/// basically as lazily or as eagerly as desired: every recursive /// reference to an expression in this enum is an `ExprRef<'tcx>`, which /// may in turn be another instance of this enum (boxed), or else an /// untranslated `&'tcx H::Expr`. Note that instances of `Expr` are very diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index e8032529b1fe..3734e91d8c24 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -191,7 +191,7 @@ pub fn compare_simd_types<'a, 'tcx>( /// adjustment. /// /// The `old_info` argument is a bit funny. It is intended for use -/// in an upcast, where the new vtable for an object will be drived +/// in an upcast, where the new vtable for an object will be derived /// from the old one. pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, source: Ty<'tcx>, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index ed22cd1333e9..72ff9eb6f5b0 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -22,7 +22,7 @@ use util::nodemap::FxHashSet; use syntax_pos::Span; -/// check_drop_impl confirms that the Drop implementation identfied by +/// check_drop_impl confirms that the Drop implementation identified by /// `drop_impl_did` is not any more specialized than the type it is /// attached to (Issue #8142). /// diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 7742194dfe6e..37cb1f9280b6 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -98,7 +98,7 @@ pub fn identify_constrained_type_params<'tcx>(tcx: ty::TyCtxt, /// Order the predicates in `predicates` such that each parameter is /// constrained before it is used, if that is possible, and add the -/// paramaters so constrained to `input_parameters`. For example, +/// parameters so constrained to `input_parameters`. For example, /// imagine the following impl: /// /// impl> Trait for U diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 284c9c5cfc39..4b0db749964c 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -51,7 +51,7 @@ pub struct Constraint<'a> { pub variance: &'a VarianceTerm<'a>, } -/// To build constriants, we visit one item (type, trait) at a time +/// To build constraints, we visit one item (type, trait) at a time /// and look at its contents. So e.g. if we have /// /// struct Foo { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index fa5a999adf19..9b4c4e479d04 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -495,7 +495,7 @@ fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { /// A trait's generics clause actually contains all of the predicates for all of /// its associated types as well. We specifically move these clauses to the -/// associated types instead when displaying, so when we're genering the +/// associated types instead when displaying, so when we're generating the /// generics for the trait itself we need to be sure to remove them. /// We also need to remove the implied "recursive" Self: Trait bound. /// diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 58356bc43eeb..10b3209257ef 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -37,7 +37,7 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location}; /// In Rust a function can "return" early if it either panics or calls a /// function which transitively panics. This sort of control flow is not always /// anticipated, and has the possibility of causing subtle bugs through a -/// combination of two cricial components: +/// combination of two criticial components: /// /// 1. A data structure is in a temporarily invalid state when the thread /// panics. diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs index ec9005c2cc3b..9fc809eb821d 100644 --- a/src/libstd/sys/redox/syscall/call.rs +++ b/src/libstd/sys/redox/syscall/call.rs @@ -40,7 +40,7 @@ pub unsafe fn brk(addr: usize) -> Result { /// /// * `EACCES` - permission is denied for one of the components of `path`, or `path` /// * `EFAULT` - `path` does not point to the process's addressible memory -/// * `EIO` - an I/O error occured +/// * `EIO` - an I/O error occurred /// * `ENOENT` - `path` does not exit /// * `ENOTDIR` - `path` is not a directory pub fn chdir(path: &str) -> Result { @@ -290,7 +290,7 @@ pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result /// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block /// * `EBADF` - the file descriptor is not valid or is not open for writing /// * `EFAULT` - `buf` does not point to the process's addressible memory -/// * `EIO` - an I/O error occured +/// * `EIO` - an I/O error occurred /// * `ENOSPC` - the device containing the file descriptor has no room for data /// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed pub fn write(fd: usize, buf: &[u8]) -> Result { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index cbd019c2c0e6..80eb8ba93f75 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -531,7 +531,7 @@ pub fn current() -> Thread { /// /// However programmers will usually prefer to use, [`channel`]s, [`Condvar`]s, /// [`Mutex`]es or [`join`] for their synchronisation routines, as they avoid -/// thinking about thread schedulling. +/// thinking about thread scheduling. /// /// Note that [`channel`]s for example are implemented using this primitive. /// Indeed when you call `send` or `recv`, which are blocking, they will yield diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index a247fe7f8a56..d5caf458fd76 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -435,7 +435,7 @@ pub fn mk_attr_inner(span: Span, id: AttrId, item: MetaItem) -> Attribute { mk_spanned_attr_inner(span, id, item) } -/// Returns an innter attribute with the given value and span. +/// Returns an inner attribute with the given value and span. pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute { Attribute { id: id, diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 893bada2670d..957164bab79a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -124,7 +124,7 @@ pub fn parse_expr_from_source_str(name: String, source: String, sess: &ParseSess /// Parses an item. /// -/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and`Err` +/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err` /// when a syntax error occurred. pub fn parse_item_from_source_str(name: String, source: String, sess: &ParseSess) -> PResult>> { From ea5be96bab45a68d5877acdfab88404df7376209 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Fri, 11 Aug 2017 00:31:47 +0200 Subject: [PATCH 20/88] Fix some more typos, this time words that are duplicated. --- src/libcore/ops/unsize.rs | 2 +- src/libproc_macro/lib.rs | 2 +- src/librustc_driver/driver.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs index 1914216e9f08..58da290cfb69 100644 --- a/src/libcore/ops/unsize.rs +++ b/src/libcore/ops/unsize.rs @@ -24,7 +24,7 @@ use marker::Unsize; /// Such an impl can only be written if `Foo` has only a single non-phantomdata /// field involving `T`. If the type of that field is `Bar`, an implementation /// of `CoerceUnsized> for Bar` must exist. The coercion will work by -/// by coercing the `Bar` field into `Bar` and filling in the rest of the fields +/// coercing the `Bar` field into `Bar` and filling in the rest of the fields /// from `Foo` to create a `Foo`. This will effectively drill down to a pointer /// field and coerce that. /// diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 1bffffd6c9e7..6a71e67676ae 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -111,7 +111,7 @@ impl fmt::Display for TokenStream { /// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input. /// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs -/// constructs the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`. +/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`. /// /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 22f98454f6c4..eb233aa203ab 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -282,7 +282,7 @@ pub fn source_name(input: &Input) -> String { /// This is a somewhat higher level controller than a Session - the Session /// controls what happens in each phase, whereas the CompileController controls /// whether a phase is run at all and whether other code (from outside the -/// the compiler) is run between phases. +/// compiler) is run between phases. /// /// Note that if compilation is set to stop and a callback is provided for a /// given entry point, the callback is called before compilation is stopped. From bc9e0820e74333b0f578d63939c9ab25bc196a1e Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 10 Aug 2017 18:52:10 -0400 Subject: [PATCH 21/88] doc doc(inline) and doc(no_inline) --- src/doc/rustdoc/src/the-doc-attribute.md | 58 +++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 18a1814938a0..013eccab04eb 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -94,7 +94,63 @@ it will not. These forms of the `#[doc]` attribute are used on individual items, to control how they are documented. -## `#[doc(no_inline)]` +## `#[doc(no_inline)]`/`#[doc(inline)]` + +These attributes are used on `use` statements, and control where the documentation shows +up. For example, consider this Rust code: + +```rust +pub use bar::Bar; + +/// bar docs +pub mod bar { + /// the docs for Bar + pub struct Bar; +} +``` + +The documentation will generate a "Reexports" section, and say `pub use bar::Bar;`, where +`Bar` is a link to its page. + +If we change the `use` line like this: + +```rust,ignore +#[doc(inline)] +pub use bar::Bar; +``` + +Instead, `Bar` will appear in a `Structs` section, just like `Bar` was defined at the +top level, rather than `pub use`'d. + +Let's change our original example, by making `bar` private: + +```rust +pub use bar::Bar; + +/// bar docs +mod bar { + /// the docs for Bar + pub struct Bar; +} +``` + +Here, because `bar` is not public, `Bar` wouldn't have its own page, so there's nowhere +to link to. `rustdoc` will inline these definitions, and so we end up in the same case +as the `#[doc(inline)]` above; `Bar` is in a `Structs` section, as if it were defined at +the top level. If we add the `no_inline` form of the attribute: + +```rust +#[doc(no_inline)] +pub use bar::Bar; + +/// bar docs +mod bar { + /// the docs for Bar + pub struct Bar; +} +``` + +Now we'll have a `Reexports` line, and `Bar` will not link to anywhere. ## `#[doc(hidden)]` From 640cf596ec1eb6efb30232df6222d927d814bffb Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 10 Aug 2017 18:59:51 -0400 Subject: [PATCH 22/88] review feedback --- src/doc/rustdoc/src/the-doc-attribute.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 013eccab04eb..0b14f44b63e8 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -3,15 +3,17 @@ The `#[doc]` attribute lets you control various aspects of how `rustdoc` does its job. -The most basic job of `#[doc]` is to be the way that the text of the documentation -is handled. That is, `///` is syntax sugar for `#[doc]`. This means that these two +The most basic function of `#[doc]` is to handle the actual documentation +text. That is, `///` is syntax sugar for `#[doc]`. This means that these two are the same: ```rust,ignore /// This is a doc comment. -#[doc = "This is a doc comment."] +#[doc = " This is a doc comment."] ``` +(Note the leading space in the attribute version.) + In most cases, `///` is easier to use than `#[doc]`. One case where the latter is easier is when generating documentation in macros; the `collapse-docs` pass will combine multiple `#[doc]` attributes into a single doc comment, letting you generate code like this: @@ -22,7 +24,13 @@ when generating documentation in macros; the `collapse-docs` pass will combine m #[doc = "doc comment"] ``` -Which can feel more flexible. +Which can feel more flexible. Note that this would generate this: + +```rust,ignore +#[doc = "This is\n a \ndoc comment"] +``` + +but given that docs are rendered via Markdown, it will remove these newlines. The `doc` attribute has more options though! These don't involve the text of the output, but instead, various aspects of the presentation of the output. From 92f84424345c72ab5d7b13e931d09d62f8543038 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Thu, 10 Aug 2017 20:17:41 -0400 Subject: [PATCH 23/88] ignore more things --- src/doc/rustdoc/src/the-doc-attribute.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 0b14f44b63e8..b77565ec2d71 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -107,7 +107,7 @@ they are documented. These attributes are used on `use` statements, and control where the documentation shows up. For example, consider this Rust code: -```rust +```rust,ignore pub use bar::Bar; /// bar docs @@ -132,7 +132,7 @@ top level, rather than `pub use`'d. Let's change our original example, by making `bar` private: -```rust +```rust,ignore pub use bar::Bar; /// bar docs @@ -147,7 +147,7 @@ to link to. `rustdoc` will inline these definitions, and so we end up in the sam as the `#[doc(inline)]` above; `Bar` is in a `Structs` section, as if it were defined at the top level. If we add the `no_inline` form of the attribute: -```rust +```rust,ignore #[doc(no_inline)] pub use bar::Bar; @@ -169,4 +169,4 @@ the `strip-hidden` pass is removed. Since primitive types are defined in the compiler, there's no place to attach documentation attributes. This attribute is used by the standard library to provide a way to generate -documentation for primitive types. \ No newline at end of file +documentation for primitive types. From 783ccc443b88884a10eed564e0fdc3c1e6f974a4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 4 Aug 2017 09:49:40 +0200 Subject: [PATCH 24/88] Make TypeckTables::type_dependent_defs use ItemLocalId instead of NodeId. --- src/librustc/hir/def_id.rs | 7 + src/librustc/hir/lowering.rs | 177 +++++++++++++------- src/librustc/hir/map/definitions.rs | 4 + src/librustc/hir/map/mod.rs | 9 + src/librustc/hir/mod.rs | 8 +- src/librustc/ich/impls_hir.rs | 6 +- src/librustc/ich/impls_ty.rs | 5 +- src/librustc/infer/mod.rs | 4 +- src/librustc/lint/context.rs | 4 +- src/librustc/middle/dead.rs | 12 +- src/librustc/middle/effect.rs | 5 +- src/librustc/middle/expr_use_visitor.rs | 4 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/mem_categorization.rs | 6 +- src/librustc/middle/reachable.rs | 6 +- src/librustc/ty/context.rs | 46 ++++- src/librustc/util/nodemap.rs | 3 + src/librustc_const_eval/eval.rs | 2 +- src/librustc_const_eval/pattern.rs | 16 +- src/librustc_data_structures/indexed_vec.rs | 10 ++ src/librustc_driver/pretty.rs | 3 +- src/librustc_lint/builtin.rs | 9 +- src/librustc_mir/hair/cx/expr.rs | 5 +- src/librustc_passes/consts.rs | 9 +- src/librustc_privacy/lib.rs | 69 +++++++- src/librustc_save_analysis/lib.rs | 8 +- src/librustc_typeck/check/callee.rs | 7 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/mod.rs | 48 ++++-- src/librustc_typeck/check/op.rs | 4 +- src/librustc_typeck/check/writeback.rs | 39 +++-- 31 files changed, 387 insertions(+), 152 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 7f76e1bf770b..bb3b248674ab 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -201,4 +201,11 @@ impl DefId { pub fn is_local(&self) -> bool { self.krate == LOCAL_CRATE } + + pub fn invalid() -> DefId { + DefId { + krate: INVALID_CRATE, + index: CRATE_DEF_INDEX, + } + } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 421a81c0d234..27048a71454b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -155,6 +155,11 @@ enum ParamMode { Optional } +struct LoweredNodeId { + node_id: NodeId, + hir_id: hir::HirId, +} + impl<'a> LoweringContext<'a> { fn lower_crate(mut self, c: &Crate) -> hir::Crate { /// Full-crate AST visitor that inserts into a fresh @@ -278,11 +283,14 @@ impl<'a> LoweringContext<'a> { fn lower_node_id_generic(&mut self, ast_node_id: NodeId, alloc_hir_id: F) - -> NodeId + -> LoweredNodeId where F: FnOnce(&mut Self) -> hir::HirId { if ast_node_id == DUMMY_NODE_ID { - return ast_node_id; + return LoweredNodeId { + node_id: DUMMY_NODE_ID, + hir_id: hir::DUMMY_HIR_ID, + } } let min_size = ast_node_id.as_usize() + 1; @@ -291,12 +299,22 @@ impl<'a> LoweringContext<'a> { self.node_id_to_hir_id.resize(min_size, hir::DUMMY_HIR_ID); } - if self.node_id_to_hir_id[ast_node_id] == hir::DUMMY_HIR_ID { - // Generate a new HirId - self.node_id_to_hir_id[ast_node_id] = alloc_hir_id(self); - } + let existing_hir_id = self.node_id_to_hir_id[ast_node_id]; - ast_node_id + if existing_hir_id == hir::DUMMY_HIR_ID { + // Generate a new HirId + let hir_id = alloc_hir_id(self); + self.node_id_to_hir_id[ast_node_id] = hir_id; + LoweredNodeId { + node_id: ast_node_id, + hir_id, + } + } else { + LoweredNodeId { + node_id: ast_node_id, + hir_id: existing_hir_id, + } + } } fn with_hir_id_owner(&mut self, owner: NodeId, f: F) @@ -323,7 +341,7 @@ impl<'a> LoweringContext<'a> { /// actually used in the HIR, as that would trigger an assertion in the /// HirIdValidator later on, which makes sure that all NodeIds got mapped /// properly. Calling the method twice with the same NodeId is fine though. - fn lower_node_id(&mut self, ast_node_id: NodeId) -> NodeId { + fn lower_node_id(&mut self, ast_node_id: NodeId) -> LoweredNodeId { self.lower_node_id_generic(ast_node_id, |this| { let &mut (def_index, ref mut local_id_counter) = this.current_hir_id_owner .last_mut() @@ -340,7 +358,7 @@ impl<'a> LoweringContext<'a> { fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) - -> NodeId { + -> LoweredNodeId { self.lower_node_id_generic(ast_node_id, |this| { let local_id_counter = this.item_local_id_counters .get_mut(&owner) @@ -375,7 +393,7 @@ impl<'a> LoweringContext<'a> { id } - fn next_id(&mut self) -> NodeId { + fn next_id(&mut self) -> LoweredNodeId { self.lower_node_id(self.sess.next_node_id()) } @@ -517,7 +535,7 @@ impl<'a> LoweringContext<'a> { match destination { Some((id, label_ident)) => { let target = if let Def::Label(loop_id) = self.expect_full_def(id) { - hir::LoopIdResult::Ok(self.lower_node_id(loop_id)) + hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id) } else { hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel) }; @@ -534,7 +552,7 @@ impl<'a> LoweringContext<'a> { hir::Destination { ident: None, target_id: hir::ScopeTarget::Loop( - loop_id.map(|id| Ok(self.lower_node_id(id))) + loop_id.map(|id| Ok(self.lower_node_id(id).node_id)) .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) .into()) } @@ -557,7 +575,7 @@ impl<'a> LoweringContext<'a> { fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding { hir::TypeBinding { - id: self.lower_node_id(b.id), + id: self.lower_node_id(b.id).node_id, name: self.lower_ident(b.ident), ty: self.lower_ty(&b.ty), span: b.span, @@ -594,7 +612,7 @@ impl<'a> LoweringContext<'a> { return self.lower_ty(ty); } TyKind::Path(ref qself, ref path) => { - let id = self.lower_node_id(t.id); + let id = self.lower_node_id(t.id).node_id; let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); return self.ty_path(id, t.span, qpath); } @@ -645,7 +663,7 @@ impl<'a> LoweringContext<'a> { }; P(hir::Ty { - id: self.lower_node_id(t.id), + id: self.lower_node_id(t.id).node_id, node: kind, span: t.span, }) @@ -758,7 +776,7 @@ impl<'a> LoweringContext<'a> { // Otherwise, the base path is an implicit `Self` type path, // e.g. `Vec` in `Vec::new` or `::Item` in // `::Item::default`. - let new_id = self.next_id(); + let new_id = self.next_id().node_id; self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)) }; @@ -782,7 +800,7 @@ impl<'a> LoweringContext<'a> { } // Wrap the associated extension in another type node. - let new_id = self.next_id(); + let new_id = self.next_id().node_id; ty = self.ty_path(new_id, p.span, qpath); } @@ -887,7 +905,7 @@ impl<'a> LoweringContext<'a> { fn lower_local(&mut self, l: &Local) -> P { P(hir::Local { - id: self.lower_node_id(l.id), + id: self.lower_node_id(l.id).node_id, ty: l.ty.as_ref().map(|t| self.lower_ty(t)), pat: self.lower_pat(&l.pat), init: l.init.as_ref().map(|e| P(self.lower_expr(e))), @@ -905,8 +923,10 @@ impl<'a> LoweringContext<'a> { } fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(arg.id); hir::Arg { - id: self.lower_node_id(arg.id), + id: node_id, + hir_id, pat: self.lower_pat(&arg.pat), } } @@ -969,7 +989,7 @@ impl<'a> LoweringContext<'a> { } hir::TyParam { - id: self.lower_node_id(tp.id), + id: self.lower_node_id(tp.id).node_id, name, bounds, default: tp.default.as_ref().map(|x| self.lower_ty(x)), @@ -987,7 +1007,7 @@ impl<'a> LoweringContext<'a> { fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { hir::Lifetime { - id: self.lower_node_id(l.id), + id: self.lower_node_id(l.id).node_id, name: self.lower_ident(l.ident), span: l.span, } @@ -1059,7 +1079,7 @@ impl<'a> LoweringContext<'a> { fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause { hir::WhereClause { - id: self.lower_node_id(wc.id), + id: self.lower_node_id(wc.id).node_id, predicates: wc.predicates .iter() .map(|predicate| self.lower_where_predicate(predicate)) @@ -1098,7 +1118,7 @@ impl<'a> LoweringContext<'a> { ref rhs_ty, span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - id: self.lower_node_id(id), + id: self.lower_node_id(id).node_id, lhs_ty: self.lower_ty(lhs_ty), rhs_ty: self.lower_ty(rhs_ty), span, @@ -1114,16 +1134,16 @@ impl<'a> LoweringContext<'a> { .enumerate() .map(|f| self.lower_struct_field(f)) .collect(), - self.lower_node_id(id)) + self.lower_node_id(id).node_id) } VariantData::Tuple(ref fields, id) => { hir::VariantData::Tuple(fields.iter() .enumerate() .map(|f| self.lower_struct_field(f)) .collect(), - self.lower_node_id(id)) + self.lower_node_id(id).node_id) } - VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id)), + VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id).node_id), } } @@ -1134,7 +1154,7 @@ impl<'a> LoweringContext<'a> { }; hir::TraitRef { path, - ref_id: self.lower_node_id(p.ref_id), + ref_id: self.lower_node_id(p.ref_id).node_id, } } @@ -1149,7 +1169,7 @@ impl<'a> LoweringContext<'a> { fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField { hir::StructField { span: f.span, - id: self.lower_node_id(f.id), + id: self.lower_node_id(f.id).node_id, name: self.lower_ident(match f.ident { Some(ident) => ident, // FIXME(jseyfried) positional field hygiene @@ -1198,8 +1218,11 @@ impl<'a> LoweringContext<'a> { } } + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(b.id); + P(hir::Block { - id: self.lower_node_id(b.id), + id: node_id, + hir_id, stmts: stmts.into(), expr, rules: self.lower_block_check_mode(&b.rules), @@ -1249,7 +1272,7 @@ impl<'a> LoweringContext<'a> { hir::Visibility::Restricted { path: path.clone(), // We are allocating a new NodeId here - id: this.next_id(), + id: this.next_id().node_id, } } }; @@ -1387,7 +1410,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { self.with_parent_def(i.id, |this| { hir::TraitItem { - id: this.lower_node_id(i.id), + id: this.lower_node_id(i.id).node_id, name: this.lower_ident(i.ident), attrs: this.lower_attrs(&i.attrs), node: match i.node { @@ -1448,7 +1471,7 @@ impl<'a> LoweringContext<'a> { fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem { self.with_parent_def(i.id, |this| { hir::ImplItem { - id: this.lower_node_id(i.id), + id: this.lower_node_id(i.id).node_id, name: this.lower_ident(i.ident), attrs: this.lower_attrs(&i.attrs), vis: this.lower_visibility(&i.vis, None), @@ -1540,7 +1563,7 @@ impl<'a> LoweringContext<'a> { }); Some(hir::Item { - id: self.lower_node_id(i.id), + id: self.lower_node_id(i.id).node_id, name, attrs, node, @@ -1552,7 +1575,7 @@ impl<'a> LoweringContext<'a> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { self.with_parent_def(i.id, |this| { hir::ForeignItem { - id: this.lower_node_id(i.id), + id: this.lower_node_id(i.id).node_id, name: i.ident.name, attrs: this.lower_attrs(&i.attrs), node: match i.node { @@ -1630,8 +1653,11 @@ impl<'a> LoweringContext<'a> { } fn lower_pat(&mut self, p: &Pat) -> P { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id); + P(hir::Pat { - id: self.lower_node_id(p.id), + id: node_id, + hir_id, node: match p.node { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, pth1, ref sub) => { @@ -1813,7 +1839,7 @@ impl<'a> LoweringContext<'a> { let call_move_val_init = hir::StmtSemi( make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), - self.next_id()); + self.next_id().node_id); let call_move_val_init = respan(e.span, call_move_val_init); let place = self.expr_ident(e.span, place_ident, place_binding); @@ -1883,11 +1909,15 @@ impl<'a> LoweringContext<'a> { // wrap the if-let expr in a block let span = els.span; let els = P(self.lower_expr(els)); - let id = self.next_id(); + let LoweredNodeId { + node_id, + hir_id, + } = self.next_id(); let blk = P(hir::Block { stmts: hir_vec![], expr: Some(els), - id, + id: node_id, + hir_id, rules: hir::DefaultBlock, span, targeted_by_break: false, @@ -1986,8 +2016,11 @@ impl<'a> LoweringContext<'a> { let struct_path = self.std_path(unstable_span, &struct_path, is_unit); let struct_path = hir::QPath::Resolved(None, P(struct_path)); + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id); + return hir::Expr { - id: self.lower_node_id(e.id), + id: node_id, + hir_id, node: if is_unit { hir::ExprPath(struct_path) } else { @@ -2234,7 +2267,7 @@ impl<'a> LoweringContext<'a> { hir::MatchSource::ForLoopDesugar), ThinVec::new())) }; - let match_stmt = respan(e.span, hir::StmtExpr(match_expr, self.next_id())); + let match_stmt = respan(e.span, hir::StmtExpr(match_expr, self.next_id().node_id)); let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id)); @@ -2254,7 +2287,7 @@ impl<'a> LoweringContext<'a> { let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); - let body_stmt = respan(e.span, hir::StmtExpr(body_expr, self.next_id())); + let body_stmt = respan(e.span, hir::StmtExpr(body_expr, self.next_id().node_id)); let loop_block = P(self.block_all(e.span, hir_vec![next_let, @@ -2266,8 +2299,10 @@ impl<'a> LoweringContext<'a> { // `[opt_ident]: loop { ... }` let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), hir::LoopSource::ForLoop); + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id); let loop_expr = P(hir::Expr { - id: self.lower_node_id(e.id), + id: node_id, + hir_id, node: loop_expr, span: e.span, attrs: ThinVec::new(), @@ -2406,8 +2441,11 @@ impl<'a> LoweringContext<'a> { ExprKind::Mac(_) => panic!("Shouldn't exist here"), }; + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id); + hir::Expr { - id: self.lower_node_id(e.id), + id: node_id, + hir_id, node: kind, span: e.span, attrs: e.attrs.clone(), @@ -2420,7 +2458,7 @@ impl<'a> LoweringContext<'a> { node: hir::StmtDecl(P(Spanned { node: hir::DeclLocal(self.lower_local(l)), span: s.span, - }), self.lower_node_id(s.id)), + }), self.lower_node_id(s.id).node_id), span: s.span, }, StmtKind::Item(ref it) => { @@ -2431,22 +2469,22 @@ impl<'a> LoweringContext<'a> { node: hir::DeclItem(item_id), span: s.span, }), id.take() - .map(|id| self.lower_node_id(id)) - .unwrap_or_else(|| self.next_id())), + .map(|id| self.lower_node_id(id).node_id) + .unwrap_or_else(|| self.next_id().node_id)), span: s.span, }).collect(); } StmtKind::Expr(ref e) => { Spanned { node: hir::StmtExpr(P(self.lower_expr(e)), - self.lower_node_id(s.id)), + self.lower_node_id(s.id).node_id), span: s.span, } } StmtKind::Semi(ref e) => { Spanned { node: hir::StmtSemi(P(self.lower_expr(e)), - self.lower_node_id(s.id)), + self.lower_node_id(s.id).node_id), span: s.span, } } @@ -2477,9 +2515,9 @@ impl<'a> LoweringContext<'a> { hir::Visibility::Restricted { path: P(self.lower_path(id, path, ParamMode::Explicit, true)), id: if let Some(owner) = explicit_owner { - self.lower_node_id_with_owner(id, owner) + self.lower_node_id_with_owner(id, owner).node_id } else { - self.lower_node_id(id) + self.lower_node_id(id).node_id } } } @@ -2621,8 +2659,10 @@ impl<'a> LoweringContext<'a> { } fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec) -> hir::Expr { + let LoweredNodeId { node_id, hir_id } = self.next_id(); hir::Expr { - id: self.next_id(), + id: node_id, + hir_id, node, span, attrs, @@ -2639,13 +2679,13 @@ impl<'a> LoweringContext<'a> { pat, ty: None, init: ex, - id: self.next_id(), + id: self.next_id().node_id, span: sp, attrs: ThinVec::new(), source, }); let decl = respan(sp, hir::DeclLocal(local)); - respan(sp, hir::StmtDecl(P(decl), self.next_id())) + respan(sp, hir::StmtDecl(P(decl), self.next_id().node_id)) } fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P) @@ -2665,10 +2705,13 @@ impl<'a> LoweringContext<'a> { fn block_all(&mut self, span: Span, stmts: hir::HirVec, expr: Option>) -> hir::Block { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + hir::Block { stmts, expr, - id: self.next_id(), + id: node_id, + hir_id, rules: hir::DefaultBlock, span, targeted_by_break: false, @@ -2712,18 +2755,22 @@ impl<'a> LoweringContext<'a> { fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingAnnotation) -> P { - let id = self.next_id(); + let LoweredNodeId { node_id, hir_id } = self.next_id(); let parent_def = self.parent_def.unwrap(); let def_id = { let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name); - let def_index = defs - .create_def_with_parent(parent_def, id, def_path_data, REGULAR_SPACE, Mark::root()); + let def_index = defs.create_def_with_parent(parent_def, + node_id, + def_path_data, + REGULAR_SPACE, + Mark::root()); DefId::local(def_index) }; P(hir::Pat { - id, + id: node_id, + hir_id, node: hir::PatKind::Binding(bm, def_id, Spanned { @@ -2740,8 +2787,10 @@ impl<'a> LoweringContext<'a> { } fn pat(&mut self, span: Span, pat: hir::PatKind) -> P { + let LoweredNodeId { node_id, hir_id } = self.next_id(); P(hir::Pat { - id: self.next_id(), + id: node_id, + hir_id, node: pat, span, }) @@ -2770,11 +2819,13 @@ impl<'a> LoweringContext<'a> { rule: hir::BlockCheckMode, attrs: ThinVec) -> hir::Expr { - let id = self.next_id(); + let LoweredNodeId { node_id, hir_id } = self.next_id(); + let block = P(hir::Block { rules: rule, span, - id, + id: node_id, + hir_id, stmts, expr: Some(expr), targeted_by_break: false, @@ -2799,7 +2850,7 @@ impl<'a> LoweringContext<'a> { // The original ID is taken by the `PolyTraitRef`, // so the `Ty` itself needs a different one. - id = self.next_id(); + id = self.next_id().node_id; hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span)) } else { @@ -2813,7 +2864,7 @@ impl<'a> LoweringContext<'a> { fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime { hir::Lifetime { - id: self.next_id(), + id: self.next_id().node_id, span, name: keywords::Invalid.name() } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index cdd5a6e3da7f..d3e3998360b6 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -465,6 +465,10 @@ impl Definitions { self.node_to_hir_id[node_id] } + pub fn find_node_for_hir_id(&self, hir_id: hir::HirId) -> ast::NodeId { + self.node_to_hir_id.binary_search(&hir_id).unwrap() + } + /// Add a definition with a parent definition. pub fn create_root_def(&mut self, crate_name: &str, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 45b1d6c18410..3b73647f0eb0 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -357,6 +357,7 @@ impl<'hir> Map<'hir> { } } + #[inline] pub fn definitions(&self) -> &Definitions { &self.definitions } @@ -377,6 +378,7 @@ impl<'hir> Map<'hir> { self.definitions.def_path(def_id.index) } + #[inline] pub fn local_def_id(&self, node: NodeId) -> DefId { self.opt_local_def_id(node).unwrap_or_else(|| { bug!("local_def_id: no entry for `{}`, which has a map of `{:?}`", @@ -384,14 +386,21 @@ impl<'hir> Map<'hir> { }) } + #[inline] pub fn opt_local_def_id(&self, node: NodeId) -> Option { self.definitions.opt_local_def_id(node) } + #[inline] pub fn as_local_node_id(&self, def_id: DefId) -> Option { self.definitions.as_local_node_id(def_id) } + #[inline] + pub fn node_to_hir_id(&self, node_id: NodeId) -> HirId { + self.definitions.node_to_hir_id(node_id) + } + fn entry_count(&self) -> usize { self.map.len() } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index efe0504aa18c..a2be74b55223 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -129,9 +129,11 @@ pub const CRATE_HIR_ID: HirId = HirId { pub const DUMMY_HIR_ID: HirId = HirId { owner: CRATE_DEF_INDEX, - local_id: ItemLocalId(!0) + local_id: DUMMY_ITEM_LOCAL_ID, }; +pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId(!0); + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, @@ -547,6 +549,7 @@ pub struct Block { /// without a semicolon, if any pub expr: Option>, pub id: NodeId, + pub hir_id: HirId, /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, pub span: Span, @@ -560,6 +563,7 @@ pub struct Block { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Pat { pub id: NodeId, + pub hir_id: HirId, pub node: PatKind, pub span: Span, } @@ -986,6 +990,7 @@ pub struct Expr { pub span: Span, pub node: Expr_, pub attrs: ThinVec, + pub hir_id: HirId, } impl fmt::Debug for Expr { @@ -1423,6 +1428,7 @@ pub struct InlineAsm { pub struct Arg { pub pat: P, pub id: NodeId, + pub hir_id: HirId, } /// Represents the header (not the body) of a function declaration diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index b344084f580b..fca70de704f3 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -359,6 +359,7 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::B ref stmts, ref expr, id, + hir_id: _, rules, span, targeted_by_break, @@ -423,6 +424,7 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::P let hir::Pat { id, + hir_id: _, ref node, ref span } = *self; @@ -551,6 +553,7 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::E hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Expr { id, + hir_id: _, ref span, ref node, ref attrs @@ -1021,7 +1024,8 @@ impl_stable_hash_for!(enum hir::Stmt_ { impl_stable_hash_for!(struct hir::Arg { pat, - id + id, + hir_id }); impl_stable_hash_for!(struct hir::Body { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 8a37d7bab444..37ef7e8cbfa3 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -618,6 +618,7 @@ for ty::TypeckTables<'gcx> { hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::TypeckTables { + local_id_root: _, ref type_dependent_defs, ref node_types, ref node_substs, @@ -637,7 +638,9 @@ for ty::TypeckTables<'gcx> { } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - ich::hash_stable_nodemap(hcx, hasher, type_dependent_defs); + ich::hash_stable_hashmap(hcx, hasher, type_dependent_defs, |_, item_local_id| { + *item_local_id + }); ich::hash_stable_nodemap(hcx, hasher, node_types); ich::hash_stable_nodemap(hcx, hasher, node_substs); ich::hash_stable_nodemap(hcx, hasher, adjustments); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index bf79becfe4a1..6aa84a975033 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -358,8 +358,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { /// Used only by `rustc_typeck` during body type-checking/inference, /// will initialize `in_progress_tables` with fresh `TypeckTables`. - pub fn with_fresh_in_progress_tables(mut self) -> Self { - self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty())); + pub fn with_fresh_in_progress_tables(mut self, table_owner: DefId) -> Self { + self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(table_owner))); self } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6ee06dc0a816..cd06806ca601 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -43,7 +43,7 @@ use syntax::ast; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use hir; -use hir::def_id::LOCAL_CRATE; +use hir::def_id::{DefId, LOCAL_CRATE}; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; @@ -986,7 +986,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut cx = LateContext { tcx, - tables: &ty::TypeckTables::empty(), + tables: &ty::TypeckTables::empty(DefId::invalid()), param_env: ty::ParamEnv::empty(Reveal::UserFacing), access_levels, lint_sess: LintSession::new(&tcx.sess.lint_store), diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 4e08bc90c7c3..4cf27981e1b6 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } } - fn lookup_and_handle_method(&mut self, id: ast::NodeId) { + fn lookup_and_handle_method(&mut self, id: hir::ItemLocalId) { self.check_def_id(self.tables.type_dependent_defs[&id].def_id()); } @@ -119,6 +119,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, def: Def, pats: &[codemap::Spanned]) { + + let variant = match self.tables.node_id_to_type(lhs.id).sty { ty::TyAdt(adt, _) => adt.variant_of_def(def), _ => span_bug!(lhs.span, "non-ADT in struct pattern") @@ -235,11 +237,11 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => { - let def = self.tables.qpath_def(qpath, expr.id); + let def = self.tables.qpath_def(qpath, expr.hir_id); self.handle_definition(def); } hir::ExprMethodCall(..) => { - self.lookup_and_handle_method(expr.id); + self.lookup_and_handle_method(expr.hir_id.local_id); } hir::ExprField(ref lhs, ref name) => { self.handle_field_access(&lhs, name.node); @@ -282,7 +284,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { self.handle_field_pattern_match(pat, path.def, fields); } PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => { - let def = self.tables.qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.hir_id); self.handle_definition(def); } _ => () @@ -425,7 +427,7 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, - tables: &ty::TypeckTables::empty(), + tables: &ty::TypeckTables::empty(DefId::invalid()), live_symbols: box FxHashSet(), struct_has_extern_repr: false, ignore_non_const_paths: false, diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index fcf366788b22..e8ecf9c21cd3 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -19,6 +19,7 @@ use syntax::ast; use syntax_pos::Span; use hir::{self, PatKind}; use hir::def::Def; +use hir::def_id::DefId; use hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap}; #[derive(Copy, Clone)] @@ -165,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { - let def_id = self.tables.type_dependent_defs[&expr.id].def_id(); + let def_id = self.tables.type_dependent_defs[&expr.hir_id.local_id].def_id(); let sig = self.tcx.fn_sig(def_id); debug!("effect: method call case, signature is {:?}", sig); @@ -262,7 +263,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = EffectCheckVisitor { tcx, - tables: &ty::TypeckTables::empty(), + tables: &ty::TypeckTables::empty(DefId::invalid()), body_id: hir::BodyId { node_id: ast::CRATE_NODE_ID }, unsafe_context: UnsafeContext::new(SafeContext), }; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 87e933e85e22..80abe87470c2 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -537,7 +537,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let def_id = self.mc.tables.type_dependent_defs[&call.id].def_id(); + let def_id = self.mc.tables.type_dependent_defs[&call.hir_id.local_id].def_id(); match OverloadedCallType::from_method_id(self.tcx(), def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); @@ -863,7 +863,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { PatKind::Struct(ref qpath, ..) => qpath, _ => return }; - let def = mc.tables.qpath_def(qpath, pat.id); + let def = mc.tables.qpath_def(qpath, pat.hir_id); match def { Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index d29622b4a815..83278bd88e92 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { let def = if let hir::ExprPath(ref qpath) = expr.node { - self.tables.qpath_def(qpath, expr.id) + self.tables.qpath_def(qpath, expr.hir_id) } else { Def::Err }; diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b4993aafc4c9..c6773250bde9 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -604,7 +604,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprPath(ref qpath) => { - let def = self.tables.qpath_def(qpath, expr.id); + let def = self.tables.qpath_def(qpath, expr.hir_id); self.cat_def(expr.id, expr.span, expr_ty, def) } @@ -1124,7 +1124,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match pat.node { PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { - let def = self.tables.qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.hir_id); let (cmt, expected_len) = match def { Def::Err => { debug!("access to unresolvable pattern {:?}", pat); @@ -1161,7 +1161,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { PatKind::Struct(ref qpath, ref field_pats, _) => { // {f1: p1, ..., fN: pN} - let def = self.tables.qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.hir_id); let cmt = match def { Def::Err => { debug!("access to unresolvable pattern {:?}", pat); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index df828c8d8e71..98f82a51267f 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -107,10 +107,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { let def = match expr.node { hir::ExprPath(ref qpath) => { - Some(self.tables.qpath_def(qpath, expr.id)) + Some(self.tables.qpath_def(qpath, expr.hir_id)) } hir::ExprMethodCall(..) => { - Some(self.tables.type_dependent_defs[&expr.id]) + Some(self.tables.type_dependent_defs[&expr.hir_id.local_id]) } _ => None }; @@ -375,7 +375,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> }); let mut reachable_context = ReachableContext { tcx, - tables: &ty::TypeckTables::empty(), + tables: &ty::TypeckTables::empty(DefId::invalid()), reachable_symbols: NodeSet(), worklist: Vec::new(), any_library, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6b9cbabf20e9..46bb13c89ba7 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,7 @@ use dep_graph::DepGraph; use errors::DiagnosticBuilder; use session::Session; use middle; -use hir::TraitMap; +use hir::{TraitMap}; use hir::def::{Def, ExportMap}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; @@ -42,7 +42,7 @@ use ty::inhabitedness::DefIdForest; use ty::maps; use ty::steal::Steal; use ty::BindingMode; -use util::nodemap::{NodeMap, NodeSet, DefIdSet}; +use util::nodemap::{NodeMap, NodeSet, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -209,9 +209,12 @@ pub struct CommonTypes<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct TypeckTables<'tcx> { + /// The HirId::owner all ItemLocalIds in this table are relative to. + pub local_id_root: DefId, + /// Resolved definitions for `::X` associated paths and /// method calls, including those of overloaded operators. - pub type_dependent_defs: NodeMap, + pub type_dependent_defs: ItemLocalMap, /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated until after typeck. See @@ -271,9 +274,10 @@ pub struct TypeckTables<'tcx> { } impl<'tcx> TypeckTables<'tcx> { - pub fn empty() -> TypeckTables<'tcx> { + pub fn empty(local_id_root: DefId) -> TypeckTables<'tcx> { TypeckTables { - type_dependent_defs: NodeMap(), + local_id_root, + type_dependent_defs: ItemLocalMap(), node_types: FxHashMap(), node_substs: NodeMap(), adjustments: NodeMap(), @@ -291,11 +295,12 @@ impl<'tcx> TypeckTables<'tcx> { } /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node. - pub fn qpath_def(&self, qpath: &hir::QPath, id: NodeId) -> Def { + pub fn qpath_def(&self, qpath: &hir::QPath, id: hir::HirId) -> Def { match *qpath { hir::QPath::Resolved(_, ref path) => path.def, hir::QPath::TypeRelative(..) => { - self.type_dependent_defs.get(&id).cloned().unwrap_or(Def::Err) + self.validate_hir_id(id); + self.type_dependent_defs.get(&id.local_id).cloned().unwrap_or(Def::Err) } } } @@ -373,7 +378,8 @@ impl<'tcx> TypeckTables<'tcx> { return false; } - match self.type_dependent_defs.get(&expr.id) { + self.validate_hir_id(expr.hir_id); + match self.type_dependent_defs.get(&expr.hir_id.local_id) { Some(&Def::Method(_)) => true, _ => false } @@ -382,6 +388,30 @@ impl<'tcx> TypeckTables<'tcx> { pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { self.upvar_capture_map[&upvar_id] } + + /// Validate that a NodeId can safely be converted to an ItemLocalId for + /// this table. + #[inline] + pub fn validate_hir_id(&self, hir_id: hir::HirId) { + #[cfg(debug_assertions)] + { + if self.local_id_root.is_local() { + if hir_id.owner != self.local_id_root.index { + ty::tls::with(|tcx| { + let node_id = tcx.hir + .definitions() + .find_node_for_hir_id(hir_id); + + bug!("node {} with HirId::owner {:?} cannot be placed in \ + TypeckTables with local_id_root {:?}", + tcx.hir.node_to_string(node_id), + DefId::local(hir_id.owner), + self.local_id_root) + }); + } + } + } + } } impl<'tcx> CommonTypes<'tcx> { diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index b03011fcb216..c397371c5c76 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -13,6 +13,7 @@ #![allow(non_snake_case)] use hir::def_id::DefId; +use hir::ItemLocalId; use syntax::ast; pub use rustc_data_structures::fx::FxHashMap; @@ -20,12 +21,14 @@ pub use rustc_data_structures::fx::FxHashSet; pub type NodeMap = FxHashMap; pub type DefIdMap = FxHashMap; +pub type ItemLocalMap = FxHashMap; pub type NodeSet = FxHashSet; pub type DefIdSet = FxHashSet; pub fn NodeMap() -> NodeMap { FxHashMap() } pub fn DefIdMap() -> DefIdMap { FxHashMap() } +pub fn ItemLocalMap() -> ItemLocalMap { FxHashMap() } pub fn NodeSet() -> NodeSet { FxHashSet() } pub fn DefIdSet() -> DefIdSet { FxHashSet() } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index eb45fd9c0e0a..cce511daf8ae 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -276,7 +276,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } hir::ExprPath(ref qpath) => { let substs = cx.tables.node_substs(e.id).subst(tcx, cx.substs); - match cx.tables.qpath_def(qpath, e.id) { + match cx.tables.qpath_def(qpath, e.hir_id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) { diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index f37a112a596a..30183ca2daf7 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Path(ref qpath) => { - return self.lower_path(qpath, pat.id, pat.id, pat.span); + return self.lower_path(qpath, (pat.id, pat.hir_id), pat.id, pat.span); } PatKind::Ref(ref subpattern, _) | @@ -417,7 +417,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => { - let def = self.tables.qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.hir_id); let adt_def = match ty.sty { ty::TyAdt(adt_def, _) => adt_def, _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), @@ -436,7 +436,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Struct(ref qpath, ref fields, _) => { - let def = self.tables.qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.hir_id); let adt_def = match ty.sty { ty::TyAdt(adt_def, _) => adt_def, _ => { @@ -590,12 +590,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_path(&mut self, qpath: &hir::QPath, - id: ast::NodeId, + (id, hir_id): (ast::NodeId, hir::HirId), pat_id: ast::NodeId, span: Span) -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); - let def = self.tables.qpath_def(qpath, id); + let def = self.tables.qpath_def(qpath, hir_id); let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); @@ -696,7 +696,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { _ => bug!() }; let ty = self.tables.node_id_to_type(callee.id); - let def = self.tables.qpath_def(qpath, callee.id); + let def = self.tables.qpath_def(qpath, callee.hir_id); match def { Def::Fn(..) | Def::Method(..) => self.lower_lit(expr), _ => { @@ -712,7 +712,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } hir::ExprStruct(ref qpath, ref fields, None) => { - let def = self.tables.qpath_def(qpath, expr.id); + let def = self.tables.qpath_def(qpath, expr.hir_id); let adt_def = match pat_ty.sty { ty::TyAdt(adt_def, _) => adt_def, _ => { @@ -755,7 +755,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } hir::ExprPath(ref qpath) => { - return self.lower_path(qpath, expr.id, pat_id, span); + return self.lower_path(qpath, (expr.id, expr.hir_id), pat_id, span); } _ => self.lower_lit(expr) diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 1f44378c9e64..bc9bfa404972 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -196,6 +196,16 @@ impl IndexVec { } } +impl IndexVec { + #[inline] + pub fn binary_search(&self, value: &T) -> Result { + match self.raw.binary_search(value) { + Ok(i) => Ok(Idx::new(i)), + Err(i) => Err(Idx::new(i)), + } + } +} + impl Index for IndexVec { type Output = T; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 269363fdd2f9..51f5cc4f249f 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -45,6 +45,7 @@ use std::option; use std::path::Path; use std::str::FromStr; +use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::hir::map::blocks; use rustc::hir; @@ -232,7 +233,7 @@ impl PpSourceMode { arenas, id, |tcx, _, _, _| { - let empty_tables = ty::TypeckTables::empty(); + let empty_tables = ty::TypeckTables::empty(DefId::invalid()); let annotation = TypedAnnotation { tcx: tcx, tables: Cell::new(&empty_tables) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 88432e642903..85ec606e87ef 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -896,7 +896,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { match cx.tcx.hir.get(id) { hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { let def = if let hir::ExprPath(ref qpath) = callee.node { - cx.tables.qpath_def(qpath, callee.id) + cx.tables.qpath_def(qpath, callee.hir_id) } else { return false; }; @@ -934,7 +934,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Check for method calls and overloaded operators. if cx.tables.is_method_call(expr) { - let def_id = cx.tables.type_dependent_defs[&id].def_id(); + let local_id = cx.tcx.hir.definitions().node_to_hir_id(id).local_id; + let def_id = cx.tables.type_dependent_defs[&local_id].def_id(); let substs = cx.tables.node_substs(id); if method_call_refers_to_method(cx, method, def_id, substs, id) { return true; @@ -945,7 +946,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { match expr.node { hir::ExprCall(ref callee, _) => { let def = if let hir::ExprPath(ref qpath) = callee.node { - cx.tables.qpath_def(qpath, callee.id) + cx.tables.qpath_def(qpath, callee.hir_id) } else { return false; }; @@ -1179,7 +1180,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { expr: &hir::Expr) -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> { let def = if let hir::ExprPath(ref qpath) = expr.node { - cx.tables.qpath_def(qpath, expr.id) + cx.tables.qpath_def(qpath, expr.hir_id) } else { return None; }; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 06a0c4ff213d..3effc29d67e2 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -450,7 +450,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprPath(ref qpath) => { - let def = cx.tables().qpath_def(qpath, expr.id); + let def = cx.tables().qpath_def(qpath, expr.hir_id); convert_path_expr(cx, expr, def) } @@ -580,7 +580,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, -> Expr<'tcx> { let temp_lifetime = cx.region_maps.temporary_scope(expr.id); let (def_id, substs) = custom_callee.unwrap_or_else(|| { - (cx.tables().type_dependent_defs[&expr.id].def_id(), + cx.tables().validate_hir_id(expr.hir_id); + (cx.tables().type_dependent_defs[&expr.hir_id.local_id].def_id(), cx.tables().node_substs(expr.id)) }); Expr { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 8443cc8267d1..b3a1509972a0 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -329,7 +329,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprPath(ref qpath) => { - let def = v.tables.qpath_def(qpath, e.id); + let def = v.tables.qpath_def(qpath, e.hir_id); match def { Def::VariantCtor(..) | Def::StructCtor(..) | Def::Fn(..) | Def::Method(..) => {} @@ -365,7 +365,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } // The callee is an arbitrary expression, it doesn't necessarily have a definition. let def = if let hir::ExprPath(ref qpath) = callee.node { - v.tables.qpath_def(qpath, callee.id) + v.tables.qpath_def(qpath, callee.hir_id) } else { Def::Err }; @@ -387,7 +387,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - let def_id = v.tables.type_dependent_defs[&e.id].def_id(); + v.tables.validate_hir_id(e.hir_id); + let def_id = v.tables.type_dependent_defs[&e.hir_id.local_id].def_id(); match v.tcx.associated_item(def_id).container { ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty), ty::TraitContainer(_) => v.promotable = false @@ -471,7 +472,7 @@ 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.hir.krate().visit_all_item_likes(&mut CheckCrateVisitor { tcx: tcx, - tables: &ty::TypeckTables::empty(), + tables: &ty::TypeckTables::empty(DefId::invalid()), in_fn: false, promotable: false, mut_rvalue_borrows: NodeSet(), diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 9fa5fea20d91..c1cab0cc8f74 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -473,6 +473,7 @@ struct NamePrivacyVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, current_item: ast::NodeId, + empty_tables: &'a ty::TypeckTables<'tcx>, } impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> { @@ -489,6 +490,22 @@ impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> { } } +// Set the correct TypeckTables for the given `item_id` (or an empty table if +// there is no TypeckTables for the item). +fn update_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_id: ast::NodeId, + tables: &mut &'a ty::TypeckTables<'tcx>, + empty_tables: &'a ty::TypeckTables<'tcx>) + -> &'a ty::TypeckTables<'tcx> { + let def_id = tcx.hir.local_def_id(item_id); + + if tcx.has_typeck_tables(def_id) { + replace(tables, tcx.typeck_tables_of(def_id)) + } else { + replace(tables, empty_tables) + } +} + impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. @@ -505,14 +522,28 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { let orig_current_item = replace(&mut self.current_item, item.id); + let orig_tables = update_tables(self.tcx, item.id, &mut self.tables, self.empty_tables); intravisit::walk_item(self, item); self.current_item = orig_current_item; + self.tables = orig_tables; + } + + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { + let orig_tables = update_tables(self.tcx, ti.id, &mut self.tables, self.empty_tables); + intravisit::walk_trait_item(self, ti); + self.tables = orig_tables; + } + + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { + let orig_tables = update_tables(self.tcx, ii.id, &mut self.tables, self.empty_tables); + intravisit::walk_impl_item(self, ii); + self.tables = orig_tables; } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprStruct(ref qpath, ref fields, ref base) => { - let def = self.tables.qpath_def(qpath, expr.id); + let def = self.tables.qpath_def(qpath, expr.hir_id); let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_def(def); if let Some(ref base) = *base { @@ -539,7 +570,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &'tcx hir::Pat) { match pat.node { PatKind::Struct(ref qpath, ref fields, _) => { - let def = self.tables.qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.hir_id); let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap(); let variant = adt.variant_of_def(def); for field in fields { @@ -564,6 +595,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> { tables: &'a ty::TypeckTables<'tcx>, current_item: DefId, span: Span, + empty_tables: &'a ty::TypeckTables<'tcx>, } impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { @@ -716,7 +748,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { } hir::ExprMethodCall(_, span, _) => { // Method calls have to be checked specially. - let def_id = self.tables.type_dependent_defs[&expr.id].def_id(); + self.tables.validate_hir_id(expr.hir_id); + let def_id = self.tables.type_dependent_defs[&expr.hir_id.local_id].def_id(); self.span = span; if self.tcx.type_of(def_id).visit_with(self) { return; @@ -732,7 +765,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Inherent associated constants don't have self type in substs, // we have to check it additionally. if let hir::QPath::TypeRelative(..) = *qpath { - if let Some(def) = self.tables.type_dependent_defs.get(&id).cloned() { + let hir_id = self.tcx.hir.node_to_hir_id(id); + self.tables.validate_hir_id(hir_id); + if let Some(def) = self.tables.type_dependent_defs.get(&hir_id.local_id).cloned() { if let Some(assoc_item) = self.tcx.opt_associated_item(def.def_id()) { if let ty::ImplContainer(impl_def_id) = assoc_item.container { if self.tcx.type_of(impl_def_id).visit_with(self) { @@ -770,6 +805,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Check types in item interfaces fn visit_item(&mut self, item: &'tcx hir::Item) { let orig_current_item = self.current_item; + let orig_tables = update_tables(self.tcx, + item.id, + &mut self.tables, + self.empty_tables); match item.node { hir::ItemExternCrate(..) | hir::ItemMod(..) | @@ -829,8 +868,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { self.current_item = self.tcx.hir.local_def_id(item.id); intravisit::walk_item(self, item); + self.tables = orig_tables; self.current_item = orig_current_item; } + + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { + let orig_tables = update_tables(self.tcx, ti.id, &mut self.tables, self.empty_tables); + intravisit::walk_trait_item(self, ti); + self.tables = orig_tables; + } + + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { + let orig_tables = update_tables(self.tcx, ii.id, &mut self.tables, self.empty_tables); + intravisit::walk_impl_item(self, ii); + self.tables = orig_tables; + } } impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { @@ -1606,11 +1658,15 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.hir.krate(); + let empty_tables = ty::TypeckTables::empty(DefId::invalid()); + + // Check privacy of names not checked in previous compilation stages. let mut visitor = NamePrivacyVisitor { tcx: tcx, - tables: &ty::TypeckTables::empty(), + tables: &empty_tables, current_item: CRATE_NODE_ID, + empty_tables: &empty_tables, }; intravisit::walk_crate(&mut visitor, krate); @@ -1618,9 +1674,10 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // inferred types of expressions and patterns. let mut visitor = TypePrivacyVisitor { tcx: tcx, - tables: &ty::TypeckTables::empty(), + tables: &empty_tables, current_item: DefId::local(CRATE_DEF_INDEX), span: krate.span, + empty_tables: &empty_tables, }; intravisit::walk_crate(&mut visitor, krate); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1dd0df4108fc..d46d8624a12c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -550,7 +550,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::MethodCall(..) => { - let method_id = self.tables.type_dependent_defs[&expr.id].def_id(); + let local_id = self.tcx.hir.definitions().node_to_hir_id(expr.id).local_id; + let method_id = self.tables.type_dependent_defs[&local_id].def_id(); let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), @@ -586,7 +587,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Node::NodePat(&hir::Pat { node: hir::PatKind::Path(ref qpath), .. }) | Node::NodePat(&hir::Pat { node: hir::PatKind::Struct(ref qpath, ..), .. }) | Node::NodePat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. }) => { - self.tables.qpath_def(qpath, id) + let hir_id = self.tcx.hir.node_to_hir_id(id); + self.tables.qpath_def(qpath, hir_id) } Node::NodeLocal(&hir::Pat { node: hir::PatKind::Binding(_, def_id, ..), .. }) => { @@ -975,7 +977,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(tcx: TyCtxt<'l, 'tcx, 'tcx>, let save_ctxt = SaveContext { tcx: tcx, - tables: &ty::TypeckTables::empty(), + tables: &ty::TypeckTables::empty(DefId::invalid()), analysis: analysis, span_utils: SpanUtils::new(&tcx.sess), config: find_config(config), diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index a0801a748665..cdf1c3b235b6 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -222,7 +222,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let hir::ExprCall(ref expr, _) = call_expr.node { let def = if let hir::ExprPath(ref qpath) = expr.node { - self.tables.borrow().qpath_def(qpath, expr.id) + self.tables.borrow().qpath_def(qpath, expr.hir_id) } else { Def::Err }; @@ -314,7 +314,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TupleArgumentsFlag::TupleArguments, expected); - self.write_method_call(call_expr.id, method_callee); + self.write_method_call((call_expr.id, call_expr.hir_id), method_callee); output_type } } @@ -364,7 +364,8 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { adjustments.extend(autoref); fcx.apply_adjustments(self.callee_expr, adjustments); - fcx.write_method_call(self.call_expr.id, method_callee); + fcx.write_method_call((self.call_expr.id, self.call_expr.hir_id), + method_callee); } None => { span_bug!(self.call_expr.span, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index b6a5ce0a6ce5..a6f904b0c96c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -513,7 +513,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed") }; debug!("convert_lvalue_op_to_mutable: method={:?}", method); - self.write_method_call(expr.id, method); + self.write_method_call((expr.id, expr.hir_id), method); let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty { (r, mt.mutbl) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 697d9de931a8..885472a76a92 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -572,8 +572,16 @@ pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId) -> InheritedBuilder<'a, 'gcx, 'tcx> { + let hir_id_root = if def_id.is_local() { + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + let hir_id = tcx.hir.definitions().node_to_hir_id(node_id); + DefId::local(hir_id.owner) + } else { + def_id + }; + InheritedBuilder { - infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(), + infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(hir_id_root), def_id, } } @@ -840,7 +848,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); let body = tcx.hir.body(body_id); - Inherited::build(tcx, def_id).enter(|inh| { + let tables = Inherited::build(tcx, def_id).enter(|inh| { let param_env = tcx.param_env(def_id); let fcx = if let Some(decl) = fn_decl { let fn_sig = tcx.fn_sig(def_id); @@ -887,7 +895,13 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fcx.resolve_type_vars_in_body(body) - }) + }); + + // Consistency check our TypeckTables instance can hold all ItemLocalIds + // it will need to hold. + assert_eq!(tables.local_id_root, + DefId::local(tcx.hir.definitions().node_to_hir_id(id).owner)); + tables } fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) { @@ -1804,8 +1818,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn write_method_call(&self, node_id: ast::NodeId, method: MethodCallee<'tcx>) { - self.tables.borrow_mut().type_dependent_defs.insert(node_id, Def::Method(method.def_id)); + // The NodeId and the ItemLocalId must identify the same item. We just pass + // both of them for consistency checking. + pub fn write_method_call(&self, + (node_id, hir_id): (ast::NodeId, hir::HirId), + method: MethodCallee<'tcx>) { + { + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(hir_id); + tables.type_dependent_defs.insert(hir_id.local_id, Def::Method(method.def_id)); + } self.write_substs(node_id, method.substs); } @@ -2254,7 +2276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.apply_adjustments(base_expr, adjustments); - self.write_method_call(expr.id, method); + self.write_method_call((expr.id, expr.hir_id), method); (input_ty, self.make_overloaded_lvalue_return_type(method).ty) }); if result.is_some() { @@ -2794,7 +2816,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, rcvr) { Ok(method) => { - self.write_method_call(expr.id, method); + self.write_method_call((expr.id, expr.hir_id), method); Ok(method) } Err(error) => { @@ -3499,7 +3521,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }]); } oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; - self.write_method_call(expr.id, method); + self.write_method_call((expr.id, expr.hir_id), method); } else { type_error_struct!(tcx.sess, expr.span, oprnd_t, E0614, "type `{}` cannot be dereferenced", @@ -4000,7 +4022,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty, def, segment); // Write back the new resolution. - self.tables.borrow_mut().type_dependent_defs.insert(node_id, def); + let hir_id = self.tcx.hir.node_to_hir_id(node_id); + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(hir_id); + tables.type_dependent_defs.insert(hir_id.local_id, def); (def, ty) } @@ -4041,7 +4066,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Write back the new resolution. - self.tables.borrow_mut().type_dependent_defs.insert(node_id, def); + let hir_id = self.tcx.hir.node_to_hir_id(node_id); + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(hir_id); + tables.type_dependent_defs.insert(hir_id.local_id, def); (def, Some(ty), slice::ref_slice(&**item_segment)) } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index c1711491ee48..71457377b108 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -214,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .or_insert(vec![]).push(autoref); } } - self.write_method_call(expr.id, method); + self.write_method_call((expr.id, expr.hir_id), method); method.sig.output() } @@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(op.is_by_value()); match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) { Ok(method) => { - self.write_method_call(ex.id, method); + self.write_method_call((ex.id, ex.hir_id), method); method.sig.output() } Err(()) => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 9e5cf5137c21..93d0e6e976a7 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -14,6 +14,7 @@ use check::FnCtxt; use rustc::hir; +use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::infer::{InferCtxt}; use rustc::ty::{self, Ty, TyCtxt}; @@ -34,7 +35,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut wbcx = WritebackCx::new(self, body); for arg in &body.arguments { - wbcx.visit_node_id(arg.pat.span, arg.id); + wbcx.visit_node_id(arg.pat.span, (arg.id, arg.hir_id)); } wbcx.visit_body(body); wbcx.visit_upvar_borrow_map(); @@ -74,10 +75,13 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn new(fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>, body: &'gcx hir::Body) - -> WritebackCx<'cx, 'gcx, 'tcx> { + -> WritebackCx<'cx, 'gcx, 'tcx> + { + let owner = fcx.tcx.hir.definitions().node_to_hir_id(body.id().node_id); + WritebackCx { fcx: fcx, - tables: ty::TypeckTables::empty(), + tables: ty::TypeckTables::empty(DefId::local(owner.owner)), body: body } } @@ -105,7 +109,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if inner_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); - tables.type_dependent_defs.remove(&e.id); + tables.validate_hir_id(e.hir_id); + tables.type_dependent_defs.remove(&e.hir_id.local_id); tables.node_substs.remove(&e.id); } } @@ -119,7 +124,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if lhs_ty.is_scalar() && rhs_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); - tables.type_dependent_defs.remove(&e.id); + tables.validate_hir_id(e.hir_id); + tables.type_dependent_defs.remove(&e.hir_id.local_id); tables.node_substs.remove(&e.id); match e.node { @@ -157,12 +163,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_expr(&mut self, e: &'gcx hir::Expr) { self.fix_scalar_builtin_expr(e); - self.visit_node_id(e.span, e.id); + self.visit_node_id(e.span, (e.id, e.hir_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(e.span, arg.id); + self.visit_node_id(e.span, (arg.id, arg.hir_id)); } self.visit_body(body); @@ -172,7 +178,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_block(&mut self, b: &'gcx hir::Block) { - self.visit_node_id(b.span, b.id); + self.visit_node_id(b.span, (b.id, b.hir_id)); intravisit::walk_block(self, b); } @@ -186,7 +192,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { _ => {} }; - self.visit_node_id(p.span, p.id); + self.visit_node_id(p.span, (p.id, p.hir_id)); intravisit::walk_pat(self, p); } @@ -277,10 +283,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - fn visit_node_id(&mut self, span: Span, node_id: ast::NodeId) { - // Export associated path extensions and method resultions. - if let Some(def) = self.fcx.tables.borrow_mut().type_dependent_defs.remove(&node_id) { - self.tables.type_dependent_defs.insert(node_id, def); + fn visit_node_id(&mut self, + span: Span, + (node_id, hir_id): (ast::NodeId, hir::HirId)) { + { + let mut fcx_tables = self.fcx.tables.borrow_mut(); + fcx_tables.validate_hir_id(hir_id); + // Export associated path extensions and method resultions. + if let Some(def) = fcx_tables.type_dependent_defs.remove(&hir_id.local_id) { + self.tables.validate_hir_id(hir_id); + self.tables.type_dependent_defs.insert(hir_id.local_id, def); + } } // Resolve any borrowings for the node with id `node_id` From 7f2423eede51cc622420356988777db2473a0be2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Aug 2017 14:43:43 +0200 Subject: [PATCH 25/88] Use ItemLocalId as key for node_types, node_substs, and adjustments in TypeckTables. --- src/librustc/hir/lowering.rs | 9 ++- src/librustc/hir/mod.rs | 1 + src/librustc/ich/hcx.rs | 14 +++- src/librustc/ich/impls_hir.rs | 1 + src/librustc/ich/impls_ty.rs | 10 ++- src/librustc/ich/mod.rs | 2 +- .../infer/error_reporting/need_type_info.rs | 10 ++- src/librustc/infer/error_reporting/util.rs | 2 +- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 9 +-- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/mem_categorization.rs | 19 +++-- src/librustc/ty/context.rs | 42 ++++++----- .../borrowck/gather_loans/mod.rs | 4 +- src/librustc_const_eval/check_match.rs | 6 +- src/librustc_const_eval/eval.rs | 2 +- src/librustc_const_eval/pattern.rs | 18 ++--- src/librustc_lint/builtin.rs | 12 ++-- src/librustc_lint/types.rs | 6 +- src/librustc_mir/build/mod.rs | 3 +- src/librustc_mir/hair/cx/block.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 19 ++--- src/librustc_passes/consts.rs | 6 +- src/librustc_privacy/lib.rs | 12 ++-- src/librustc_save_analysis/dump_visitor.rs | 17 +++-- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/callee.rs | 4 +- src/librustc_typeck/check/coercion.rs | 4 +- src/librustc_typeck/check/method/confirm.rs | 22 +++--- src/librustc_typeck/check/mod.rs | 67 +++++++++-------- src/librustc_typeck/check/op.rs | 8 ++- src/librustc_typeck/check/regionck.rs | 70 ++++++++++-------- src/librustc_typeck/check/upvar.rs | 8 +-- src/librustc_typeck/check/writeback.rs | 72 ++++++++++--------- src/librustc_typeck/collect.rs | 3 +- 35 files changed, 282 insertions(+), 208 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 27048a71454b..356d8209ce55 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -904,8 +904,10 @@ impl<'a> LoweringContext<'a> { } fn lower_local(&mut self, l: &Local) -> P { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(l.id); P(hir::Local { - id: self.lower_node_id(l.id).node_id, + id: node_id, + hir_id, ty: l.ty.as_ref().map(|t| self.lower_ty(t)), pat: self.lower_pat(&l.pat), init: l.init.as_ref().map(|e| P(self.lower_expr(e))), @@ -2675,11 +2677,14 @@ impl<'a> LoweringContext<'a> { pat: P, source: hir::LocalSource) -> hir::Stmt { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + let local = P(hir::Local { pat, ty: None, init: ex, - id: self.next_id().node_id, + id: node_id, + hir_id, span: sp, attrs: ThinVec::new(), source, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index a2be74b55223..1831814b0f4c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -901,6 +901,7 @@ pub struct Local { /// Initializer expression to set the value, if any pub init: Option>, pub id: NodeId, + pub hir_id: HirId, pub span: Span, pub attrs: ThinVec, pub source: LocalSource, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 8ce1b39d934d..218483232d67 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -14,7 +14,7 @@ use hir::map::DefPathHash; use ich::{self, CachingCodemapView}; use session::config::DebugInfoLevel::NoDebugInfo; use ty; -use util::nodemap::NodeMap; +use util::nodemap::{NodeMap, ItemLocalMap}; use std::hash as std_hash; use std::collections::{HashMap, HashSet, BTreeMap}; @@ -358,6 +358,18 @@ pub fn hash_stable_nodemap<'a, 'tcx, 'gcx, V, W>( }); } +pub fn hash_stable_itemlocalmap<'a, 'tcx, 'gcx, V, W>( + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher, + map: &ItemLocalMap) + where V: HashStable>, + W: StableHasherResult, +{ + hash_stable_hashmap(hcx, hasher, map, |_, local_id| { + *local_id + }); +} + pub fn hash_stable_btreemap<'a, 'tcx, 'gcx, K, V, SK, F, W>( hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index fca70de704f3..4c70816c0b83 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -506,6 +506,7 @@ impl_stable_hash_for!(struct hir::Local { ty, init, id, + hir_id, span, attrs, source diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 37ef7e8cbfa3..ab5051418802 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -638,12 +638,10 @@ for ty::TypeckTables<'gcx> { } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - ich::hash_stable_hashmap(hcx, hasher, type_dependent_defs, |_, item_local_id| { - *item_local_id - }); - ich::hash_stable_nodemap(hcx, hasher, node_types); - ich::hash_stable_nodemap(hcx, hasher, node_substs); - ich::hash_stable_nodemap(hcx, hasher, adjustments); + ich::hash_stable_itemlocalmap(hcx, hasher, type_dependent_defs); + ich::hash_stable_itemlocalmap(hcx, hasher, node_types); + ich::hash_stable_itemlocalmap(hcx, hasher, node_substs); + ich::hash_stable_itemlocalmap(hcx, hasher, adjustments); ich::hash_stable_nodemap(hcx, hasher, pat_binding_modes); ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { let ty::UpvarId { diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 5b2380908505..dcf84be0eeb3 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -14,7 +14,7 @@ pub use self::fingerprint::Fingerprint; pub use self::caching_codemap_view::CachingCodemapView; pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap, hash_stable_hashset, hash_stable_nodemap, - hash_stable_btreemap}; + hash_stable_btreemap, hash_stable_itemlocalmap}; mod fingerprint; mod caching_codemap_view; mod hcx; diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index a684881c0912..22d9a9e313b7 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::{self, Local, Pat, Body}; +use hir::{self, Local, Pat, Body, HirId}; use hir::intravisit::{self, Visitor, NestedVisitorMap}; use infer::InferCtxt; use infer::type_variable::TypeVariableOrigin; use ty::{self, Ty, TyInfer, TyVar}; - -use syntax::ast::NodeId; use syntax_pos::Span; struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { @@ -26,7 +24,7 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn node_matches_type(&mut self, node_id: NodeId) -> bool { + fn node_matches_type(&mut self, node_id: HirId) -> bool { let ty_opt = self.infcx.in_progress_tables.and_then(|tables| { tables.borrow().node_id_to_type_opt(node_id) }); @@ -56,7 +54,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { } fn visit_local(&mut self, local: &'gcx Local) { - if self.found_local_pattern.is_none() && self.node_matches_type(local.id) { + if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) { self.found_local_pattern = Some(&*local.pat); } intravisit::walk_local(self, local); @@ -64,7 +62,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { 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) { + if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) { self.found_arg_pattern = Some(&*argument.pat); } } diff --git a/src/librustc/infer/error_reporting/util.rs b/src/librustc/infer/error_reporting/util.rs index 14fe8e699c7f..c8f78367420e 100644 --- a/src/librustc/infer/error_reporting/util.rs +++ b/src/librustc/infer/error_reporting/util.rs @@ -46,7 +46,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .iter() .enumerate() .filter_map(|(index, arg)| { - let ty = tables.borrow().node_id_to_type(arg.id); + let ty = tables.borrow().node_id_to_type(arg.hir_id); let mut found_anon_region = false; let new_arg_ty = self.tcx .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 4cf27981e1b6..0cca5690c018 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -121,7 +121,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { pats: &[codemap::Spanned]) { - let variant = match self.tables.node_id_to_type(lhs.id).sty { + let variant = match self.tables.node_id_to_type(lhs.hir_id).sty { ty::TyAdt(adt, _) => adt.variant_of_def(def), _ => span_bug!(lhs.span, "non-ADT in struct pattern") }; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 80abe87470c2..b44f1c7da739 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -296,7 +296,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("consume_body(body={:?})", body); for arg in &body.arguments { - let arg_ty = return_if_err!(self.mc.node_ty(arg.pat.id)); + let arg_ty = return_if_err!(self.mc.node_ty(arg.pat.hir_id)); let fn_body_scope_r = self.tcx().node_scope_region(body.value.id); let arg_cmt = self.mc.cat_rvalue( @@ -826,7 +826,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let bm = *mc.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode"); // pat_ty: the type of the binding being produced. - let pat_ty = return_if_err!(mc.node_ty(pat.id)); + let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); // Each match binding is effectively an assignment to the // binding being produced. @@ -923,8 +923,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective - let var_id = self.tcx().hir.as_local_node_id(upvar_def.def_id()).unwrap(); - let var_ty = self.mc.node_ty(var_id)?; + let var_node_id = self.tcx().hir.as_local_node_id(upvar_def.def_id()).unwrap(); + let var_hir_id = self.tcx().hir.node_to_hir_id(var_node_id); + let var_ty = self.mc.node_ty(var_hir_id)?; self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def) } } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 83278bd88e92..0a4e5094cde7 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -152,7 +152,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { }; if let Def::Fn(did) = def { if self.def_id_is_transmute(did) { - let typ = self.tables.node_id_to_type(expr.id); + let typ = self.tables.node_id_to_type(expr.hir_id); let sig = typ.fn_sig(self.tcx); let from = sig.inputs().skip_binder()[0]; let to = *sig.output().skip_binder(); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c6773250bde9..7a949cf38b36 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -435,7 +435,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } fn resolve_type_vars_or_error(&self, - id: ast::NodeId, + id: hir::HirId, ty: Option>) -> McResult> { match ty { @@ -451,26 +451,30 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FIXME None if self.is_tainted_by_errors() => Err(()), None => { + let id = self.tcx.hir.definitions().find_node_for_hir_id(id); bug!("no type for node {}: {} in mem_categorization", id, self.tcx.hir.node_to_string(id)); } } } - pub fn node_ty(&self, id: ast::NodeId) -> McResult> { - self.resolve_type_vars_or_error(id, self.tables.node_id_to_type_opt(id)) + pub fn node_ty(&self, + hir_id: hir::HirId) + -> McResult> { + self.resolve_type_vars_or_error(hir_id, + self.tables.node_id_to_type_opt(hir_id)) } pub fn expr_ty(&self, expr: &hir::Expr) -> McResult> { - self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_opt(expr)) + self.resolve_type_vars_or_error(expr.hir_id, self.tables.expr_ty_opt(expr)) } pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_adjusted_opt(expr)) + self.resolve_type_vars_or_error(expr.hir_id, self.tables.expr_ty_adjusted_opt(expr)) } fn pat_ty(&self, pat: &hir::Pat) -> McResult> { - let base_ty = self.node_ty(pat.id)?; + let base_ty = self.node_ty(pat.hir_id)?; // FIXME (Issue #18207): This code detects whether we are // looking at a `ref x`, and if so, figures out what the type // *being borrowed* is. But ideally we would put in a more @@ -714,7 +718,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let upvar_id = ty::UpvarId { var_id, closure_expr_id: fn_node_id }; - let var_ty = self.node_ty(var_id)?; + let var_hir_id = self.tcx.hir.node_to_hir_id(var_id); + let var_ty = self.node_ty(var_hir_id)?; // Mutability of original variable itself let var_mutbl = MutabilityCategory::from_local(self.tcx, self.tables, var_id); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 46bb13c89ba7..528fb4e2e7fc 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -57,7 +57,7 @@ use std::ops::Deref; use std::iter; use std::rc::Rc; use syntax::abi; -use syntax::ast::{self, Name, NodeId}; +use syntax::ast::{self, Name}; use syntax::attr; use syntax::codemap::MultiSpan; use syntax::symbol::{Symbol, keywords}; @@ -219,15 +219,15 @@ pub struct TypeckTables<'tcx> { /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated until after typeck. See /// typeck::check::fn_ctxt for details. - pub node_types: NodeMap>, + pub node_types: ItemLocalMap>, /// Stores the type parameters which were substituted to obtain the type /// of this node. This only applies to nodes that refer to entities /// parameterized by type parameters, such as generic fns, types, or /// other items. - pub node_substs: NodeMap<&'tcx Substs<'tcx>>, + pub node_substs: ItemLocalMap<&'tcx Substs<'tcx>>, - pub adjustments: NodeMap>>, + pub adjustments: ItemLocalMap>>, // Stores the actual binding mode for all instances of hir::BindingAnnotation. pub pat_binding_modes: NodeMap, @@ -278,9 +278,9 @@ impl<'tcx> TypeckTables<'tcx> { TypeckTables { local_id_root, type_dependent_defs: ItemLocalMap(), - node_types: FxHashMap(), - node_substs: NodeMap(), - adjustments: NodeMap(), + node_types: ItemLocalMap(), + node_substs: ItemLocalMap(), + adjustments: ItemLocalMap(), pat_binding_modes: NodeMap(), upvar_capture_map: FxHashMap(), closure_tys: NodeMap(), @@ -305,32 +305,37 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { + pub fn node_id_to_type(&self, id: hir::HirId) -> Ty<'tcx> { match self.node_id_to_type_opt(id) { Some(ty) => ty, None => { bug!("node_id_to_type: no type for node `{}`", - tls::with(|tcx| tcx.hir.node_to_string(id))) + tls::with(|tcx| { + let id = tcx.hir.definitions().find_node_for_hir_id(id); + tcx.hir.node_to_string(id) + })) } } } - pub fn node_id_to_type_opt(&self, id: NodeId) -> Option> { - self.node_types.get(&id).cloned() + pub fn node_id_to_type_opt(&self, id: hir::HirId) -> Option> { + self.validate_hir_id(id); + self.node_types.get(&id.local_id).cloned() } - pub fn node_substs(&self, id: NodeId) -> &'tcx Substs<'tcx> { - self.node_substs.get(&id).cloned().unwrap_or(Substs::empty()) + pub fn node_substs(&self, id: hir::HirId) -> &'tcx Substs<'tcx> { + self.validate_hir_id(id); + self.node_substs.get(&id.local_id).cloned().unwrap_or(Substs::empty()) } // Returns the type of a pattern as a monotype. Like @expr_ty, this function // doesn't provide type parameter substitutions. pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { - self.node_id_to_type(pat.id) + self.node_id_to_type(pat.hir_id) } pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option> { - self.node_id_to_type_opt(pat.id) + self.node_id_to_type_opt(pat.hir_id) } // Returns the type of an expression as a monotype. @@ -344,16 +349,17 @@ impl<'tcx> TypeckTables<'tcx> { // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" // instead of "fn(ty) -> T with T = isize". pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> { - self.node_id_to_type(expr.id) + self.node_id_to_type(expr.hir_id) } pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option> { - self.node_id_to_type_opt(expr.id) + self.node_id_to_type_opt(expr.hir_id) } pub fn expr_adjustments(&self, expr: &hir::Expr) -> &[ty::adjustment::Adjustment<'tcx>] { - self.adjustments.get(&expr.id).map_or(&[], |a| &a[..]) + self.validate_hir_id(expr.hir_id); + self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..]) } /// Returns the type of `expr`, considering any `Adjustment` diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 3d669aa81df6..7a89d1f09d39 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -155,7 +155,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { } fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) { - let ty = self.bccx.tables.node_id_to_type(id); + let ty = self.bccx + .tables + .node_id_to_type(self.bccx.tcx.hir.node_to_hir_id(id)); gather_moves::gather_decl(self.bccx, &self.move_data, id, ty); } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index a3f8aae472ca..0d92bff02b12 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -188,7 +188,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { // Then, if the match has no arms, check whether the scrutinee // is uninhabited. - let pat_ty = self.tables.node_id_to_type(scrut.id); + let pat_ty = self.tables.node_id_to_type(scrut.hir_id); let module = self.tcx.hir.get_module_parent(scrut.id); if inlined_arms.is_empty() { let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type { @@ -217,7 +217,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { .flat_map(|arm| &arm.0) .map(|pat| vec![pat.0]) .collect(); - let scrut_ty = self.tables.node_id_to_type(scrut.id); + let scrut_ty = self.tables.node_id_to_type(scrut.hir_id); check_exhaustive(cx, scrut_ty, scrut.span, &matrix); }) } @@ -494,7 +494,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, let bm = *cx.tables.pat_binding_modes.get(&p.id).expect("missing binding mode"); match bm { ty::BindByValue(..) => { - let pat_ty = cx.tables.node_id_to_type(p.id); + let pat_ty = cx.tables.node_id_to_type(p.hir_id); if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) { check_move(p, sub.as_ref().map(|p| &**p)); } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index cce511daf8ae..c0a050cb6b43 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -275,7 +275,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprPath(ref qpath) => { - let substs = cx.tables.node_substs(e.id).subst(tcx, cx.substs); + let substs = cx.tables.node_substs(e.hir_id).subst(tcx, cx.substs); match cx.tables.qpath_def(qpath, e.hir_id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 30183ca2daf7..bad9895420a0 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -303,7 +303,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { - let mut ty = self.tables.node_id_to_type(pat.id); + let mut ty = self.tables.node_id_to_type(pat.hir_id); let kind = match pat.node { PatKind::Wild => PatternKind::Wild, @@ -321,7 +321,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Path(ref qpath) => { - return self.lower_path(qpath, (pat.id, pat.hir_id), pat.id, pat.span); + return self.lower_path(qpath, pat.hir_id, pat.id, pat.span); } PatKind::Ref(ref subpattern, _) | @@ -330,7 +330,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Slice(ref prefix, ref slice, ref suffix) => { - let ty = self.tables.node_id_to_type(pat.id); + let ty = self.tables.node_id_to_type(pat.hir_id); match ty.sty { ty::TyRef(_, mt) => PatternKind::Deref { @@ -355,7 +355,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Tuple(ref subpatterns, ddpos) => { - let ty = self.tables.node_id_to_type(pat.id); + let ty = self.tables.node_id_to_type(pat.hir_id); match ty.sty { ty::TyTuple(ref tys, _) => { let subpatterns = @@ -376,7 +376,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatKind::Binding(_, def_id, ref ident, ref sub) => { let id = self.tcx.hir.as_local_node_id(def_id).unwrap(); - let var_ty = self.tables.node_id_to_type(pat.id); + let var_ty = self.tables.node_id_to_type(pat.hir_id); let region = match var_ty.sty { ty::TyRef(r, _) => Some(r), _ => None, @@ -590,12 +590,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_path(&mut self, qpath: &hir::QPath, - (id, hir_id): (ast::NodeId, hir::HirId), + id: hir::HirId, pat_id: ast::NodeId, span: Span) -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); - let def = self.tables.qpath_def(qpath, hir_id); + let def = self.tables.qpath_def(qpath, id); let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); @@ -695,7 +695,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { hir::ExprPath(ref qpath) => qpath, _ => bug!() }; - let ty = self.tables.node_id_to_type(callee.id); + let ty = self.tables.node_id_to_type(callee.hir_id); let def = self.tables.qpath_def(qpath, callee.hir_id); match def { Def::Fn(..) | Def::Method(..) => self.lower_lit(expr), @@ -755,7 +755,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } hir::ExprPath(ref qpath) => { - return self.lower_path(qpath, (expr.id, expr.hir_id), pat_id, span); + return self.lower_path(qpath, expr.hir_id, pat_id, span); } _ => self.lower_lit(expr) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 85ec606e87ef..56c0fa7b2adf 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -139,7 +139,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { } fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { - let ty = cx.tables.node_id_to_type(e.id); + let ty = cx.tables.node_id_to_type(e.hir_id); self.check_heap_type(cx, e.span, ty); } } @@ -934,9 +934,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Check for method calls and overloaded operators. if cx.tables.is_method_call(expr) { - let local_id = cx.tcx.hir.definitions().node_to_hir_id(id).local_id; - let def_id = cx.tables.type_dependent_defs[&local_id].def_id(); - let substs = cx.tables.node_substs(id); + let hir_id = cx.tcx.hir.definitions().node_to_hir_id(id); + let def_id = cx.tables.type_dependent_defs[&hir_id.local_id].def_id(); + let substs = cx.tables.node_substs(hir_id); if method_call_refers_to_method(cx, method, def_id, substs, id) { return true; } @@ -952,7 +952,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { }; match def { Def::Method(def_id) => { - let substs = cx.tables.node_substs(callee.id); + let substs = cx.tables.node_substs(callee.hir_id); method_call_refers_to_method(cx, method, def_id, substs, id) } _ => false, @@ -1188,7 +1188,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { if !def_id_is_transmute(cx, did) { return None; } - let sig = cx.tables.node_id_to_type(expr.id).fn_sig(cx.tcx); + let sig = cx.tables.node_id_to_type(expr.hir_id).fn_sig(cx.tcx); let from = sig.inputs().skip_binder()[0]; let to = *sig.output().skip_binder(); return Some((&from.sty, &to.sty)); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index aca98df9cc99..cdf099679608 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -92,7 +92,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } if binop.node.is_shift() { - let opt_ty_bits = match cx.tables.node_id_to_type(l.id).sty { + let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty { ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)), ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)), _ => None, @@ -135,7 +135,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } hir::ExprLit(ref lit) => { - match cx.tables.node_id_to_type(e.id).sty { + match cx.tables.node_id_to_type(e.hir_id).sty { ty::TyInt(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | @@ -285,7 +285,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { // Normalize the binop so that the literal is always on the RHS in // the comparison let norm_binop = if swap { rev_binop(binop) } else { binop }; - match cx.tables.node_id_to_type(expr.id).sty { + match cx.tables.node_id_to_type(expr.hir_id).sty { ty::TyInt(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i128 = match lit.node { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 3353fb9a5b49..66817fda5b7b 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -202,7 +202,8 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, closure_expr_id: ast::NodeId, body_id: hir::BodyId) -> Ty<'tcx> { - let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id); + let closure_expr_hir_id = tcx.hir.node_to_hir_id(closure_expr_id); + let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_hir_id); let closure_def_id = tcx.hir.local_def_id(closure_expr_id); let region = ty::ReFree(ty::FreeRegion { diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index c91326f6d874..fa54925c6e75 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -95,7 +95,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, block: &'tcx hir::Block) -> ExprRef<'tcx> { - let block_ty = cx.tables().node_id_to_type(block.id); + let block_ty = cx.tables().node_id_to_type(block.hir_id); let temp_lifetime = cx.region_maps.temporary_scope(block.id); let expr = Expr { ty: block_ty, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 3effc29d67e2..ea9a19c83782 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -217,7 +217,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, None }; if let Some((adt_def, index)) = adt_data { - let substs = cx.tables().node_substs(fun.id); + let substs = cx.tables().node_substs(fun.hir_id); let field_refs = args.iter() .enumerate() .map(|(idx, e)| { @@ -236,7 +236,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } else { ExprKind::Call { - ty: cx.tables().node_id_to_type(fun.id), + ty: cx.tables().node_id_to_type(fun.hir_id), fun: fun.to_ref(), args: args.to_ref(), } @@ -582,7 +582,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let (def_id, substs) = custom_callee.unwrap_or_else(|| { cx.tables().validate_hir_id(expr.hir_id); (cx.tables().type_dependent_defs[&expr.hir_id.local_id].def_id(), - cx.tables().node_substs(expr.id)) + cx.tables().node_substs(expr.hir_id)) }); Expr { temp_lifetime: temp_lifetime, @@ -620,7 +620,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) -> ExprKind<'tcx> { - let substs = cx.tables().node_substs(expr.id); + let substs = cx.tables().node_substs(expr.hir_id); match def { // A regular function, constructor function or a constant. Def::Fn(def_id) | @@ -642,7 +642,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::StructCtor(def_id, CtorKind::Const) | Def::VariantCtor(def_id, CtorKind::Const) => { - match cx.tables().node_id_to_type(expr.id).sty { + match cx.tables().node_id_to_type(expr.hir_id).sty { // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. ty::TyAdt(adt_def, substs) => { @@ -684,10 +684,12 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, id_var, index, closure_expr_id); - let var_ty = cx.tables().node_id_to_type(id_var); + let var_ty = cx.tables() + .node_id_to_type(cx.tcx.hir.node_to_hir_id(id_var)); // FIXME free regions in closures are not right - let closure_ty = cx.tables().node_id_to_type(closure_expr_id); + let closure_ty = cx.tables() + .node_id_to_type(cx.tcx.hir.node_to_hir_id(closure_expr_id)); // FIXME we're just hard-coding the idea that the // signature will be &self or &mut self and hence will @@ -879,7 +881,8 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id); - let var_ty = cx.tables().node_id_to_type(id_var); + let var_ty = cx.tables() + .node_id_to_type(cx.tcx.hir.node_to_hir_id(id_var)); let captured_var = Expr { temp_lifetime: temp_lifetime, ty: var_ty, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b3a1509972a0..c06ae721f365 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -219,7 +219,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { let outer = self.promotable; self.promotable = true; - let node_ty = self.tables.node_id_to_type(ex.id); + let node_ty = self.tables.node_id_to_type(ex.hir_id); check_expr(self, ex, node_ty); check_adjustments(self, ex); @@ -297,7 +297,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node v.promotable = false; } hir::ExprUnary(op, ref inner) => { - match v.tables.node_id_to_type(inner.id).sty { + match v.tables.node_id_to_type(inner.hir_id).sty { ty::TyRawPtr(_) => { assert!(op == hir::UnDeref); @@ -307,7 +307,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprBinary(op, ref lhs, _) => { - match v.tables.node_id_to_type(lhs.id).sty { + match v.tables.node_id_to_type(lhs.hir_id).sty { ty::TyRawPtr(_) => { assert!(op.node == hir::BiEq || op.node == hir::BiNe || op.node == hir::BiLe || op.node == hir::BiLt || diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index c1cab0cc8f74..1c5e528d887d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -639,7 +639,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { } // Take node ID of an expression or pattern and check its type for privacy. - fn check_expr_pat_type(&mut self, id: ast::NodeId, span: Span) -> bool { + fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool { self.span = span; if let Some(ty) = self.tables.node_id_to_type_opt(id) { if ty.visit_with(self) { @@ -649,7 +649,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { if self.tables.node_substs(id).visit_with(self) { return true; } - if let Some(adjustments) = self.tables.adjustments.get(&id) { + if let Some(adjustments) = self.tables.adjustments.get(&id.local_id) { for adjustment in adjustments { if adjustment.target.visit_with(self) { return true; @@ -735,14 +735,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Check types of expressions fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - if self.check_expr_pat_type(expr.id, expr.span) { + if self.check_expr_pat_type(expr.hir_id, expr.span) { // Do not check nested expressions if the error already happened. return; } match expr.node { hir::ExprAssign(.., ref rhs) | hir::ExprMatch(ref rhs, ..) => { // Do not report duplicate errors for `x = y` and `match x { ... }`. - if self.check_expr_pat_type(rhs.id, rhs.span) { + if self.check_expr_pat_type(rhs.hir_id, rhs.span) { return; } } @@ -783,7 +783,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Check types of patterns fn visit_pat(&mut self, pattern: &'tcx hir::Pat) { - if self.check_expr_pat_type(pattern.id, pattern.span) { + if self.check_expr_pat_type(pattern.hir_id, pattern.span) { // Do not check nested patterns if the error already happened. return; } @@ -793,7 +793,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { fn visit_local(&mut self, local: &'tcx hir::Local) { if let Some(ref init) = local.init { - if self.check_expr_pat_type(init.id, init.span) { + if self.check_expr_pat_type(init.hir_id, init.span) { // Do not report duplicate errors for `let x = y`. return; } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 4740f9a0d5a5..af816473033f 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -345,7 +345,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { collector.visit_pat(&arg.pat); let span_utils = self.span.clone(); for &(id, ref p, ..) in &collector.collected_paths { - let typ = match self.save_ctxt.tables.node_types.get(&id) { + let hir_id = self.tcx.hir.node_to_hir_id(id); + let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { Some(s) => s.to_string(), None => continue, }; @@ -893,7 +894,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { match p.node { PatKind::Struct(ref _path, ref fields, _) => { // FIXME do something with _path? - let adt = match self.save_ctxt.tables.node_id_to_type_opt(p.id) { + let hir_id = self.tcx.hir.node_to_hir_id(p.id); + let adt = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { Some(ty) => ty.ty_adt_def().unwrap(), None => { visit::walk_pat(self, p); @@ -935,7 +937,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { ast::Mutability::Immutable => value.to_string(), _ => String::new(), }; - let typ = match self.save_ctxt.tables.node_types.get(&id) { + let hir_id = self.tcx.hir.node_to_hir_id(id); + let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { Some(typ) => { let typ = typ.to_string(); if !value.is_empty() { @@ -1466,8 +1469,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } else { "".to_string() }; - let typ = self.save_ctxt.tables.node_types - .get(&id).map(|t| t.to_string()).unwrap_or(String::new()); + let hir_id = self.tcx.hir.node_to_hir_id(id); + let typ = self.save_ctxt + .tables + .node_id_to_type_opt(hir_id) + .map(|t| t.to_string()) + .unwrap_or(String::new()); value.push_str(": "); value.push_str(&typ); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index eaff8e7b8ace..e1ced048870b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -323,7 +323,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.write_ty(pat.id, ty); + self.write_ty(pat.hir_id, ty); // (*) In most of the cases above (literals and constants being // the exception), we relate types using strict equality, evewn diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index cdf1c3b235b6..460e2858b22e 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -314,7 +314,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { TupleArgumentsFlag::TupleArguments, expected); - self.write_method_call((call_expr.id, call_expr.hir_id), method_callee); + self.write_method_call(call_expr.hir_id, method_callee); output_type } } @@ -364,7 +364,7 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { adjustments.extend(autoref); fcx.apply_adjustments(self.callee_expr, adjustments); - fcx.write_method_call((self.call_expr.id, self.call_expr.hir_id), + fcx.write_method_call(self.call_expr.hir_id, method_callee); } None => { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 934a4f9b2968..428938eae828 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -844,7 +844,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // First try to coerce the new expression to the type of the previous ones, // 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) { + if !self.tables.borrow().adjustments.contains_key(&new.hir_id.local_id) { let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty)); match result { Ok(ok) => { @@ -866,7 +866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Adjustment { kind: Adjust::Deref(_), .. }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. } ] => { - match self.node_ty(expr.id).sty { + match self.node_ty(expr.hir_id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore, because // the next adjustment can only be a Deref diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a6f904b0c96c..0294dab17d55 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -445,11 +445,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Fix up the autoderefs. Autorefs can only occur immediately preceding // overloaded lvalue ops, and will be fixed by them in order to get // the correct region. - let mut source = self.node_ty(expr.id); + let mut source = self.node_ty(expr.hir_id); // Do not mutate adjustments in place, but rather take them, // and replace them after mutating them, to avoid having the // tables borrowed during (`deref_mut`) method resolution. - let previous_adjustments = self.tables.borrow_mut().adjustments.remove(&expr.id); + let previous_adjustments = self.tables + .borrow_mut() + .adjustments + .remove(&expr.hir_id.local_id); if let Some(mut adjustments) = previous_adjustments { let pref = LvaluePreference::PreferMutLvalue; for adjustment in &mut adjustments { @@ -466,12 +469,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } source = adjustment.target; } - self.tables.borrow_mut().adjustments.insert(expr.id, adjustments); + self.tables.borrow_mut().adjustments.insert(expr.hir_id.local_id, adjustments); } match expr.node { hir::ExprIndex(ref base_expr, ref index_expr) => { - let index_expr_ty = self.node_ty(index_expr.id); + let index_expr_ty = self.node_ty(index_expr.hir_id); self.convert_lvalue_op_to_mutable( LvalueOp::Index, expr, base_expr, &[index_expr_ty]); } @@ -498,7 +501,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } let base_ty = self.tables.borrow().expr_adjustments(base_expr).last() - .map_or_else(|| self.node_ty(expr.id), |adj| adj.target); + .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target); let base_ty = self.resolve_type_vars_if_possible(&base_ty); // Need to deref because overloaded lvalue ops take self by-reference. @@ -513,7 +516,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed") }; debug!("convert_lvalue_op_to_mutable: method={:?}", method); - self.write_method_call((expr.id, expr.hir_id), method); + self.write_method_call(expr.hir_id, method); let (region, mutbl) = if let ty::TyRef(r, mt) = method.sig.inputs()[0].sty { (r, mt.mutbl) @@ -523,8 +526,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Convert the autoref in the base expr to mutable with the correct // region and mutability. - let base_expr_ty = self.node_ty(base_expr.id); - if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&base_expr.id) { + let base_expr_ty = self.node_ty(base_expr.hir_id); + if let Some(adjustments) = self.tables + .borrow_mut() + .adjustments + .get_mut(&base_expr.hir_id.local_id) { let mut source = base_expr_ty; for adjustment in &mut adjustments[..] { if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 885472a76a92..facacdc8d114 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1024,7 +1024,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.require_type_is_sized(arg_ty, decl.output.span(), traits::MiscObligation); } - fcx.write_ty(arg.id, arg_ty); + fcx.write_ty(arg.hir_id, arg_ty); } inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); @@ -1807,10 +1807,14 @@ 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, self.resolve_type_vars_if_possible(&ty), self.tag()); - self.tables.borrow_mut().node_types.insert(node_id, ty); + pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { + debug!("write_ty({:?}, {:?}) in fcx {}", + id, self.resolve_type_vars_if_possible(&ty), self.tag()); + { + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(id); + tables.node_types.insert(id.local_id, ty); + } if ty.references_error() { self.has_errors.set(true); @@ -1821,24 +1825,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The NodeId and the ItemLocalId must identify the same item. We just pass // both of them for consistency checking. pub fn write_method_call(&self, - (node_id, hir_id): (ast::NodeId, hir::HirId), + hir_id: hir::HirId, method: MethodCallee<'tcx>) { { let mut tables = self.tables.borrow_mut(); tables.validate_hir_id(hir_id); tables.type_dependent_defs.insert(hir_id.local_id, Def::Method(method.def_id)); } - self.write_substs(node_id, method.substs); + self.write_substs(hir_id, method.substs); } - pub fn write_substs(&self, node_id: ast::NodeId, substs: &'tcx Substs<'tcx>) { + pub fn write_substs(&self, node_id: hir::HirId, substs: &'tcx Substs<'tcx>) { if !substs.is_noop() { - debug!("write_substs({}, {:?}) in fcx {}", + debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); - self.tables.borrow_mut().node_substs.insert(node_id, substs); + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(node_id); + tables.node_substs.insert(node_id.local_id, substs); } } @@ -1849,7 +1855,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return; } - match self.tables.borrow_mut().adjustments.entry(expr.id) { + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(expr.hir_id); + match tables.adjustments.entry(expr.hir_id.local_id) { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); @@ -2002,13 +2010,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { t } - pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> { - match self.tables.borrow().node_types.get(&id) { + pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { + let tables = self.tables.borrow(); + tables.validate_hir_id(id); + match tables.node_types.get(&id.local_id) { Some(&t) => t, None if self.err_count_since_creation() != 0 => self.tcx.types.err, None => { + let node_id = self.tcx.hir.definitions().find_node_for_hir_id(id); bug!("no type for node {}: {} in fcx {}", - id, self.tcx.hir.node_to_string(id), + node_id, self.tcx.hir.node_to_string(node_id), self.tag()); } } @@ -2276,7 +2287,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } self.apply_adjustments(base_expr, adjustments); - self.write_method_call((expr.id, expr.hir_id), method); + self.write_method_call(expr.hir_id, method); (input_ty, self.make_overloaded_lvalue_return_type(method).ty) }); if result.is_some() { @@ -2665,7 +2676,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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), + assert!(!self.tables.borrow().adjustments.contains_key(&expr.hir_id.local_id), "expression with never type wound up being adjusted"); let adj_ty = self.next_diverging_ty_var( TypeVariableOrigin::AdjustmentType(expr.span)); @@ -2816,7 +2827,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, rcvr) { Ok(method) => { - self.write_method_call((expr.id, expr.hir_id), method); + self.write_method_call(expr.hir_id, method); Ok(method) } Err(error) => { @@ -3448,7 +3459,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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. - self.write_ty(expr.id, ty); + self.write_ty(expr.hir_id, ty); // Combine the diverging and has_error flags. self.diverges.set(self.diverges.get() | old_diverges); @@ -3521,7 +3532,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }]); } oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; - self.write_method_call((expr.id, expr.hir_id), method); + self.write_method_call(expr.hir_id, method); } else { type_error_struct!(tcx.sess, expr.span, oprnd_t, E0614, "type `{}` cannot be dereferenced", @@ -3599,7 +3610,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. - let substs = self.tables.borrow().node_substs(expr.id); + let substs = self.tables.borrow().node_substs(expr.hir_id); self.add_wf_bounds(substs, expr); ty @@ -4101,19 +4112,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_decl_local(&self, local: &'gcx hir::Local) { let t = self.local_ty(local.span, local.id); - self.write_ty(local.id, t); + self.write_ty(local.hir_id, t); if let Some(ref init) = local.init { let init_ty = self.check_decl_initializer(local, &init); if init_ty.references_error() { - self.write_ty(local.id, init_ty); + self.write_ty(local.hir_id, init_ty); } } self.check_pat(&local.pat, t); - let pat_ty = self.node_ty(local.pat.id); + let pat_ty = self.node_ty(local.pat.hir_id); if pat_ty.references_error() { - self.write_ty(local.id, pat_ty); + self.write_ty(local.hir_id, pat_ty); } } @@ -4265,7 +4276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty = self.tcx.types.err } - self.write_ty(blk.id, ty); + self.write_ty(blk.hir_id, ty); *self.ps.borrow_mut() = prev; ty @@ -4443,7 +4454,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::StmtSemi(ref e, _) => e, _ => return, }; - let last_expr_ty = self.node_ty(last_expr.id); + let last_expr_ty = self.node_ty(last_expr.hir_id); if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { return; } @@ -4586,7 +4597,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let nid = self.tcx.hir.as_local_node_id(def_id).unwrap(); let ty = self.local_ty(span, nid); let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(node_id, ty); + self.write_ty(self.tcx.hir.node_to_hir_id(node_id), ty); return ty; } _ => {} @@ -4718,7 +4729,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("instantiate_value_path: type of {:?} is {:?}", node_id, ty_substituted); - self.write_substs(node_id, substs); + self.write_substs(self.tcx.hir.node_to_hir_id(node_id), substs); ty_substituted } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 71457377b108..f2104b8dbae0 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -210,11 +210,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // some cases applied on the RHS, on top of which we need // to autoref, which is not allowed by apply_adjustments. // self.apply_adjustments(rhs_expr, vec![autoref]); - self.tables.borrow_mut().adjustments.entry(rhs_expr.id) + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(rhs_expr.hir_id); + tables.adjustments.entry(rhs_expr.hir_id.local_id) .or_insert(vec![]).push(autoref); } } - self.write_method_call((expr.id, expr.hir_id), method); + self.write_method_call(expr.hir_id, method); method.sig.output() } @@ -340,7 +342,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(op.is_by_value()); match self.lookup_op_method(operand_ty, &[], Op::Unary(op, ex.span)) { Ok(method) => { - self.write_method_call((ex.id, ex.hir_id), method); + self.write_method_call(ex.hir_id, method); method.sig.output() } Err(()) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9b7ecc194ca8..d88ed888338c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } /// Try to resolve the type for the given node. - fn resolve_node_type(&self, id: ast::NodeId) -> Ty<'tcx> { + fn resolve_node_type(&self, id: hir::HirId) -> Ty<'tcx> { let t = self.node_ty(id); self.resolve_type(t) } @@ -338,8 +338,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("visit_fn_body body.id {:?} call_site_scope: {:?}", body.id(), call_site_scope); let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope)); + let body_hir_id = self.tcx.hir.node_to_hir_id(body_id.node_id); self.type_of_node_must_outlive(infer::CallReturn(span), - body_id.node_id, + body_hir_id, call_site_region); self.region_bound_pairs.truncate(old_region_bounds_pairs_len); @@ -613,9 +614,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let var_region = self.tcx.mk_region(ty::ReScope(var_scope)); let origin = infer::BindingTypeIsNotValidAtDecl(span); - self.type_of_node_must_outlive(origin, id, var_region); + let hir_id = self.tcx.hir.node_to_hir_id(id); + self.type_of_node_must_outlive(origin, hir_id, var_region); - let typ = self.resolve_node_type(id); + let typ = self.resolve_node_type(hir_id); let _ = dropck::check_safety_of_destructor_if_necessary( self, typ, span, var_scope); }) @@ -664,7 +666,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // No matter what, the type of each expression must outlive the // scope of that expression. This also guarantees basic WF. - let expr_ty = self.resolve_node_type(expr.id); + let expr_ty = self.resolve_node_type(expr.hir_id); // the region corresponding to this expression let expr_region = self.tcx.node_scope_region(expr.id); self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), @@ -686,7 +688,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { infer::ParameterOrigin::OverloadedOperator }; - let substs = self.tables.borrow().node_substs(expr.id); + let substs = self.tables.borrow().node_substs(expr.hir_id); self.substs_wf_in_scope(origin, substs, expr.span, expr_region); // Arguments (sub-expressions) are checked via `constrain_call`, below. } @@ -709,7 +711,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { expr, self.repeating_scope); match expr.node { hir::ExprPath(_) => { - let substs = self.tables.borrow().node_substs(expr.id); + let substs = self.tables.borrow().node_substs(expr.hir_id); let origin = infer::ParameterOrigin::Path; self.substs_wf_in_scope(origin, substs, expr.span, expr_region); } @@ -718,7 +720,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { if is_method_call { self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e)); } else { - self.constrain_callee(callee.id, expr, &callee); + self.constrain_callee(&callee); self.constrain_call(expr, None, args.iter().map(|e| &*e)); } @@ -812,7 +814,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // adjustments*. // // FIXME(#6268) nested method calls requires that this rule change - let ty0 = self.resolve_node_type(expr.id); + let ty0 = self.resolve_node_type(expr.hir_id); self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region); intravisit::walk_expr(self, expr); } @@ -849,7 +851,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { ret_expr.id, call_site_scope); let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap())); self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span), - ret_expr.id, + ret_expr.hir_id, call_site_region); intravisit::walk_expr(self, expr); } @@ -870,8 +872,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { cast_expr, source_expr); - let source_ty = self.resolve_node_type(source_expr.id); - let target_ty = self.resolve_node_type(cast_expr.id); + let source_ty = self.resolve_node_type(source_expr.hir_id); + let target_ty = self.resolve_node_type(cast_expr.hir_id); self.walk_cast(cast_expr, source_ty, target_ty); } @@ -915,11 +917,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.set_repeating_scope(repeating_scope); } - fn constrain_callee(&mut self, - callee_id: ast::NodeId, - _call_expr: &hir::Expr, - _callee_expr: &hir::Expr) { - let callee_ty = self.resolve_node_type(callee_id); + fn constrain_callee(&mut self, callee_expr: &hir::Expr) { + let callee_ty = self.resolve_node_type(callee_expr.hir_id); match callee_ty.sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { } _ => { @@ -962,14 +961,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: self.type_of_node_must_outlive(infer::CallArg(arg_expr.span), - arg_expr.id, callee_region); + arg_expr.hir_id, + callee_region); } // as loop above, but for receiver if let Some(r) = receiver { debug!("receiver: {:?}", r); self.type_of_node_must_outlive(infer::CallRcvr(r.span), - r.id, callee_region); + r.hir_id, + callee_region); } } @@ -1038,7 +1039,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // // FIXME(#6268) remove to support nested method calls self.type_of_node_must_outlive(infer::AutoBorrow(expr.span), - expr.id, expr_region); + expr.hir_id, + expr_region); } cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?; @@ -1109,21 +1111,27 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// adjustments) are valid for at least `minimum_lifetime` fn type_of_node_must_outlive(&mut self, origin: infer::SubregionOrigin<'tcx>, - id: ast::NodeId, + hir_id: hir::HirId, minimum_lifetime: ty::Region<'tcx>) { // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. - let ty0 = self.resolve_node_type(id); - let ty = self.tables.borrow().adjustments.get(&id) - .and_then(|adj| adj.last()) - .map_or(ty0, |adj| adj.target); + let ty0 = self.resolve_node_type(hir_id); + + let ty = { + let tables = self.tables.borrow(); + tables.validate_hir_id(hir_id); + tables.adjustments + .get(&hir_id.local_id) + .and_then(|adj| adj.last()) + .map_or(ty0, |adj| adj.target) + }; let ty = self.resolve_type(ty); debug!("constrain_regions_in_type_of_node(\ - ty={}, ty0={}, id={}, minimum_lifetime={:?})", + ty={}, ty0={}, id={:?}, minimum_lifetime={:?})", ty, ty0, - id, minimum_lifetime); + hir_id, minimum_lifetime); self.type_must_outlive(origin, ty, minimum_lifetime); } @@ -1137,7 +1145,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("link_addr_of: cmt={:?}", cmt); - self.link_region_from_node_type(expr.span, expr.id, mutability, cmt); + self.link_region_from_node_type(expr.span, expr.hir_id, mutability, cmt); } /// Computes the guarantors for any ref bindings in a `let` and @@ -1173,7 +1181,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) { debug!("regionck::link_fn_args(body_scope={:?})", body_scope); for arg in args { - let arg_ty = self.node_ty(arg.id); + let arg_ty = self.node_ty(arg.hir_id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); let arg_cmt = self.with_mc(|mc| { mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty) @@ -1200,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let bm = *mc.tables.pat_binding_modes.get(&sub_pat.id) .expect("missing binding mode"); if let ty::BindByReference(mutbl) = bm { - self.link_region_from_node_type(sub_pat.span, sub_pat.id, + self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id, mutbl, sub_cmt); } } @@ -1236,7 +1244,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// which must be some reference (`&T`, `&str`, etc). fn link_region_from_node_type(&self, span: Span, - id: ast::NodeId, + id: hir::HirId, mutbl: hir::Mutability, cmt_borrowed: mc::cmt<'tcx>) { debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 59ca896b347f..22047ed583e2 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -78,7 +78,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { hir::ExprClosure(cc, _, body_id, _) => { let body = self.fcx.tcx.hir.body(body_id); self.visit_body(body); - self.fcx.analyze_closure(expr.id, expr.span, body, cc); + self.fcx.analyze_closure((expr.id, expr.hir_id), expr.span, body, cc); } _ => { } @@ -90,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn analyze_closure(&self, - id: ast::NodeId, + (id, hir_id): (ast::NodeId, hir::HirId), span: Span, body: &hir::Body, capture_clause: hir::CaptureClause) { @@ -172,7 +172,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // inference algorithm will reject it). // Extract the type variables UV0...UVn. - let (def_id, closure_substs) = match self.node_ty(id).sty { + let (def_id, closure_substs) = match self.node_ty(hir_id).sty { ty::TyClosure(def_id, substs) => (def_id, substs), ref t => { span_bug!( @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { freevars.iter().map(|freevar| { let def_id = freevar.def.def_id(); let var_id = tcx.hir.as_local_node_id(def_id).unwrap(); - let freevar_ty = self.node_ty(var_id); + let freevar_ty = self.node_ty(tcx.hir.node_to_hir_id(var_id)); let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: closure_id diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 93d0e6e976a7..058cef71d4a8 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -35,7 +35,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut wbcx = WritebackCx::new(self, body); for arg in &body.arguments { - wbcx.visit_node_id(arg.pat.span, (arg.id, arg.hir_id)); + wbcx.visit_node_id(arg.pat.span, arg.hir_id); } wbcx.visit_body(body); wbcx.visit_upvar_borrow_map(); @@ -90,10 +90,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.fcx.tcx } - fn write_ty_to_tables(&mut self, node_id: ast::NodeId, ty: Ty<'gcx>) { - debug!("write_ty_to_tables({}, {:?})", node_id, ty); + fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) { + debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty); assert!(!ty.needs_infer()); - self.tables.node_types.insert(node_id, ty); + self.tables.validate_hir_id(hir_id); + self.tables.node_types.insert(hir_id.local_id, ty); } // Hacky hack: During type-checking, we treat *all* operators @@ -104,39 +105,39 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { match e.node { hir::ExprUnary(hir::UnNeg, ref inner) | hir::ExprUnary(hir::UnNot, ref inner) => { - let inner_ty = self.fcx.node_ty(inner.id); + let inner_ty = self.fcx.node_ty(inner.hir_id); let inner_ty = self.fcx.resolve_type_vars_if_possible(&inner_ty); if inner_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); tables.validate_hir_id(e.hir_id); tables.type_dependent_defs.remove(&e.hir_id.local_id); - tables.node_substs.remove(&e.id); + tables.node_substs.remove(&e.hir_id.local_id); } } hir::ExprBinary(ref op, ref lhs, ref rhs) | hir::ExprAssignOp(ref op, ref lhs, ref rhs) => { - let lhs_ty = self.fcx.node_ty(lhs.id); + let lhs_ty = self.fcx.node_ty(lhs.hir_id); let lhs_ty = self.fcx.resolve_type_vars_if_possible(&lhs_ty); - let rhs_ty = self.fcx.node_ty(rhs.id); + let rhs_ty = self.fcx.node_ty(rhs.hir_id); let rhs_ty = self.fcx.resolve_type_vars_if_possible(&rhs_ty); if lhs_ty.is_scalar() && rhs_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); tables.validate_hir_id(e.hir_id); tables.type_dependent_defs.remove(&e.hir_id.local_id); - tables.node_substs.remove(&e.id); + tables.node_substs.remove(&e.hir_id.local_id); match e.node { hir::ExprBinary(..) => { if !op.node.is_by_value() { - tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); - tables.adjustments.get_mut(&rhs.id).map(|a| a.pop()); + tables.adjustments.get_mut(&lhs.hir_id.local_id).map(|a| a.pop()); + tables.adjustments.get_mut(&rhs.hir_id.local_id).map(|a| a.pop()); } }, hir::ExprAssignOp(..) => { - tables.adjustments.get_mut(&lhs.id).map(|a| a.pop()); + tables.adjustments.get_mut(&lhs.hir_id.local_id).map(|a| a.pop()); }, _ => {}, } @@ -163,12 +164,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_expr(&mut self, e: &'gcx hir::Expr) { self.fix_scalar_builtin_expr(e); - self.visit_node_id(e.span, (e.id, e.hir_id)); + self.visit_node_id(e.span, e.hir_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(e.span, (arg.id, arg.hir_id)); + self.visit_node_id(e.span, arg.hir_id); } self.visit_body(body); @@ -178,7 +179,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_block(&mut self, b: &'gcx hir::Block) { - self.visit_node_id(b.span, (b.id, b.hir_id)); + self.visit_node_id(b.span, b.hir_id); intravisit::walk_block(self, b); } @@ -192,7 +193,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { _ => {} }; - self.visit_node_id(p.span, (p.id, p.hir_id)); + self.visit_node_id(p.span, p.hir_id); intravisit::walk_pat(self, p); } @@ -200,7 +201,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { 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); + self.write_ty_to_tables(l.hir_id, var_ty); } } @@ -279,13 +280,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } }); - self.tables.node_types.insert(node_id, outside_ty); + let hir_id = self.tcx().hir.node_to_hir_id(node_id); + self.tables.validate_hir_id(hir_id); + self.tables.node_types.insert(hir_id.local_id, outside_ty); } } - fn visit_node_id(&mut self, - span: Span, - (node_id, hir_id): (ast::NodeId, hir::HirId)) { + fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) { { let mut fcx_tables = self.fcx.tables.borrow_mut(); fcx_tables.validate_hir_id(hir_id); @@ -297,34 +298,39 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } // Resolve any borrowings for the node with id `node_id` - self.visit_adjustments(span, node_id); + self.visit_adjustments(span, hir_id); // Resolve the type of the node with id `node_id` - let n_ty = self.fcx.node_ty(node_id); + let n_ty = self.fcx.node_ty(hir_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); + self.write_ty_to_tables(hir_id, n_ty); + debug!("Node {:?} has type {:?}", hir_id, n_ty); // Resolve any substitutions - if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&node_id) { + if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&hir_id.local_id) { let substs = self.resolve(&substs, &span); - debug!("write_substs_to_tcx({}, {:?})", node_id, substs); + debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); assert!(!substs.needs_infer()); - self.tables.node_substs.insert(node_id, substs); + self.tables.node_substs.insert(hir_id.local_id, substs); } } - fn visit_adjustments(&mut self, span: Span, node_id: ast::NodeId) { - let adjustment = self.fcx.tables.borrow_mut().adjustments.remove(&node_id); + fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) { + let adjustment = { + let mut fcx_tables = self.fcx.tables.borrow_mut(); + fcx_tables.validate_hir_id(hir_id); + fcx_tables.adjustments.remove(&hir_id.local_id) + }; match adjustment { None => { - debug!("No adjustments for node {}", node_id); + debug!("No adjustments for node {:?}", hir_id); } Some(adjustment) => { let resolved_adjustment = self.resolve(&adjustment, &span); - debug!("Adjustments for node {}: {:?}", node_id, resolved_adjustment); - self.tables.adjustments.insert(node_id, resolved_adjustment); + debug!("Adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); + self.tables.validate_hir_id(hir_id); + self.tables.adjustments.insert(hir_id.local_id, resolved_adjustment); } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fba32dbb889d..7b63bd883f97 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1187,7 +1187,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => { let owner = tcx.hir.get_parent_did(node_id); - tcx.typeck_tables_of(owner).node_id_to_type(node_id) + let hir_id = tcx.hir.node_to_hir_id(node_id); + tcx.typeck_tables_of(owner).node_id_to_type(hir_id) } x => { From e777189b4accdd7a92adf8554a368d399ff7f3ee Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Aug 2017 15:06:10 +0200 Subject: [PATCH 26/88] Use ItemLocalId as key for TypeckTables::pat_binding_modes. --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 7 +++++-- src/librustc/middle/mem_categorization.rs | 13 +++++++++++-- src/librustc/ty/context.rs | 4 ++-- src/librustc_borrowck/borrowck/mod.rs | 9 +++++++-- src/librustc_const_eval/check_match.rs | 20 +++++++++++++++++--- src/librustc_const_eval/pattern.rs | 2 +- src/librustc_lint/unused.rs | 4 +++- src/librustc_typeck/check/_match.rs | 7 +++++-- src/librustc_typeck/check/regionck.rs | 3 ++- src/librustc_typeck/check/writeback.rs | 11 ++++++++--- 11 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index ab5051418802..21d797d1e9a7 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -642,7 +642,7 @@ for ty::TypeckTables<'gcx> { ich::hash_stable_itemlocalmap(hcx, hasher, node_types); ich::hash_stable_itemlocalmap(hcx, hasher, node_substs); ich::hash_stable_itemlocalmap(hcx, hasher, adjustments); - ich::hash_stable_nodemap(hcx, hasher, pat_binding_modes); + ich::hash_stable_itemlocalmap(hcx, hasher, pat_binding_modes); ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { let ty::UpvarId { var_id, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index b44f1c7da739..a11511c2434a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -797,7 +797,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pat); return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { if let PatKind::Binding(..) = pat.node { - let bm = *self.mc.tables.pat_binding_modes.get(&pat.id) + self.mc.tables.validate_hir_id(pat.hir_id); + let bm = *self.mc.tables.pat_binding_modes.get(&pat.hir_id.local_id) .expect("missing binding mode"); match bm { ty::BindByReference(..) => @@ -823,7 +824,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(_, def_id, ..) = pat.node { debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); - let bm = *mc.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode"); + mc.tables.validate_hir_id(pat.hir_id); + let bm = *mc.tables.pat_binding_modes.get(&pat.hir_id.local_id) + .expect("missing binding mode"); // pat_ty: the type of the binding being produced. let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7a949cf38b36..faa91d0fa3a9 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -334,7 +334,11 @@ impl MutabilityCategory { let ret = match tcx.hir.get(id) { hir_map::NodeLocal(p) => match p.node { PatKind::Binding(..) => { - let bm = *tables.pat_binding_modes.get(&p.id).expect("missing binding mode"); + + tables.validate_hir_id(p.hir_id); + let bm = *tables.pat_binding_modes + .get(&p.hir_id.local_id) + .expect("missing binding mode"); if bm == ty::BindByValue(hir::MutMutable) { McDeclared } else { @@ -481,7 +485,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // fundamental fix to this conflated use of the node id. let ret_ty = match pat.node { PatKind::Binding(..) => { - let bm = *self.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode"); + self.tables.validate_hir_id(pat.hir_id); + let bm = *self.tables + .pat_binding_modes + .get(&pat.hir_id.local_id) + .expect("missing binding mode"); + if let ty::BindByReference(_) = bm { // a bind-by-ref means that the base_ty will be the type of the ident itself, // but what we want here is the type of the underlying value being borrowed. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 528fb4e2e7fc..d4ff1590e8aa 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -230,7 +230,7 @@ pub struct TypeckTables<'tcx> { pub adjustments: ItemLocalMap>>, // Stores the actual binding mode for all instances of hir::BindingAnnotation. - pub pat_binding_modes: NodeMap, + pub pat_binding_modes: ItemLocalMap, /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, @@ -281,7 +281,7 @@ impl<'tcx> TypeckTables<'tcx> { node_types: ItemLocalMap(), node_substs: ItemLocalMap(), adjustments: ItemLocalMap(), - pat_binding_modes: NodeMap(), + pat_binding_modes: ItemLocalMap(), upvar_capture_map: FxHashMap(), closure_tys: NodeMap(), closure_kinds: NodeMap(), diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 6b31535c5a52..4b26aa95759d 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -899,8 +899,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; match pat.node { - hir::PatKind::Binding(..) => - *self.tables.pat_binding_modes.get(&pat.id).expect("missing binding mode"), + hir::PatKind::Binding(..) => { + self.tables.validate_hir_id(pat.hir_id); + *self.tables + .pat_binding_modes + .get(&pat.hir_id.local_id) + .expect("missing binding mode") + } _ => bug!("local is not a binding: {:?}", pat) } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 0d92bff02b12..a990670f08bf 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -269,7 +269,12 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) { pat.walk(|p| { if let PatKind::Binding(_, _, name, None) = p.node { - let bm = *cx.tables.pat_binding_modes.get(&p.id).expect("missing binding mode"); + cx.tables.validate_hir_id(p.hir_id); + let bm = *cx.tables + .pat_binding_modes + .get(&p.hir_id.local_id) + .expect("missing binding mode"); + if bm != ty::BindByValue(hir::MutImmutable) { // Nothing to check. return true; @@ -458,7 +463,12 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, let mut by_ref_span = None; for pat in pats { pat.each_binding(|_, id, span, _path| { - let bm = *cx.tables.pat_binding_modes.get(&id).expect("missing binding mode"); + let hir_id = cx.tcx.hir.node_to_hir_id(id); + cx.tables.validate_hir_id(hir_id); + let bm = *cx.tables + .pat_binding_modes + .get(&hir_id.local_id) + .expect("missing binding mode"); if let ty::BindByReference(..) = bm { by_ref_span = Some(span); } @@ -491,7 +501,11 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, for pat in pats { pat.walk(|p| { if let PatKind::Binding(_, _, _, ref sub) = p.node { - let bm = *cx.tables.pat_binding_modes.get(&p.id).expect("missing binding mode"); + cx.tables.validate_hir_id(p.hir_id); + let bm = *cx.tables + .pat_binding_modes + .get(&p.hir_id.local_id) + .expect("missing binding mode"); match bm { ty::BindByValue(..) => { let pat_ty = cx.tables.node_id_to_type(p.hir_id); diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index bad9895420a0..924193786c1f 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -381,7 +381,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyRef(r, _) => Some(r), _ => None, }; - let bm = *self.tables.pat_binding_modes.get(&pat.id) + let bm = *self.tables.pat_binding_modes.get(&pat.hir_id.local_id) .expect("missing binding mode"); let (mutability, mode) = match bm { ty::BindByValue(hir::MutMutable) => diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index ba17df4cdca4..f8f91e6c29d3 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -45,7 +45,9 @@ impl UnusedMut { let mut mutables = FxHashMap(); for p in pats { p.each_binding(|_, id, span, path1| { - let bm = match cx.tables.pat_binding_modes.get(&id) { + let hir_id = cx.tcx.hir.node_to_hir_id(id); + cx.tables.validate_hir_id(hir_id); + let bm = match cx.tables.pat_binding_modes.get(&hir_id.local_id) { Some(&bm) => bm, None => span_bug!(span, "missing binding mode"), }; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e1ced048870b..3a616dadc42f 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -118,8 +118,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // identical to what could be scraped from the HIR, but this will change with // default binding modes (#42640). let bm = ty::BindingMode::convert(ba); - self.inh.tables.borrow_mut().pat_binding_modes.insert(pat.id, bm); - + { + let mut inh_tables = self.inh.tables.borrow_mut(); + inh_tables.validate_hir_id(pat.hir_id); + inh_tables.pat_binding_modes.insert(pat.hir_id.local_id, bm); + } let typ = self.local_ty(pat.span, pat.id); match bm { ty::BindByReference(mutbl) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d88ed888338c..3113f4a569f2 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1205,7 +1205,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match sub_pat.node { // `ref x` pattern PatKind::Binding(..) => { - let bm = *mc.tables.pat_binding_modes.get(&sub_pat.id) + mc.tables.validate_hir_id(sub_pat.hir_id); + let bm = *mc.tables.pat_binding_modes.get(&sub_pat.hir_id.local_id) .expect("missing binding mode"); if let ty::BindByReference(mutbl) = bm { self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 058cef71d4a8..b689da6e3867 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -186,9 +186,14 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_pat(&mut self, p: &'gcx hir::Pat) { match p.node { hir::PatKind::Binding(..) => { - let bm = *self.fcx.tables.borrow().pat_binding_modes.get(&p.id) - .expect("missing binding mode"); - self.tables.pat_binding_modes.insert(p.id, bm); + let bm = { + let fcx_tables = self.fcx.tables.borrow(); + fcx_tables.validate_hir_id(p.hir_id); + *fcx_tables.pat_binding_modes.get(&p.hir_id.local_id) + .expect("missing binding mode") + }; + self.tables.validate_hir_id(p.hir_id); + self.tables.pat_binding_modes.insert(p.hir_id.local_id, bm); } _ => {} }; From 454533f5d93421eb2532fc6ee0fcd3007142cff6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Aug 2017 15:50:13 +0200 Subject: [PATCH 27/88] Use ItemLocalId as key for closure_tys and closure_kinds in TypeckTables. --- src/librustc/ich/impls_ty.rs | 4 ++-- src/librustc/infer/mod.rs | 13 +++++++++---- src/librustc/middle/mem_categorization.rs | 5 ++++- src/librustc/traits/error_reporting.rs | 5 ++++- src/librustc/ty/context.rs | 8 ++++---- src/librustc_borrowck/borrowck/mod.rs | 4 +++- src/librustc_typeck/check/closure.rs | 14 +++++++++----- src/librustc_typeck/check/method/probe.rs | 15 +++++++++------ src/librustc_typeck/check/mod.rs | 3 ++- src/librustc_typeck/check/upvar.rs | 12 +++++++++--- src/librustc_typeck/check/writeback.rs | 20 +++++++++++++++++--- src/librustc_typeck/collect.rs | 6 ++++-- 12 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 21d797d1e9a7..eec73937e2ca 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -654,8 +654,8 @@ for ty::TypeckTables<'gcx> { (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_itemlocalmap(hcx, hasher, closure_tys); + ich::hash_stable_itemlocalmap(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); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 6aa84a975033..727b0af2f547 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1331,9 +1331,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - return tables.borrow() - .closure_kinds - .get(&id) + let tables = tables.borrow(); + let hir_id = self.tcx.hir.node_to_hir_id(id); + tables.validate_hir_id(hir_id); + return tables.closure_kinds + .get(&hir_id.local_id) .cloned() .map(|(kind, _)| kind); } @@ -1353,7 +1355,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> { if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - if let Some(&ty) = tables.borrow().closure_tys.get(&id) { + let tables = tables.borrow(); + let hir_id = self.tcx.hir.node_to_hir_id(id); + tables.validate_hir_id(hir_id); + if let Some(&ty) = tables.closure_tys.get(&hir_id.local_id) { return ty; } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index faa91d0fa3a9..e8c6cc812120 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -697,6 +697,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { fn_node_id: ast::NodeId) -> McResult> { + let fn_hir_id = self.tcx.hir.node_to_hir_id(fn_node_id); + self.tables.validate_hir_id(fn_hir_id); + // An upvar can have up to 3 components. We translate first to a // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the // field from the environment. @@ -720,7 +723,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk // FnOnce | copied | upvar -> &'up bk - let kind = match self.tables.closure_kinds.get(&fn_node_id) { + let kind = match self.tables.closure_kinds.get(&fn_hir_id.local_id) { Some(&(kind, _)) => kind, None => span_bug!(span, "missing closure kind") }; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f0fc6998c9e5..8c4054254d02 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -682,7 +682,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Additional context information explaining why the closure only implements // a particular trait. if let Some(tables) = self.in_progress_tables { - match tables.borrow().closure_kinds.get(&node_id) { + let tables = tables.borrow(); + let closure_hir_id = self.tcx.hir.node_to_hir_id(node_id); + tables.validate_hir_id(closure_hir_id); + match tables.closure_kinds.get(&closure_hir_id.local_id) { Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => { err.span_note(span, &format!( "closure is `FnOnce` because it moves the \ diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d4ff1590e8aa..492ec0f3e40d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -236,11 +236,11 @@ pub struct TypeckTables<'tcx> { pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, /// Records the type of each closure. - pub closure_tys: NodeMap>, + pub closure_tys: ItemLocalMap>, /// Records the kind of each closure and the span and name of the variable /// that caused the closure to be this kind. - pub closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, + pub closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions @@ -283,8 +283,8 @@ impl<'tcx> TypeckTables<'tcx> { adjustments: ItemLocalMap(), pat_binding_modes: ItemLocalMap(), upvar_capture_map: FxHashMap(), - closure_tys: NodeMap(), - closure_kinds: NodeMap(), + closure_tys: ItemLocalMap(), + closure_kinds: ItemLocalMap(), liberated_fn_sigs: NodeMap(), fru_field_types: NodeMap(), cast_kinds: NodeMap(), diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 4b26aa95759d..7c9f4abe4183 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -598,8 +598,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let need_note = match lp.ty.sty { ty::TypeVariants::TyClosure(id, _) => { let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); + let hir_id = self.tcx.hir.node_to_hir_id(node_id); + self.tables.validate_hir_id(hir_id); if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = - self.tables.closure_kinds.get(&node_id) + self.tables.closure_kinds.get(&hir_id.local_id) { err.span_note(span, &format!( "closure cannot be invoked more than once because \ diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 802eee91efcf..8bf58d866efc 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -102,12 +102,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sig, opt_kind); - self.tables.borrow_mut().closure_tys.insert(expr.id, sig); - match opt_kind { - Some(kind) => { - self.tables.borrow_mut().closure_kinds.insert(expr.id, (kind, None)); + { + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(expr.hir_id); + tables.closure_tys.insert(expr.hir_id.local_id, sig); + match opt_kind { + Some(kind) => { + tables.closure_kinds.insert(expr.hir_id.local_id, (kind, None)); + } + None => {} } - None => {} } closure_type diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 7bf671d5e9f9..fc8f4f32440a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -820,7 +820,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let closure_id = match step.self_ty.sty { ty::TyClosure(def_id, _) => { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - id + self.tcx.hir.node_to_hir_id(id) } else { continue; } @@ -828,11 +828,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { _ => continue, }; - let closure_kinds = &self.tables.borrow().closure_kinds; - let closure_kind = match closure_kinds.get(&closure_id) { - Some(&(k, _)) => k, - None => { - return Err(MethodError::ClosureAmbiguity(trait_def_id)); + let closure_kind = { + let tables = self.tables.borrow(); + tables.validate_hir_id(closure_id); + match tables.closure_kinds.get(&closure_id.local_id) { + Some(&(k, _)) => k, + None => { + return Err(MethodError::ClosureAmbiguity(trait_def_id)); + } } }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index facacdc8d114..5308ffe6f8d7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -743,7 +743,8 @@ 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.typeck_tables_of(def_id).closure_kinds[&node_id].0 + let hir_id = tcx.hir.node_to_hir_id(node_id); + tcx.typeck_tables_of(def_id).closure_kinds[&hir_id.local_id].0 } fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 22047ed583e2..6621c9d027e9 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -100,7 +100,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); - let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(id) { + let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(hir_id.local_id) { Entry::Occupied(_) => false, Entry::Vacant(entry) => { debug!("check_closure: adding closure {:?} as Fn", id); @@ -152,7 +152,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Write the adjusted values back into the main tables. if infer_kind { if let Some(kind) = delegate.adjust_closure_kinds.remove(&id) { - self.tables.borrow_mut().closure_kinds.insert(id, kind); + self.tables.borrow_mut().closure_kinds.insert(hir_id.local_id, kind); } } self.tables.borrow_mut().upvar_capture_map.extend( @@ -468,7 +468,13 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { closure_id, new_kind, upvar_span, var_name); let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned() - .or_else(|| self.fcx.tables.borrow().closure_kinds.get(&closure_id).cloned()); + .or_else(|| { + let closure_id = self.fcx.tcx.hir.node_to_hir_id(closure_id); + let fcx_tables = self.fcx.tables.borrow(); + fcx_tables.validate_hir_id(closure_id); + fcx_tables.closure_kinds.get(&closure_id.local_id).cloned() + }); + if let Some((existing_kind, _)) = closure_kind { debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", closure_id, existing_kind, new_kind); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b689da6e3867..ed7b75ddb05b 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -230,12 +230,19 @@ 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, &id); + let fcx_tables = self.fcx.tables.borrow(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + + for (&id, closure_ty) in fcx_tables.closure_tys.iter() { + let hir_id = hir::HirId { + owner: fcx_tables.local_id_root.index, + local_id: id, + }; + let closure_ty = self.resolve(closure_ty, &hir_id); self.tables.closure_tys.insert(id, closure_ty); } - for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() { + for (&id, &closure_kind) in fcx_tables.closure_kinds.iter() { self.tables.closure_kinds.insert(id, closure_kind); } } @@ -380,6 +387,13 @@ impl Locatable for ast::NodeId { fn to_span(&self, tcx: &TyCtxt) -> Span { tcx.hir.span(*self) } } +impl Locatable for hir::HirId { + fn to_span(&self, tcx: &TyCtxt) -> Span { + let node_id = tcx.hir.definitions().find_node_for_hir_id(*self); + tcx.hir.span(node_id) + } +} + /////////////////////////////////////////////////////////////////////////// // The Resolver. This is the type folding engine that detects // unresolved types and so forth. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7b63bd883f97..30188a7cbdce 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1239,8 +1239,10 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, )) } - NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { - tcx.typeck_tables_of(def_id).closure_tys[&node_id] + NodeExpr(&hir::Expr { node: hir::ExprClosure(..), hir_id, .. }) => { + let tables = tcx.typeck_tables_of(def_id); + tables.validate_hir_id(hir_id); + tables.closure_tys[&hir_id.local_id] } x => { From 55e04d9c17c655bdb6d1e6f7256d398482bf1599 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Aug 2017 17:41:02 +0200 Subject: [PATCH 28/88] Make Definitions::find_node_for_hir_id() a linear search instead of a binary one. Unfortunately, the NodeId->HirId array is not sorted. Since this search is only done right before calling bug!(), let's not waste time allocating a faster lookup. --- src/librustc/hir/map/definitions.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index d3e3998360b6..67a4d71d90c1 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -466,7 +466,11 @@ impl Definitions { } pub fn find_node_for_hir_id(&self, hir_id: hir::HirId) -> ast::NodeId { - self.node_to_hir_id.binary_search(&hir_id).unwrap() + self.node_to_hir_id + .iter() + .position(|x| *x == hir_id) + .map(|idx| ast::NodeId::new(idx)) + .unwrap() } /// Add a definition with a parent definition. From 6cd44a9d5e2a8013bac858ed9f412badefaa8a43 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Aug 2017 17:44:01 +0200 Subject: [PATCH 29/88] Add missing TypeckTables-switch in save-analysis. --- src/librustc_save_analysis/dump_visitor.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index af816473033f..f89d59b5a449 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -500,12 +500,14 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { item: &'l ast::Item, typ: &'l ast::Ty, expr: &'l ast::Expr) { - if let Some(var_data) = self.save_ctxt.get_item_data(item) { - down_cast_data!(var_data, DefData, item.span); - self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data); - } - self.visit_ty(&typ); - self.visit_expr(expr); + self.nest_tables(item.id, |v| { + if let Some(var_data) = v.save_ctxt.get_item_data(item) { + down_cast_data!(var_data, DefData, item.span); + v.dumper.dump_def(item.vis == ast::Visibility::Public, var_data); + } + v.visit_ty(&typ); + v.visit_expr(expr); + }); } fn process_assoc_const(&mut self, From 890f93f8d49f48c32f67519b8e523ce6034cb875 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 7 Aug 2017 17:45:06 +0200 Subject: [PATCH 30/88] Use ItemLocalId as key for TypeckTables::liberated_fn_sigs. --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/ty/context.rs | 4 ++-- src/librustc_mir/build/mod.rs | 4 +++- src/librustc_typeck/check/mod.rs | 7 ++++++- src/librustc_typeck/check/regionck.rs | 6 ++++-- src/librustc_typeck/check/writeback.rs | 13 ++++++++++--- 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index eec73937e2ca..740b4c428dc1 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -656,7 +656,7 @@ for ty::TypeckTables<'gcx> { ich::hash_stable_itemlocalmap(hcx, hasher, closure_tys); ich::hash_stable_itemlocalmap(hcx, hasher, closure_kinds); - ich::hash_stable_nodemap(hcx, hasher, liberated_fn_sigs); + ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs); ich::hash_stable_nodemap(hcx, hasher, fru_field_types); ich::hash_stable_nodemap(hcx, hasher, cast_kinds); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 492ec0f3e40d..5ec39b78e307 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -247,7 +247,7 @@ pub struct TypeckTables<'tcx> { /// (including late-bound regions) are replaced with free /// equivalents. This table is not used in trans (since regions /// are erased there) and hence is not serialized to metadata. - pub liberated_fn_sigs: NodeMap>, + pub liberated_fn_sigs: ItemLocalMap>, /// For each FRU expression, record the normalized types of the fields /// of the struct - this is needed because it is non-trivial to @@ -285,7 +285,7 @@ impl<'tcx> TypeckTables<'tcx> { upvar_capture_map: FxHashMap(), closure_tys: ItemLocalMap(), closure_kinds: ItemLocalMap(), - liberated_fn_sigs: NodeMap(), + liberated_fn_sigs: ItemLocalMap(), fru_field_types: NodeMap(), cast_kinds: NodeMap(), used_trait_imports: DefIdSet(), diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 66817fda5b7b..ae951d50a8cd 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -90,7 +90,9 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t } else if let MirSource::Fn(id) = src { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) - let fn_sig = cx.tables().liberated_fn_sigs[&id].clone(); + let fn_hir_id = tcx.hir.node_to_hir_id(id); + cx.tables().validate_hir_id(fn_hir_id); + let fn_sig = cx.tables().liberated_fn_sigs[&fn_hir_id.local_id].clone(); let ty = tcx.type_of(tcx.hir.local_def_id(id)); let mut abi = fn_sig.abi; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5308ffe6f8d7..0d484d2ce369 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1028,7 +1028,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(arg.hir_id, arg_ty); } - inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); + { + let mut inh_tables = inherited.tables.borrow_mut(); + let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id); + inh_tables.validate_hir_id(fn_hir_id); + inh_tables.liberated_fn_sigs.insert(fn_hir_id.local_id, fn_sig); + } fcx.check_return_expr(&body.value); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 3113f4a569f2..c9c8f3363cee 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -309,8 +309,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let old_call_site_scope = self.set_call_site_scope(Some(call_site)); let fn_sig = { - let fn_sig_map = &self.tables.borrow().liberated_fn_sigs; - match fn_sig_map.get(&id) { + let tables = self.tables.borrow(); + let fn_hir_id = self.tcx.hir.node_to_hir_id(id); + tables.validate_hir_id(fn_hir_id); + match tables.liberated_fn_sigs.get(&fn_hir_id.local_id) { Some(f) => f.clone(), None => { bug!("No fn-sig entry for id={}", id); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index ed7b75ddb05b..499afe62b4f9 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -348,9 +348,16 @@ 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, &node_id); - self.tables.liberated_fn_sigs.insert(node_id, fn_sig.clone()); + let fcx_tables = self.fcx.tables.borrow(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + + for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs.iter() { + let hir_id = hir::HirId { + owner: fcx_tables.local_id_root.index, + local_id, + }; + let fn_sig = self.resolve(fn_sig, &hir_id); + self.tables.liberated_fn_sigs.insert(local_id, fn_sig.clone()); } } From 801dd07a950b047150aa291e461ba53a7d29489e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 Aug 2017 12:13:16 +0200 Subject: [PATCH 31/88] Use ItemLocalId as key for TypeckTables::fru_field_types. --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/ty/context.rs | 4 ++-- src/librustc_mir/hair/cx/expr.rs | 5 ++++- src/librustc_typeck/check/mod.rs | 5 ++++- src/librustc_typeck/check/writeback.rs | 13 ++++++++++--- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 740b4c428dc1..84058119b459 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -657,7 +657,7 @@ for ty::TypeckTables<'gcx> { ich::hash_stable_itemlocalmap(hcx, hasher, closure_tys); ich::hash_stable_itemlocalmap(hcx, hasher, closure_kinds); ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs); - ich::hash_stable_nodemap(hcx, hasher, fru_field_types); + ich::hash_stable_itemlocalmap(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| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5ec39b78e307..f09488ebcfa6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -253,7 +253,7 @@ pub struct TypeckTables<'tcx> { /// of the struct - this is needed because it is non-trivial to /// normalize while preserving regions. This table is used only in /// MIR construction and hence is not serialized to metadata. - pub fru_field_types: NodeMap>>, + pub fru_field_types: ItemLocalMap>>, /// Maps a cast expression to its kind. This is keyed on the /// *from* expression of the cast, not the cast itself. @@ -286,7 +286,7 @@ impl<'tcx> TypeckTables<'tcx> { closure_tys: ItemLocalMap(), closure_kinds: ItemLocalMap(), liberated_fn_sigs: ItemLocalMap(), - fru_field_types: NodeMap(), + fru_field_types: ItemLocalMap(), cast_kinds: NodeMap(), used_trait_imports: DefIdSet(), tainted_by_errors: false, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ea9a19c83782..30f7378e83b1 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -387,9 +387,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, substs: substs, fields: field_refs, base: base.as_ref().map(|base| { + cx.tables().validate_hir_id(expr.hir_id); FruInfo { base: base.to_ref(), - field_types: cx.tables().fru_field_types[&expr.id].clone(), + field_types: cx.tables() + .fru_field_types[&expr.hir_id.local_id] + .clone(), } }), } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0d484d2ce369..60930d8184a3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3407,7 +3407,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fru_field_types = adt.struct_variant().fields.iter().map(|f| { self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) }).collect(); - self.tables.borrow_mut().fru_field_types.insert(expr.id, fru_field_types); + + let mut tables = self.tables.borrow_mut(); + tables.validate_hir_id(expr.hir_id); + tables.fru_field_types.insert(expr.hir_id.local_id, fru_field_types); } _ => { span_err!(self.tcx.sess, base_expr.span, E0436, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 499afe62b4f9..45ec788b1b8d 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -362,9 +362,16 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } 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, &node_id); - self.tables.fru_field_types.insert(node_id, ftys); + let fcx_tables = self.fcx.tables.borrow(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + + for (&local_id, ftys) in fcx_tables.fru_field_types.iter() { + let hir_id = hir::HirId { + owner: fcx_tables.local_id_root.index, + local_id, + }; + let ftys = self.resolve(ftys, &hir_id); + self.tables.fru_field_types.insert(local_id, ftys); } } From fbc7398badef55d58476b5410e7e911bb872f537 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 Aug 2017 12:25:22 +0200 Subject: [PATCH 32/88] Use ItemLocalId as key for TypeckTables::cast_kinds. --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/ty/context.rs | 5 +++-- src/librustc_mir/hair/cx/expr.rs | 5 ++++- src/librustc_passes/consts.rs | 3 ++- src/librustc_typeck/check/cast.rs | 8 ++++++-- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 84058119b459..7b98eb0fb717 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -658,7 +658,7 @@ for ty::TypeckTables<'gcx> { ich::hash_stable_itemlocalmap(hcx, hasher, closure_kinds); ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs); ich::hash_stable_itemlocalmap(hcx, hasher, fru_field_types); - ich::hash_stable_nodemap(hcx, hasher, cast_kinds); + ich::hash_stable_itemlocalmap(hcx, hasher, cast_kinds); ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { hcx.def_path_hash(*def_id) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index f09488ebcfa6..bf412b570071 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -257,7 +257,7 @@ pub struct TypeckTables<'tcx> { /// Maps a cast expression to its kind. This is keyed on the /// *from* expression of the cast, not the cast itself. - pub cast_kinds: NodeMap, + pub cast_kinds: ItemLocalMap, /// Set of trait imports actually used in the method resolution. /// This is used for warning unused imports. @@ -287,7 +287,8 @@ impl<'tcx> TypeckTables<'tcx> { closure_kinds: ItemLocalMap(), liberated_fn_sigs: ItemLocalMap(), fru_field_types: ItemLocalMap(), - cast_kinds: NodeMap(), + cast_kinds: ItemLocalMap(), + lints: lint::LintTable::new(), used_trait_imports: DefIdSet(), tainted_by_errors: false, free_region_map: FreeRegionMap::new(), diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 30f7378e83b1..05709fed0af8 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -551,7 +551,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprCast(ref source, _) => { // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - if let Some(&TyCastKind::CoercionCast) = cx.tables().cast_kinds.get(&source.id) { + cx.tables().validate_hir_id(source.hir_id); + if let Some(&TyCastKind::CoercionCast) = cx.tables() + .cast_kinds + .get(&source.hir_id.local_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index c06ae721f365..4a2925175c27 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -320,7 +320,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } hir::ExprCast(ref from, _) => { debug!("Checking const cast(id={})", from.id); - match v.tables.cast_kinds.get(&from.id) { + v.tables.validate_hir_id(from.hir_id); + match v.tables.cast_kinds.get(&from.hir_id.local_id) { None => span_bug!(e.span, "no kind for cast"), Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => { v.promotable = false; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 5f256eab9a9c..2be427eee1b9 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -330,12 +330,16 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); debug!(" -> CoercionCast"); - fcx.tables.borrow_mut().cast_kinds.insert(self.expr.id, CastKind::CoercionCast); + let mut tables = fcx.tables.borrow_mut(); + tables.validate_hir_id(self.expr.hir_id); + tables.cast_kinds.insert(self.expr.hir_id.local_id, CastKind::CoercionCast); } else { match self.do_check(fcx) { Ok(k) => { debug!(" -> {:?}", k); - fcx.tables.borrow_mut().cast_kinds.insert(self.expr.id, k); + let mut tables = fcx.tables.borrow_mut(); + tables.validate_hir_id(self.expr.hir_id); + tables.cast_kinds.insert(self.expr.hir_id.local_id, k); } Err(e) => self.report_cast_error(fcx, e), }; From a8cf6cc6db13efea1057dfefbe9e6b583b23ea4f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 Aug 2017 14:33:51 +0200 Subject: [PATCH 33/88] Add some ID conversion methods to HIR map and Definitions. --- src/librustc/hir/map/definitions.rs | 13 +++++++++++++ src/librustc/hir/map/mod.rs | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 67a4d71d90c1..b371366bc5d5 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -434,18 +434,22 @@ impl Definitions { DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p)) } + #[inline] pub fn opt_def_index(&self, node: ast::NodeId) -> Option { self.node_to_def_index.get(&node).cloned() } + #[inline] pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option { self.opt_def_index(node).map(DefId::local) } + #[inline] pub fn local_def_id(&self, node: ast::NodeId) -> DefId { self.opt_local_def_id(node).unwrap() } + #[inline] pub fn as_local_node_id(&self, def_id: DefId) -> Option { if def_id.krate == LOCAL_CRATE { let space_index = def_id.index.address_space().index(); @@ -461,6 +465,7 @@ impl Definitions { } } + #[inline] pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { self.node_to_hir_id[node_id] } @@ -473,6 +478,14 @@ impl Definitions { .unwrap() } + #[inline] + pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId { + let space_index = def_index.address_space().index(); + let array_index = def_index.as_array_index(); + let node_id = self.def_index_to_node[space_index][array_index]; + self.node_to_hir_id[node_id] + } + /// Add a definition with a parent definition. pub fn create_root_def(&mut self, crate_name: &str, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 3b73647f0eb0..99ed4736a512 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -401,6 +401,16 @@ impl<'hir> Map<'hir> { self.definitions.node_to_hir_id(node_id) } + #[inline] + pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> HirId { + self.definitions.def_index_to_hir_id(def_index) + } + + #[inline] + pub fn def_index_to_node_id(&self, def_index: DefIndex) -> NodeId { + self.definitions.as_local_node_id(DefId::local(def_index)).unwrap() + } + fn entry_count(&self) -> usize { self.map.len() } From 4dcc3a4aae48d4ce856a2db2a1234af190fb2eb8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 Aug 2017 14:34:37 +0200 Subject: [PATCH 34/88] Use DefIndex instead of NodeId in UpvarId. --- src/librustc/ich/impls_ty.rs | 13 ++- src/librustc/infer/error_reporting/mod.rs | 2 +- src/librustc/infer/error_reporting/note.rs | 18 ++-- src/librustc/middle/expr_use_visitor.rs | 11 ++- src/librustc/middle/mem_categorization.rs | 17 ++-- src/librustc/ty/mod.rs | 9 +- src/librustc/util/ppaux.rs | 4 +- .../borrowck/gather_loans/move_error.rs | 4 +- src/librustc_borrowck/borrowck/mod.rs | 30 +++++-- src/librustc_mir/build/mod.rs | 10 ++- src/librustc_mir/hair/cx/expr.rs | 17 ++-- src/librustc_typeck/check/upvar.rs | 83 +++++++++++-------- src/librustc_typeck/check/writeback.rs | 9 +- 13 files changed, 142 insertions(+), 85 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b98eb0fb717..279e62c63112 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -11,6 +11,7 @@ //! This module contains `HashStable` implementations for various data types //! from rustc::ty in no particular order. +use hir::def_id::DefId; use ich::{self, StableHashingContext, NodeIdHashingMode}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; @@ -618,7 +619,7 @@ for ty::TypeckTables<'gcx> { hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::TypeckTables { - local_id_root: _, + local_id_root, ref type_dependent_defs, ref node_types, ref node_substs, @@ -649,8 +650,14 @@ for ty::TypeckTables<'gcx> { 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); + let var_def_id = DefId { + krate: local_id_root.krate, + index: var_id, + }; + let closure_def_id = DefId { + krate: local_id_root.krate, + index: closure_expr_id, + }; (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id)) }); diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 9f70b4834ddc..b5390da7e852 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -913,7 +913,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } infer::UpvarRegion(ref upvar_id, _) => { format!(" for capture of `{}` by closure", - self.tcx.local_var_name_str(upvar_id.var_id).to_string()) + self.tcx.local_var_name_str_def_index(upvar_id.var_id)) } }; diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 963c14c48c82..87047d0df144 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -45,8 +45,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_note(span, &format!("...so that closure can access `{}`", self.tcx - .local_var_name_str(upvar_id.var_id) - .to_string())); + .local_var_name_str_def_index(upvar_id.var_id))); } infer::InfStackClosure(span) => { err.span_note(span, "...so that closure does not outlive its stack frame"); @@ -176,18 +175,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { E0313, "lifetime of borrowed pointer outlives lifetime \ of captured variable `{}`...", - self.tcx.local_var_name_str(upvar_id.var_id)); + self.tcx + .local_var_name_str_def_index(upvar_id.var_id)); self.tcx.note_and_explain_region(&mut err, "...the borrowed pointer is valid for ", sub, "..."); self.tcx - .note_and_explain_region(&mut err, - &format!("...but `{}` is only valid for ", - self.tcx - .local_var_name_str(upvar_id.var_id)), - sup, - ""); + .note_and_explain_region( + &mut err, + &format!("...but `{}` is only valid for ", + self.tcx.local_var_name_str_def_index(upvar_id.var_id)), + sup, + ""); err } infer::InfStackClosure(span) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a11511c2434a..73800fe7f081 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -890,10 +890,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.tcx().with_freevars(closure_expr.id, |freevars| { for freevar in freevars { - let def_id = freevar.def.def_id(); - let id_var = self.tcx().hir.as_local_node_id(def_id).unwrap(); - let upvar_id = ty::UpvarId { var_id: id_var, - closure_expr_id: closure_expr.id }; + let var_def_id = freevar.def.def_id(); + debug_assert!(var_def_id.is_local()); + let closure_def_id = self.tcx().hir.local_def_id(closure_expr.id); + let upvar_id = ty::UpvarId { + var_id: var_def_id.index, + closure_expr_id: closure_def_id.index + }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id, fn_decl_span, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e8c6cc812120..08231a9ba1ba 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -70,7 +70,7 @@ pub use self::Note::*; use self::Aliasability::*; use middle::region::RegionMaps; -use hir::def_id::DefId; +use hir::def_id::{DefId, DefIndex}; use hir::map as hir_map; use infer::InferCtxt; use hir::def::{Def, CtorKind}; @@ -190,7 +190,7 @@ pub type cmt<'tcx> = Rc>; pub enum ImmutabilityBlame<'tcx> { ImmLocal(ast::NodeId), - ClosureEnv(ast::NodeId), + ClosureEnv(DefIndex), LocalDeref(ast::NodeId), AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef) } @@ -728,8 +728,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { None => span_bug!(span, "missing closure kind") }; - let upvar_id = ty::UpvarId { var_id, - closure_expr_id: fn_node_id }; + let closure_expr_def_index = self.tcx.hir.local_def_id(fn_node_id).index; + let var_def_index = self.tcx.hir.local_def_id(var_id).index; + + let upvar_id = ty::UpvarId { + var_id: var_def_index, + closure_expr_id: closure_expr_def_index + }; let var_hir_id = self.tcx.hir.node_to_hir_id(var_id); let var_ty = self.node_ty(var_hir_id)?; @@ -766,8 +771,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // If this is a by-ref capture, then the upvar we loaded is // actually a reference, so we have to add an implicit deref // for that. - let upvar_id = ty::UpvarId { var_id, - closure_expr_id: fn_node_id }; let upvar_capture = self.tables.upvar_capture(upvar_id); let cmt_result = match upvar_capture { ty::UpvarCapture::ByValue => { @@ -805,7 +808,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // The environment of a closure is guaranteed to // outlive any bindings introduced in the body of the // closure itself. - scope: self.tcx.hir.local_def_id(upvar_id.closure_expr_id), + scope: DefId::local(upvar_id.closure_expr_id), bound_region: ty::BrEnv })); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 28a73f4a4d38..af322fc72d89 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -572,8 +572,8 @@ impl Slice { /// by the upvar) and the id of the closure expression. #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct UpvarId { - pub var_id: NodeId, - pub closure_expr_id: NodeId, + pub var_id: DefIndex, + pub closure_expr_id: DefIndex, } #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)] @@ -1983,6 +1983,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn local_var_name_str_def_index(self, def_index: DefIndex) -> InternedString { + let node_id = self.hir.as_local_node_id(DefId::local(def_index)).unwrap(); + self.local_var_name_str(node_id) + } + pub fn expr_is_lval(self, expr: &hir::Expr) -> bool { match expr.node { hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d9c99ccd5084..184fd75135e4 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -864,9 +864,9 @@ impl<'tcx> fmt::Display for ty::TyS<'tcx> { impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UpvarId({};`{}`;{})", + write!(f, "UpvarId({:?};`{}`;{:?})", self.var_id, - ty::tls::with(|tcx| tcx.local_var_name_str(self.var_id)), + ty::tls::with(|tcx| tcx.local_var_name_str_def_index(self.var_id)), self.closure_expr_id) } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index cceb4a7b3cc2..bfd883be8487 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -93,11 +93,11 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec { LpInterior(Option, InteriorKind), } -pub fn closure_to_block(closure_id: ast::NodeId, - tcx: TyCtxt) -> ast::NodeId { +fn closure_to_block(closure_id: DefIndex, + tcx: TyCtxt) -> ast::NodeId { + let closure_id = tcx.hir.def_index_to_node_id(closure_id); match tcx.hir.get(closure_id) { hir_map::NodeExpr(expr) => match expr.node { hir::ExprClosure(.., body_id, _) => { @@ -845,7 +846,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } else { "consider changing this closure to take self by mutable reference" }; - err.span_help(self.tcx.hir.span(id), help); + let node_id = self.tcx.hir.def_index_to_node_id(id); + err.span_help(self.tcx.hir.span(node_id), help); err } _ => { @@ -1181,7 +1183,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { _ => bug!() }; if kind == ty::ClosureKind::Fn { - db.span_help(self.tcx.hir.span(upvar_id.closure_expr_id), + let closure_node_id = + self.tcx.hir.def_index_to_node_id(upvar_id.closure_expr_id); + db.span_help(self.tcx.hir.span(closure_node_id), "consider changing this closure to take \ self by mutable reference"); } @@ -1214,7 +1218,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { loan_path: &LoanPath<'tcx>, out: &mut String) { match loan_path.kind { - LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) | + LpUpvar(ty::UpvarId { var_id: id, closure_expr_id: _ }) => { + out.push_str(&self.tcx.local_var_name_str_def_index(id)); + } LpVar(id) => { out.push_str(&self.tcx.local_var_name_str(id)); } @@ -1352,8 +1358,11 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { } LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => { - let s = ty::tls::with(|tcx| tcx.hir.node_to_string(var_id)); - write!(f, "$({} captured by id={})", s, closure_expr_id) + let s = ty::tls::with(|tcx| { + let var_node_id = tcx.hir.def_index_to_node_id(var_id); + tcx.hir.node_to_string(var_node_id) + }); + write!(f, "$({} captured by id={:?})", s, closure_expr_id) } LpDowncast(ref lp, variant_def_id) => { @@ -1384,7 +1393,10 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> { } LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { - let s = ty::tls::with(|tcx| tcx.hir.node_to_user_string(var_id)); + let s = ty::tls::with(|tcx| { + let var_node_id = tcx.hir.def_index_to_node_id(var_id); + tcx.hir.node_to_string(var_node_id) + }); write!(f, "$({} captured by closure)", s) } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index ae951d50a8cd..d029e2f10e88 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -368,10 +368,12 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, // Gather the upvars of a closure, if any. let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { freevars.iter().map(|fv| { - let var_id = tcx.hir.as_local_node_id(fv.def.def_id()).unwrap(); + let var_def_id = fv.def.def_id(); + let var_node_id = tcx.hir.as_local_node_id(var_def_id).unwrap(); + let closure_expr_id = tcx.hir.local_def_id(fn_id).index; let capture = hir.tables().upvar_capture(ty::UpvarId { - var_id: var_id, - closure_expr_id: fn_id + var_id: var_def_id.index, + closure_expr_id, }); let by_ref = match capture { ty::UpvarCapture::ByValue => false, @@ -381,7 +383,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, debug_name: keywords::Invalid.name(), by_ref: by_ref }; - if let Some(hir::map::NodeLocal(pat)) = tcx.hir.find(var_id) { + if let Some(hir::map::NodeLocal(pat)) = tcx.hir.find(var_node_id) { if let hir::PatKind::Binding(_, _, ref ident, _) = pat.node { decl.debug_name = ident.node; } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 05709fed0af8..11da73187b37 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -684,8 +684,8 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::VarRef { id: node_id } } - Def::Upvar(def_id, index, closure_expr_id) => { - let id_var = cx.tcx.hir.as_local_node_id(def_id).unwrap(); + Def::Upvar(var_def_id, index, closure_expr_id) => { + let id_var = cx.tcx.hir.as_local_node_id(var_def_id).unwrap(); debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, @@ -768,8 +768,8 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref let upvar_id = ty::UpvarId { - var_id: id_var, - closure_expr_id: closure_expr_id, + var_id: var_def_id.index, + closure_expr_id: closure_def_id.index, }; match cx.tables().upvar_capture(upvar_id) { ty::UpvarCapture::ByValue => field_kind, @@ -880,15 +880,16 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, freevar: &hir::Freevar, freevar_ty: Ty<'tcx>) -> ExprRef<'tcx> { - let id_var = cx.tcx.hir.as_local_node_id(freevar.def.def_id()).unwrap(); + let var_def_id = freevar.def.def_id(); + let var_node_id = cx.tcx.hir.as_local_node_id(var_def_id).unwrap(); let upvar_id = ty::UpvarId { - var_id: id_var, - closure_expr_id: closure_expr.id, + var_id: var_def_id.index, + closure_expr_id: cx.tcx.hir.local_def_id(closure_expr.id).index, }; let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id); let var_ty = cx.tables() - .node_id_to_type(cx.tcx.hir.node_to_hir_id(id_var)); + .node_id_to_type(cx.tcx.hir.node_to_hir_id(var_node_id)); let captured_var = Expr { temp_lifetime: temp_lifetime, ty: var_ty, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 6621c9d027e9..111f224c3d1f 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -50,8 +50,9 @@ use rustc::infer::UpvarRegion; use syntax::ast; use syntax_pos::Span; use rustc::hir; +use rustc::hir::def_id::DefIndex; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::util::nodemap::NodeMap; +use rustc::util::nodemap::FxHashMap; use std::collections::hash_map::Entry; @@ -90,7 +91,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn analyze_closure(&self, - (id, hir_id): (ast::NodeId, hir::HirId), + (closure_node_id, closure_hir_id): (ast::NodeId, hir::HirId), span: Span, body: &hir::Body, capture_clause: hir::CaptureClause) { @@ -98,23 +99,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { * Analysis starting point. */ - debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); + debug!("analyze_closure(id={:?}, body.id={:?})", closure_node_id, body.id()); - let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(hir_id.local_id) { + let infer_kind = match self.tables + .borrow_mut() + .closure_kinds + .entry(closure_hir_id.local_id) { Entry::Occupied(_) => false, Entry::Vacant(entry) => { - debug!("check_closure: adding closure {:?} as Fn", id); + debug!("check_closure: adding closure {:?} as Fn", closure_node_id); entry.insert((ty::ClosureKind::Fn, None)); true } }; - self.tcx.with_freevars(id, |freevars| { + let closure_def_id = self.tcx.hir.local_def_id(closure_node_id); + + self.tcx.with_freevars(closure_node_id, |freevars| { for freevar in freevars { - let def_id = freevar.def.def_id(); - let var_node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); - let upvar_id = ty::UpvarId { var_id: var_node_id, - closure_expr_id: id }; + let var_def_id = freevar.def.def_id(); + let upvar_id = ty::UpvarId { + var_id: var_def_id.index, + closure_expr_id: closure_def_id.index, + }; debug!("seed upvar_id {:?}", upvar_id); let capture_kind = match capture_clause { @@ -139,7 +146,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let region_maps = &self.tcx.region_maps(body_owner_def_id); let mut delegate = InferBorrowKind { fcx: self, - adjust_closure_kinds: NodeMap(), + adjust_closure_kinds: FxHashMap(), adjust_upvar_captures: ty::UpvarCaptureMap::default(), }; euv::ExprUseVisitor::with_infer(&mut delegate, @@ -151,8 +158,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Write the adjusted values back into the main tables. if infer_kind { - if let Some(kind) = delegate.adjust_closure_kinds.remove(&id) { - self.tables.borrow_mut().closure_kinds.insert(hir_id.local_id, kind); + if let Some(kind) = delegate.adjust_closure_kinds + .remove(&closure_def_id.index) { + self.tables + .borrow_mut() + .closure_kinds + .insert(closure_hir_id.local_id, kind); } } self.tables.borrow_mut().upvar_capture_map.extend( @@ -172,20 +183,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // inference algorithm will reject it). // Extract the type variables UV0...UVn. - let (def_id, closure_substs) = match self.node_ty(hir_id).sty { + let (def_id, closure_substs) = match self.node_ty(closure_hir_id).sty { ty::TyClosure(def_id, substs) => (def_id, substs), ref t => { span_bug!( span, "type of closure expr {:?} is not a closure {:?}", - id, t); + closure_node_id, t); } }; // Equate the type variables with the actual types. - let final_upvar_tys = self.final_upvar_tys(id); + let final_upvar_tys = self.final_upvar_tys(closure_node_id); debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", - id, closure_substs, final_upvar_tys); + closure_node_id, closure_substs, final_upvar_tys); for (upvar_ty, final_upvar_ty) in closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys) { @@ -195,7 +206,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If we are also inferred the closure kind here, // process any deferred resolutions. if infer_kind { - let closure_def_id = self.tcx.hir.local_def_id(id); let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id); for deferred_call_resolution in deferred_call_resolutions { @@ -212,19 +222,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This may change if abstract return types of some sort are // implemented. let tcx = self.tcx; + let closure_def_index = tcx.hir.local_def_id(closure_id).index; + tcx.with_freevars(closure_id, |freevars| { freevars.iter().map(|freevar| { - let def_id = freevar.def.def_id(); - let var_id = tcx.hir.as_local_node_id(def_id).unwrap(); - let freevar_ty = self.node_ty(tcx.hir.node_to_hir_id(var_id)); + let var_def_id = freevar.def.def_id(); + let var_node_id = tcx.hir.as_local_node_id(var_def_id).unwrap(); + let freevar_ty = self.node_ty(tcx.hir.node_to_hir_id(var_node_id)); let upvar_id = ty::UpvarId { - var_id: var_id, - closure_expr_id: closure_id + var_id: var_def_id.index, + closure_expr_id: closure_def_index, }; let capture = self.tables.borrow().upvar_capture(upvar_id); debug!("var_id={:?} freevar_ty={:?} capture={:?}", - var_id, freevar_ty, capture); + var_node_id, freevar_ty, capture); match capture { ty::UpvarCapture::ByValue => freevar_ty, @@ -242,7 +254,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct InferBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - adjust_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, + adjust_closure_kinds: FxHashMap)>, adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, } @@ -281,7 +293,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - tcx.hir.name(upvar_id.var_id)); + var_name(tcx, upvar_id.var_id)); self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); } @@ -295,7 +307,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - tcx.hir.name(upvar_id.var_id)); + var_name(tcx, upvar_id.var_id)); } mc::NoteNone => { } @@ -400,7 +412,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - tcx.hir.name(upvar_id.var_id)); + var_name(tcx, upvar_id.var_id)); true } @@ -411,7 +423,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - tcx.hir.name(upvar_id.var_id)); + var_name(tcx, upvar_id.var_id)); true } @@ -460,23 +472,23 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } fn adjust_closure_kind(&mut self, - closure_id: ast::NodeId, + closure_id: DefIndex, new_kind: ty::ClosureKind, upvar_span: Span, var_name: ast::Name) { - debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})", + debug!("adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})", closure_id, new_kind, upvar_span, var_name); let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned() .or_else(|| { - let closure_id = self.fcx.tcx.hir.node_to_hir_id(closure_id); + let closure_id = self.fcx.tcx.hir.def_index_to_hir_id(closure_id); let fcx_tables = self.fcx.tables.borrow(); fcx_tables.validate_hir_id(closure_id); fcx_tables.closure_kinds.get(&closure_id.local_id).cloned() }); if let Some((existing_kind, _)) = closure_kind { - debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", + debug!("adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", closure_id, existing_kind, new_kind); match (existing_kind, new_kind) { @@ -566,3 +578,8 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_mut(assignee_cmt); } } + +fn var_name(tcx: ty::TyCtxt, var_def_index: DefIndex) -> ast::Name { + let var_node_id = tcx.hir.def_index_to_node_id(var_def_index); + tcx.hir.name(var_node_id) +} diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 45ec788b1b8d..515bbe49c39b 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -14,7 +14,7 @@ use check::FnCtxt; use rustc::hir; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::infer::{InferCtxt}; use rustc::ty::{self, Ty, TyCtxt}; @@ -401,6 +401,13 @@ impl Locatable for ast::NodeId { fn to_span(&self, tcx: &TyCtxt) -> Span { tcx.hir.span(*self) } } +impl Locatable for DefIndex { + fn to_span(&self, tcx: &TyCtxt) -> Span { + let node_id = tcx.hir.def_index_to_node_id(*self); + tcx.hir.span(node_id) + } +} + impl Locatable for hir::HirId { fn to_span(&self, tcx: &TyCtxt) -> Span { let node_id = tcx.hir.definitions().find_node_for_hir_id(*self); From bdfd78db8ad4f5520414f346fdfbfb5449d5be48 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 8 Aug 2017 15:35:19 +0200 Subject: [PATCH 35/88] Improve documentation for TypeckTables::validate_hir_id(). --- src/librustc/ty/context.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index bf412b570071..77964f6845b7 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -396,8 +396,16 @@ impl<'tcx> TypeckTables<'tcx> { self.upvar_capture_map[&upvar_id] } - /// Validate that a NodeId can safely be converted to an ItemLocalId for - /// this table. + /// Validate that the given HirId (respectively its `local_id` part) can be + /// safely used as a key in the tables of this TypeckTable. For that to be + /// the case, the HirId must have the same `owner` as all the other IDs in + /// this table (signified by the `local_id_root` field). Otherwise the HirId + /// would be in a different frame of reference and using its `local_id` + /// would result in lookup errors, or worse, in silently wrong data being + /// stored/returned. + /// + /// Therefore it is advised to call this method anytime before using a given + /// HirId::local_id as a key. #[inline] pub fn validate_hir_id(&self, hir_id: hir::HirId) { #[cfg(debug_assertions)] From 1f54df1101cabc4663906a5b8b6ca99bab6267a3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 10 Aug 2017 16:10:04 +0200 Subject: [PATCH 36/88] Encapsulate sub-table access in TypeckTables and validate keys on each access. --- src/librustc/ich/impls_ty.rs | 68 +--- src/librustc/infer/mod.rs | 11 +- src/librustc/middle/dead.rs | 6 +- src/librustc/middle/effect.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 8 +- src/librustc/middle/mem_categorization.rs | 14 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/traits/error_reporting.rs | 3 +- src/librustc/ty/context.rs | 355 +++++++++++++++++--- src/librustc_borrowck/borrowck/mod.rs | 8 +- src/librustc_const_eval/check_match.rs | 15 +- src/librustc_const_eval/pattern.rs | 4 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 3 +- src/librustc_mir/build/mod.rs | 3 +- src/librustc_mir/hair/cx/expr.rs | 11 +- src/librustc_passes/consts.rs | 6 +- src/librustc_privacy/lib.rs | 8 +- src/librustc_save_analysis/lib.rs | 4 +- src/librustc_typeck/check/_match.rs | 10 +- src/librustc_typeck/check/cast.rs | 9 +- src/librustc_typeck/check/closure.rs | 5 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 10 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/mod.rs | 54 +-- src/librustc_typeck/check/op.rs | 10 +- src/librustc_typeck/check/regionck.rs | 23 +- src/librustc_typeck/check/upvar.rs | 12 +- src/librustc_typeck/check/writeback.rs | 103 +++--- src/librustc_typeck/collect.rs | 4 +- 31 files changed, 463 insertions(+), 316 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 279e62c63112..45b2a4a1e966 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -11,8 +11,7 @@ //! This module contains `HashStable` implementations for various data types //! from rustc::ty in no particular order. -use hir::def_id::DefId; -use ich::{self, StableHashingContext, NodeIdHashingMode}; +use ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; @@ -612,71 +611,6 @@ impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> { ty }); - -impl<'a, 'gcx, 'tcx> HashStable> -for ty::TypeckTables<'gcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, - hasher: &mut StableHasher) { - let ty::TypeckTables { - local_id_root, - ref type_dependent_defs, - ref node_types, - ref node_substs, - ref adjustments, - ref pat_binding_modes, - ref upvar_capture_map, - ref closure_tys, - ref closure_kinds, - ref liberated_fn_sigs, - ref fru_field_types, - - ref cast_kinds, - - ref used_trait_imports, - tainted_by_errors, - ref free_region_map, - } = *self; - - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - ich::hash_stable_itemlocalmap(hcx, hasher, type_dependent_defs); - ich::hash_stable_itemlocalmap(hcx, hasher, node_types); - ich::hash_stable_itemlocalmap(hcx, hasher, node_substs); - ich::hash_stable_itemlocalmap(hcx, hasher, adjustments); - ich::hash_stable_itemlocalmap(hcx, hasher, pat_binding_modes); - 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 = DefId { - krate: local_id_root.krate, - index: var_id, - }; - let closure_def_id = DefId { - krate: local_id_root.krate, - index: closure_expr_id, - }; - (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id)) - }); - - ich::hash_stable_itemlocalmap(hcx, hasher, closure_tys); - ich::hash_stable_itemlocalmap(hcx, hasher, closure_kinds); - ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs); - ich::hash_stable_itemlocalmap(hcx, hasher, fru_field_types); - ich::hash_stable_itemlocalmap(hcx, hasher, cast_kinds); - - ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { - hcx.def_path_hash(*def_id) - }); - - tainted_by_errors.hash_stable(hcx, hasher); - free_region_map.hash_stable(hcx, hasher); - }) - } -} - impl_stable_hash_for!(enum ty::fast_reject::SimplifiedType { BoolSimplifiedType, CharSimplifiedType, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 727b0af2f547..1a8d570bde03 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1331,11 +1331,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - let tables = tables.borrow(); let hir_id = self.tcx.hir.node_to_hir_id(id); - tables.validate_hir_id(hir_id); - return tables.closure_kinds - .get(&hir_id.local_id) + return tables.borrow() + .closure_kinds() + .get(hir_id) .cloned() .map(|(kind, _)| kind); } @@ -1355,10 +1354,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> { if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - let tables = tables.borrow(); let hir_id = self.tcx.hir.node_to_hir_id(id); - tables.validate_hir_id(hir_id); - if let Some(&ty) = tables.closure_tys.get(&hir_id.local_id) { + if let Some(&ty) = tables.borrow().closure_tys().get(hir_id) { return ty; } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 0cca5690c018..0081555095b2 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -94,8 +94,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } } - fn lookup_and_handle_method(&mut self, id: hir::ItemLocalId) { - self.check_def_id(self.tables.type_dependent_defs[&id].def_id()); + fn lookup_and_handle_method(&mut self, id: hir::HirId) { + self.check_def_id(self.tables.type_dependent_defs()[id].def_id()); } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { @@ -241,7 +241,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { self.handle_definition(def); } hir::ExprMethodCall(..) => { - self.lookup_and_handle_method(expr.hir_id.local_id); + self.lookup_and_handle_method(expr.hir_id); } hir::ExprField(ref lhs, ref name) => { self.handle_field_access(&lhs, name.node); diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index e8ecf9c21cd3..6b7280cf0ac4 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -166,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { hir::ExprMethodCall(..) => { - let def_id = self.tables.type_dependent_defs[&expr.hir_id.local_id].def_id(); + let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id(); let sig = self.tcx.fn_sig(def_id); debug!("effect: method call case, signature is {:?}", sig); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 73800fe7f081..324f9a6e9061 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -537,7 +537,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let def_id = self.mc.tables.type_dependent_defs[&call.hir_id.local_id].def_id(); + let def_id = self.mc.tables.type_dependent_defs()[call.hir_id].def_id(); match OverloadedCallType::from_method_id(self.tcx(), def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); @@ -797,8 +797,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pat); return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { if let PatKind::Binding(..) = pat.node { - self.mc.tables.validate_hir_id(pat.hir_id); - let bm = *self.mc.tables.pat_binding_modes.get(&pat.hir_id.local_id) + let bm = *self.mc.tables.pat_binding_modes().get(pat.hir_id) .expect("missing binding mode"); match bm { ty::BindByReference(..) => @@ -824,8 +823,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(_, def_id, ..) = pat.node { debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); - mc.tables.validate_hir_id(pat.hir_id); - let bm = *mc.tables.pat_binding_modes.get(&pat.hir_id.local_id) + let bm = *mc.tables.pat_binding_modes().get(pat.hir_id) .expect("missing binding mode"); // pat_ty: the type of the binding being produced. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 08231a9ba1ba..1f3f9fce8542 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -334,10 +334,8 @@ impl MutabilityCategory { let ret = match tcx.hir.get(id) { hir_map::NodeLocal(p) => match p.node { PatKind::Binding(..) => { - - tables.validate_hir_id(p.hir_id); - let bm = *tables.pat_binding_modes - .get(&p.hir_id.local_id) + let bm = *tables.pat_binding_modes() + .get(p.hir_id) .expect("missing binding mode"); if bm == ty::BindByValue(hir::MutMutable) { McDeclared @@ -485,10 +483,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // fundamental fix to this conflated use of the node id. let ret_ty = match pat.node { PatKind::Binding(..) => { - self.tables.validate_hir_id(pat.hir_id); let bm = *self.tables - .pat_binding_modes - .get(&pat.hir_id.local_id) + .pat_binding_modes() + .get(pat.hir_id) .expect("missing binding mode"); if let ty::BindByReference(_) = bm { @@ -698,7 +695,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { -> McResult> { let fn_hir_id = self.tcx.hir.node_to_hir_id(fn_node_id); - self.tables.validate_hir_id(fn_hir_id); // An upvar can have up to 3 components. We translate first to a // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the @@ -723,7 +719,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk // FnOnce | copied | upvar -> &'up bk - let kind = match self.tables.closure_kinds.get(&fn_hir_id.local_id) { + let kind = match self.tables.closure_kinds().get(fn_hir_id) { Some(&(kind, _)) => kind, None => span_bug!(span, "missing closure kind") }; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 98f82a51267f..bd9a413ca617 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { Some(self.tables.qpath_def(qpath, expr.hir_id)) } hir::ExprMethodCall(..) => { - Some(self.tables.type_dependent_defs[&expr.hir_id.local_id]) + Some(self.tables.type_dependent_defs()[expr.hir_id]) } _ => None }; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8c4054254d02..c5b0f11b823a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -684,8 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some(tables) = self.in_progress_tables { let tables = tables.borrow(); let closure_hir_id = self.tcx.hir.node_to_hir_id(node_id); - tables.validate_hir_id(closure_hir_id); - match tables.closure_kinds.get(&closure_hir_id.local_id) { + match tables.closure_kinds().get(closure_hir_id) { Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => { err.span_note(span, &format!( "closure is `FnOnce` because it moves the \ diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 77964f6845b7..ac851f182a0f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -20,6 +20,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::DefPathHash; use lint::{self, Lint}; +use ich::{self, StableHashingContext, NodeIdHashingMode}; use middle::free_region::FreeRegionMap; use middle::lang_items; use middle::resolve_lifetime; @@ -45,19 +46,22 @@ use ty::BindingMode; use util::nodemap::{NodeMap, NodeSet, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; use arena::{TypedArena, DroplessArena}; use rustc_data_structures::indexed_vec::IndexVec; use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use std::cmp::Ordering; +use std::collections::hash_map::{self, Entry}; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; use std::iter; use std::rc::Rc; use syntax::abi; -use syntax::ast::{self, Name}; +use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; use syntax::symbol::{Symbol, keywords}; @@ -207,6 +211,91 @@ pub struct CommonTypes<'tcx> { pub re_erased: Region<'tcx>, } +pub struct LocalTableInContext<'a, V: 'a> { + local_id_root: DefId, + data: &'a ItemLocalMap +} + +/// Validate that the given HirId (respectively its `local_id` part) can be +/// safely used as a key in the tables of a TypeckTable. For that to be +/// the case, the HirId must have the same `owner` as all the other IDs in +/// this table (signified by `local_id_root`). Otherwise the HirId +/// would be in a different frame of reference and using its `local_id` +/// would result in lookup errors, or worse, in silently wrong data being +/// stored/returned. +fn validate_hir_id_for_typeck_tables(table_id_root: DefId, hir_id: hir::HirId) { + #[cfg(debug_assertions)] + { + if table_id_root.is_local() { + if hir_id.owner != table_id_root.index { + ty::tls::with(|tcx| { + let node_id = tcx.hir + .definitions() + .find_node_for_hir_id(hir_id); + + bug!("node {} with HirId::owner {:?} cannot be placed in \ + TypeckTables with local_id_root {:?}", + tcx.hir.node_to_string(node_id), + DefId::local(hir_id.owner), + table_id_root) + }); + } + } + } +} + +impl<'a, V> LocalTableInContext<'a, V> { + pub fn contains_key(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_tables(self.local_id_root, id); + self.data.contains_key(&id.local_id) + } + + pub fn get(&self, id: hir::HirId) -> Option<&V> { + validate_hir_id_for_typeck_tables(self.local_id_root, id); + self.data.get(&id.local_id) + } + + pub fn iter(&self) -> hash_map::Iter { + self.data.iter() + } +} + +impl<'a, V> ::std::ops::Index for LocalTableInContext<'a, V> { + type Output = V; + + fn index(&self, key: hir::HirId) -> &V { + self.get(key).expect("LocalTableInContext: key not found") + } +} + +pub struct LocalTableInContextMut<'a, V: 'a> { + local_id_root: DefId, + data: &'a mut ItemLocalMap +} + +impl<'a, V> LocalTableInContextMut<'a, V> { + + pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> { + validate_hir_id_for_typeck_tables(self.local_id_root, id); + self.data.get_mut(&id.local_id) + } + + pub fn entry(&mut self, id: hir::HirId) -> Entry { + validate_hir_id_for_typeck_tables(self.local_id_root, id); + self.data.entry(id.local_id) + } + + pub fn insert(&mut self, id: hir::HirId, val: V) -> Option { + validate_hir_id_for_typeck_tables(self.local_id_root, id); + self.data.insert(id.local_id, val) + } + + pub fn remove(&mut self, id: hir::HirId) -> Option { + validate_hir_id_for_typeck_tables(self.local_id_root, id); + self.data.remove(&id.local_id) + } +} + #[derive(RustcEncodable, RustcDecodable)] pub struct TypeckTables<'tcx> { /// The HirId::owner all ItemLocalIds in this table are relative to. @@ -214,50 +303,50 @@ pub struct TypeckTables<'tcx> { /// Resolved definitions for `::X` associated paths and /// method calls, including those of overloaded operators. - pub type_dependent_defs: ItemLocalMap, + type_dependent_defs: ItemLocalMap, /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated until after typeck. See /// typeck::check::fn_ctxt for details. - pub node_types: ItemLocalMap>, + node_types: ItemLocalMap>, /// Stores the type parameters which were substituted to obtain the type /// of this node. This only applies to nodes that refer to entities /// parameterized by type parameters, such as generic fns, types, or /// other items. - pub node_substs: ItemLocalMap<&'tcx Substs<'tcx>>, + node_substs: ItemLocalMap<&'tcx Substs<'tcx>>, - pub adjustments: ItemLocalMap>>, + adjustments: ItemLocalMap>>, // Stores the actual binding mode for all instances of hir::BindingAnnotation. - pub pat_binding_modes: ItemLocalMap, + pat_binding_modes: ItemLocalMap, /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, /// Records the type of each closure. - pub closure_tys: ItemLocalMap>, + closure_tys: ItemLocalMap>, /// Records the kind of each closure and the span and name of the variable /// that caused the closure to be this kind. - pub closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, + closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions /// (including late-bound regions) are replaced with free /// equivalents. This table is not used in trans (since regions /// are erased there) and hence is not serialized to metadata. - pub liberated_fn_sigs: ItemLocalMap>, + liberated_fn_sigs: ItemLocalMap>, /// For each FRU expression, record the normalized types of the fields /// of the struct - this is needed because it is non-trivial to /// normalize while preserving regions. This table is used only in /// MIR construction and hence is not serialized to metadata. - pub fru_field_types: ItemLocalMap>>, + fru_field_types: ItemLocalMap>>, /// Maps a cast expression to its kind. This is keyed on the /// *from* expression of the cast, not the cast itself. - pub cast_kinds: ItemLocalMap, + cast_kinds: ItemLocalMap, /// Set of trait imports actually used in the method resolution. /// This is used for warning unused imports. @@ -288,7 +377,6 @@ impl<'tcx> TypeckTables<'tcx> { liberated_fn_sigs: ItemLocalMap(), fru_field_types: ItemLocalMap(), cast_kinds: ItemLocalMap(), - lints: lint::LintTable::new(), used_trait_imports: DefIdSet(), tainted_by_errors: false, free_region_map: FreeRegionMap::new(), @@ -300,12 +388,40 @@ impl<'tcx> TypeckTables<'tcx> { match *qpath { hir::QPath::Resolved(_, ref path) => path.def, hir::QPath::TypeRelative(..) => { - self.validate_hir_id(id); + validate_hir_id_for_typeck_tables(self.local_id_root, id); self.type_dependent_defs.get(&id.local_id).cloned().unwrap_or(Def::Err) } } } + pub fn type_dependent_defs(&self) -> LocalTableInContext { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.type_dependent_defs + } + } + + pub fn type_dependent_defs_mut(&mut self) -> LocalTableInContextMut { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.type_dependent_defs + } + } + + pub fn node_types(&self) -> LocalTableInContext> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.node_types + } + } + + pub fn node_types_mut(&mut self) -> LocalTableInContextMut> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.node_types + } + } + pub fn node_id_to_type(&self, id: hir::HirId) -> Ty<'tcx> { match self.node_id_to_type_opt(id) { Some(ty) => ty, @@ -320,15 +436,27 @@ impl<'tcx> TypeckTables<'tcx> { } pub fn node_id_to_type_opt(&self, id: hir::HirId) -> Option> { - self.validate_hir_id(id); + validate_hir_id_for_typeck_tables(self.local_id_root, id); self.node_types.get(&id.local_id).cloned() } + pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<&'tcx Substs<'tcx>> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.node_substs + } + } + pub fn node_substs(&self, id: hir::HirId) -> &'tcx Substs<'tcx> { - self.validate_hir_id(id); + validate_hir_id_for_typeck_tables(self.local_id_root, id); self.node_substs.get(&id.local_id).cloned().unwrap_or(Substs::empty()) } + pub fn node_substs_opt(&self, id: hir::HirId) -> Option<&'tcx Substs<'tcx>> { + validate_hir_id_for_typeck_tables(self.local_id_root, id); + self.node_substs.get(&id.local_id).cloned() + } + // Returns the type of a pattern as a monotype. Like @expr_ty, this function // doesn't provide type parameter substitutions. pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { @@ -357,9 +485,24 @@ impl<'tcx> TypeckTables<'tcx> { self.node_id_to_type_opt(expr.hir_id) } + pub fn adjustments(&self) -> LocalTableInContext>> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.adjustments + } + } + + pub fn adjustments_mut(&mut self) + -> LocalTableInContextMut>> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.adjustments + } + } + pub fn expr_adjustments(&self, expr: &hir::Expr) -> &[ty::adjustment::Adjustment<'tcx>] { - self.validate_hir_id(expr.hir_id); + validate_hir_id_for_typeck_tables(self.local_id_root, expr.hir_id); self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..]) } @@ -385,48 +528,166 @@ impl<'tcx> TypeckTables<'tcx> { return false; } - self.validate_hir_id(expr.hir_id); - match self.type_dependent_defs.get(&expr.hir_id.local_id) { + match self.type_dependent_defs().get(expr.hir_id) { Some(&Def::Method(_)) => true, _ => false } } + pub fn pat_binding_modes(&self) -> LocalTableInContext { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.pat_binding_modes + } + } + + pub fn pat_binding_modes_mut(&mut self) + -> LocalTableInContextMut { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.pat_binding_modes + } + } + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { self.upvar_capture_map[&upvar_id] } - /// Validate that the given HirId (respectively its `local_id` part) can be - /// safely used as a key in the tables of this TypeckTable. For that to be - /// the case, the HirId must have the same `owner` as all the other IDs in - /// this table (signified by the `local_id_root` field). Otherwise the HirId - /// would be in a different frame of reference and using its `local_id` - /// would result in lookup errors, or worse, in silently wrong data being - /// stored/returned. - /// - /// Therefore it is advised to call this method anytime before using a given - /// HirId::local_id as a key. - #[inline] - pub fn validate_hir_id(&self, hir_id: hir::HirId) { - #[cfg(debug_assertions)] - { - if self.local_id_root.is_local() { - if hir_id.owner != self.local_id_root.index { - ty::tls::with(|tcx| { - let node_id = tcx.hir - .definitions() - .find_node_for_hir_id(hir_id); - - bug!("node {} with HirId::owner {:?} cannot be placed in \ - TypeckTables with local_id_root {:?}", - tcx.hir.node_to_string(node_id), - DefId::local(hir_id.owner), - self.local_id_root) - }); - } - } + pub fn closure_tys(&self) -> LocalTableInContext> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.closure_tys } } + + pub fn closure_tys_mut(&mut self) + -> LocalTableInContextMut> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.closure_tys + } + } + + pub fn closure_kinds(&self) -> LocalTableInContext<(ty::ClosureKind, + Option<(Span, ast::Name)>)> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.closure_kinds + } + } + + pub fn closure_kinds_mut(&mut self) + -> LocalTableInContextMut<(ty::ClosureKind, Option<(Span, ast::Name)>)> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.closure_kinds + } + } + + pub fn liberated_fn_sigs(&self) -> LocalTableInContext> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.liberated_fn_sigs + } + } + + pub fn liberated_fn_sigs_mut(&mut self) -> LocalTableInContextMut> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.liberated_fn_sigs + } + } + + pub fn fru_field_types(&self) -> LocalTableInContext>> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.fru_field_types + } + } + + pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut>> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.fru_field_types + } + } + + pub fn cast_kinds(&self) -> LocalTableInContext { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.cast_kinds + } + } + + pub fn cast_kinds_mut(&mut self) -> LocalTableInContextMut { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.cast_kinds + } + } +} + +impl<'a, 'gcx, 'tcx> HashStable> for TypeckTables<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher) { + let ty::TypeckTables { + local_id_root, + ref type_dependent_defs, + ref node_types, + ref node_substs, + ref adjustments, + ref pat_binding_modes, + ref upvar_capture_map, + ref closure_tys, + ref closure_kinds, + ref liberated_fn_sigs, + ref fru_field_types, + + ref cast_kinds, + + ref used_trait_imports, + tainted_by_errors, + ref free_region_map, + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ich::hash_stable_itemlocalmap(hcx, hasher, type_dependent_defs); + ich::hash_stable_itemlocalmap(hcx, hasher, node_types); + ich::hash_stable_itemlocalmap(hcx, hasher, node_substs); + ich::hash_stable_itemlocalmap(hcx, hasher, adjustments); + ich::hash_stable_itemlocalmap(hcx, hasher, pat_binding_modes); + 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 = DefId { + krate: local_id_root.krate, + index: var_id, + }; + let closure_def_id = DefId { + krate: local_id_root.krate, + index: closure_expr_id, + }; + (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id)) + }); + + ich::hash_stable_itemlocalmap(hcx, hasher, closure_tys); + ich::hash_stable_itemlocalmap(hcx, hasher, closure_kinds); + ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs); + ich::hash_stable_itemlocalmap(hcx, hasher, fru_field_types); + ich::hash_stable_itemlocalmap(hcx, hasher, cast_kinds); + + ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { + hcx.def_path_hash(*def_id) + }); + + tainted_by_errors.hash_stable(hcx, hasher); + free_region_map.hash_stable(hcx, hasher); + }) + } } impl<'tcx> CommonTypes<'tcx> { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 07981cc67fc7..412af05f5bdf 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -600,9 +600,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { ty::TypeVariants::TyClosure(id, _) => { let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); let hir_id = self.tcx.hir.node_to_hir_id(node_id); - self.tables.validate_hir_id(hir_id); if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = - self.tables.closure_kinds.get(&hir_id.local_id) + self.tables.closure_kinds().get(hir_id) { err.span_note(span, &format!( "closure cannot be invoked more than once because \ @@ -904,10 +903,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { match pat.node { hir::PatKind::Binding(..) => { - self.tables.validate_hir_id(pat.hir_id); *self.tables - .pat_binding_modes - .get(&pat.hir_id.local_id) + .pat_binding_modes() + .get(pat.hir_id) .expect("missing binding mode") } _ => bug!("local is not a binding: {:?}", pat) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index a990670f08bf..ea7deef47242 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -269,10 +269,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) { pat.walk(|p| { if let PatKind::Binding(_, _, name, None) = p.node { - cx.tables.validate_hir_id(p.hir_id); let bm = *cx.tables - .pat_binding_modes - .get(&p.hir_id.local_id) + .pat_binding_modes() + .get(p.hir_id) .expect("missing binding mode"); if bm != ty::BindByValue(hir::MutImmutable) { @@ -464,10 +463,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, for pat in pats { pat.each_binding(|_, id, span, _path| { let hir_id = cx.tcx.hir.node_to_hir_id(id); - cx.tables.validate_hir_id(hir_id); let bm = *cx.tables - .pat_binding_modes - .get(&hir_id.local_id) + .pat_binding_modes() + .get(hir_id) .expect("missing binding mode"); if let ty::BindByReference(..) = bm { by_ref_span = Some(span); @@ -501,10 +499,9 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, for pat in pats { pat.walk(|p| { if let PatKind::Binding(_, _, _, ref sub) = p.node { - cx.tables.validate_hir_id(p.hir_id); let bm = *cx.tables - .pat_binding_modes - .get(&p.hir_id.local_id) + .pat_binding_modes() + .get(p.hir_id) .expect("missing binding mode"); match bm { ty::BindByValue(..) => { diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 924193786c1f..d151e817040a 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -381,8 +381,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyRef(r, _) => Some(r), _ => None, }; - let bm = *self.tables.pat_binding_modes.get(&pat.hir_id.local_id) - .expect("missing binding mode"); + let bm = *self.tables.pat_binding_modes().get(pat.hir_id) + .expect("missing binding mode"); let (mutability, mode) = match bm { ty::BindByValue(hir::MutMutable) => (Mutability::Mut, BindingMode::ByValue), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 56c0fa7b2adf..cef35be59cd1 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -935,7 +935,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Check for method calls and overloaded operators. if cx.tables.is_method_call(expr) { let hir_id = cx.tcx.hir.definitions().node_to_hir_id(id); - let def_id = cx.tables.type_dependent_defs[&hir_id.local_id].def_id(); + let def_id = cx.tables.type_dependent_defs()[hir_id].def_id(); let substs = cx.tables.node_substs(hir_id); if method_call_refers_to_method(cx, method, def_id, substs, id) { return true; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index f8f91e6c29d3..65973d99c547 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -46,8 +46,7 @@ impl UnusedMut { for p in pats { p.each_binding(|_, id, span, path1| { let hir_id = cx.tcx.hir.node_to_hir_id(id); - cx.tables.validate_hir_id(hir_id); - let bm = match cx.tables.pat_binding_modes.get(&hir_id.local_id) { + let bm = match cx.tables.pat_binding_modes().get(hir_id) { Some(&bm) => bm, None => span_bug!(span, "missing binding mode"), }; diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index d029e2f10e88..14392ae70e4e 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -91,8 +91,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) let fn_hir_id = tcx.hir.node_to_hir_id(id); - cx.tables().validate_hir_id(fn_hir_id); - let fn_sig = cx.tables().liberated_fn_sigs[&fn_hir_id.local_id].clone(); + let fn_sig = cx.tables().liberated_fn_sigs()[fn_hir_id].clone(); let ty = tcx.type_of(tcx.hir.local_def_id(id)); let mut abi = fn_sig.abi; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 11da73187b37..5b3e4b1ddc37 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -387,11 +387,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, substs: substs, fields: field_refs, base: base.as_ref().map(|base| { - cx.tables().validate_hir_id(expr.hir_id); FruInfo { base: base.to_ref(), field_types: cx.tables() - .fru_field_types[&expr.hir_id.local_id] + .fru_field_types()[expr.hir_id] .clone(), } }), @@ -551,10 +550,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprCast(ref source, _) => { // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - cx.tables().validate_hir_id(source.hir_id); if let Some(&TyCastKind::CoercionCast) = cx.tables() - .cast_kinds - .get(&source.hir_id.local_id) { + .cast_kinds() + .get(source.hir_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { @@ -586,8 +584,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, -> Expr<'tcx> { let temp_lifetime = cx.region_maps.temporary_scope(expr.id); let (def_id, substs) = custom_callee.unwrap_or_else(|| { - cx.tables().validate_hir_id(expr.hir_id); - (cx.tables().type_dependent_defs[&expr.hir_id.local_id].def_id(), + (cx.tables().type_dependent_defs()[expr.hir_id].def_id(), cx.tables().node_substs(expr.hir_id)) }); Expr { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 4a2925175c27..a390448f43a9 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -320,8 +320,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } hir::ExprCast(ref from, _) => { debug!("Checking const cast(id={})", from.id); - v.tables.validate_hir_id(from.hir_id); - match v.tables.cast_kinds.get(&from.hir_id.local_id) { + match v.tables.cast_kinds().get(from.hir_id) { None => span_bug!(e.span, "no kind for cast"), Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => { v.promotable = false; @@ -388,8 +387,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - v.tables.validate_hir_id(e.hir_id); - let def_id = v.tables.type_dependent_defs[&e.hir_id.local_id].def_id(); + let def_id = v.tables.type_dependent_defs()[e.hir_id].def_id(); match v.tcx.associated_item(def_id).container { ty::ImplContainer(_) => v.handle_const_fn_call(def_id, node_ty), ty::TraitContainer(_) => v.promotable = false diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 1c5e528d887d..6f8c6a5ed3b0 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -649,7 +649,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { if self.tables.node_substs(id).visit_with(self) { return true; } - if let Some(adjustments) = self.tables.adjustments.get(&id.local_id) { + if let Some(adjustments) = self.tables.adjustments().get(id) { for adjustment in adjustments { if adjustment.target.visit_with(self) { return true; @@ -748,8 +748,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { } hir::ExprMethodCall(_, span, _) => { // Method calls have to be checked specially. - self.tables.validate_hir_id(expr.hir_id); - let def_id = self.tables.type_dependent_defs[&expr.hir_id.local_id].def_id(); + let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id(); self.span = span; if self.tcx.type_of(def_id).visit_with(self) { return; @@ -766,8 +765,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // we have to check it additionally. if let hir::QPath::TypeRelative(..) = *qpath { let hir_id = self.tcx.hir.node_to_hir_id(id); - self.tables.validate_hir_id(hir_id); - if let Some(def) = self.tables.type_dependent_defs.get(&hir_id.local_id).cloned() { + if let Some(def) = self.tables.type_dependent_defs().get(hir_id).cloned() { if let Some(assoc_item) = self.tcx.opt_associated_item(def.def_id()) { if let ty::ImplContainer(impl_def_id) = assoc_item.container { if self.tcx.type_of(impl_def_id).visit_with(self) { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index d46d8624a12c..8baea0fd83db 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -550,8 +550,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::MethodCall(..) => { - let local_id = self.tcx.hir.definitions().node_to_hir_id(expr.id).local_id; - let method_id = self.tables.type_dependent_defs[&local_id].def_id(); + let expr_hir_id = self.tcx.hir.definitions().node_to_hir_id(expr.id); + let method_id = self.tables.type_dependent_defs()[expr_hir_id].def_id(); let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 3a616dadc42f..b49b9377e8c5 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -118,11 +118,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // identical to what could be scraped from the HIR, but this will change with // default binding modes (#42640). let bm = ty::BindingMode::convert(ba); - { - let mut inh_tables = self.inh.tables.borrow_mut(); - inh_tables.validate_hir_id(pat.hir_id); - inh_tables.pat_binding_modes.insert(pat.hir_id.local_id, bm); - } + self.inh + .tables + .borrow_mut() + .pat_binding_modes_mut() + .insert(pat.hir_id, bm); let typ = self.local_ty(pat.span, pat.id); match bm { ty::BindByReference(mutbl) => { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 2be427eee1b9..b18b11f3d906 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -330,16 +330,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); debug!(" -> CoercionCast"); - let mut tables = fcx.tables.borrow_mut(); - tables.validate_hir_id(self.expr.hir_id); - tables.cast_kinds.insert(self.expr.hir_id.local_id, CastKind::CoercionCast); + fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id, + CastKind::CoercionCast); } else { match self.do_check(fcx) { Ok(k) => { debug!(" -> {:?}", k); - let mut tables = fcx.tables.borrow_mut(); - tables.validate_hir_id(self.expr.hir_id); - tables.cast_kinds.insert(self.expr.hir_id.local_id, k); + fcx.tables.borrow_mut().cast_kinds_mut().insert(self.expr.hir_id, k); } Err(e) => self.report_cast_error(fcx, e), }; diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8bf58d866efc..61795a7e623d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -104,11 +104,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(expr.hir_id); - tables.closure_tys.insert(expr.hir_id.local_id, sig); + tables.closure_tys_mut().insert(expr.hir_id, sig); match opt_kind { Some(kind) => { - tables.closure_kinds.insert(expr.hir_id.local_id, (kind, None)); + tables.closure_kinds_mut().insert(expr.hir_id, (kind, None)); } None => {} } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 428938eae828..53f3d811fae4 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -844,7 +844,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // First try to coerce the new expression to the type of the previous ones, // 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.hir_id.local_id) { + if !self.tables.borrow().adjustments().contains_key(new.hir_id) { let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty)); match result { Ok(ok) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 0294dab17d55..355e6cdbbe07 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -451,8 +451,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // tables borrowed during (`deref_mut`) method resolution. let previous_adjustments = self.tables .borrow_mut() - .adjustments - .remove(&expr.hir_id.local_id); + .adjustments_mut() + .remove(expr.hir_id); if let Some(mut adjustments) = previous_adjustments { let pref = LvaluePreference::PreferMutLvalue; for adjustment in &mut adjustments { @@ -469,7 +469,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } source = adjustment.target; } - self.tables.borrow_mut().adjustments.insert(expr.hir_id.local_id, adjustments); + self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments); } match expr.node { @@ -529,8 +529,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let base_expr_ty = self.node_ty(base_expr.hir_id); if let Some(adjustments) = self.tables .borrow_mut() - .adjustments - .get_mut(&base_expr.hir_id.local_id) { + .adjustments_mut() + .get_mut(base_expr.hir_id) { let mut source = base_expr_ty; for adjustment in &mut adjustments[..] { if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index fc8f4f32440a..5de4a35bdc72 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -829,9 +829,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { }; let closure_kind = { - let tables = self.tables.borrow(); - tables.validate_hir_id(closure_id); - match tables.closure_kinds.get(&closure_id.local_id) { + match self.tables.borrow().closure_kinds().get(closure_id) { Some(&(k, _)) => k, None => { return Err(MethodError::ClosureAmbiguity(trait_def_id)); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 60930d8184a3..483b5bb10209 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -744,7 +744,7 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> ty::ClosureKind { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let hir_id = tcx.hir.node_to_hir_id(node_id); - tcx.typeck_tables_of(def_id).closure_kinds[&hir_id.local_id].0 + tcx.typeck_tables_of(def_id).closure_kinds()[hir_id].0 } fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1028,12 +1028,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(arg.hir_id, arg_ty); } - { - let mut inh_tables = inherited.tables.borrow_mut(); - let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id); - inh_tables.validate_hir_id(fn_hir_id); - inh_tables.liberated_fn_sigs.insert(fn_hir_id.local_id, fn_sig); - } + let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id); + inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_hir_id, fn_sig); fcx.check_return_expr(&body.value); @@ -1816,11 +1812,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_type_vars_if_possible(&ty), self.tag()); - { - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(id); - tables.node_types.insert(id.local_id, ty); - } + self.tables.borrow_mut().node_types_mut().insert(id, ty); if ty.references_error() { self.has_errors.set(true); @@ -1833,11 +1825,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { - { - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(hir_id); - tables.type_dependent_defs.insert(hir_id.local_id, Def::Method(method.def_id)); - } + self.tables + .borrow_mut() + .type_dependent_defs_mut() + .insert(hir_id, Def::Method(method.def_id)); self.write_substs(hir_id, method.substs); } @@ -1848,9 +1839,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { substs, self.tag()); - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(node_id); - tables.node_substs.insert(node_id.local_id, substs); + self.tables.borrow_mut().node_substs_mut().insert(node_id, substs); } } @@ -1861,9 +1850,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return; } - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(expr.hir_id); - match tables.adjustments.entry(expr.hir_id.local_id) { + match self.tables.borrow_mut().adjustments_mut().entry(expr.hir_id) { Entry::Vacant(entry) => { entry.insert(adj); }, Entry::Occupied(mut entry) => { debug!(" - composing on top of {:?}", entry.get()); @@ -2017,9 +2004,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { - let tables = self.tables.borrow(); - tables.validate_hir_id(id); - match tables.node_types.get(&id.local_id) { + match self.tables.borrow().node_types().get(id) { Some(&t) => t, None if self.err_count_since_creation() != 0 => self.tcx.types.err, None => { @@ -2682,7 +2667,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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.hir_id.local_id), + assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id), "expression with never type wound up being adjusted"); let adj_ty = self.next_diverging_ty_var( TypeVariableOrigin::AdjustmentType(expr.span)); @@ -3408,9 +3393,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) }).collect(); - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(expr.hir_id); - tables.fru_field_types.insert(expr.hir_id.local_id, fru_field_types); + self.tables + .borrow_mut() + .fru_field_types_mut() + .insert(expr.hir_id, fru_field_types); } _ => { span_err!(self.tcx.sess, base_expr.span, E0436, @@ -4043,9 +4029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Write back the new resolution. let hir_id = self.tcx.hir.node_to_hir_id(node_id); - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(hir_id); - tables.type_dependent_defs.insert(hir_id.local_id, def); + self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def); (def, ty) } @@ -4087,9 +4071,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Write back the new resolution. let hir_id = self.tcx.hir.node_to_hir_id(node_id); - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(hir_id); - tables.type_dependent_defs.insert(hir_id.local_id, def); + self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def); (def, Some(ty), slice::ref_slice(&**item_segment)) } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index f2104b8dbae0..a4e1fdaf39e2 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -210,10 +210,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // some cases applied on the RHS, on top of which we need // to autoref, which is not allowed by apply_adjustments. // self.apply_adjustments(rhs_expr, vec![autoref]); - let mut tables = self.tables.borrow_mut(); - tables.validate_hir_id(rhs_expr.hir_id); - tables.adjustments.entry(rhs_expr.hir_id.local_id) - .or_insert(vec![]).push(autoref); + self.tables + .borrow_mut() + .adjustments_mut() + .entry(rhs_expr.hir_id) + .or_insert(vec![]) + .push(autoref); } } self.write_method_call(expr.hir_id, method); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index c9c8f3363cee..b187075a36d2 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -309,10 +309,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let old_call_site_scope = self.set_call_site_scope(Some(call_site)); let fn_sig = { - let tables = self.tables.borrow(); let fn_hir_id = self.tcx.hir.node_to_hir_id(id); - tables.validate_hir_id(fn_hir_id); - match tables.liberated_fn_sigs.get(&fn_hir_id.local_id) { + match self.tables.borrow().liberated_fn_sigs().get(fn_hir_id) { Some(f) => f.clone(), None => { bug!("No fn-sig entry for id={}", id); @@ -1121,14 +1119,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // report errors later on in the writeback phase. let ty0 = self.resolve_node_type(hir_id); - let ty = { - let tables = self.tables.borrow(); - tables.validate_hir_id(hir_id); - tables.adjustments - .get(&hir_id.local_id) - .and_then(|adj| adj.last()) - .map_or(ty0, |adj| adj.target) - }; + let ty = self.tables + .borrow() + .adjustments() + .get(hir_id) + .and_then(|adj| adj.last()) + .map_or(ty0, |adj| adj.target); let ty = self.resolve_type(ty); debug!("constrain_regions_in_type_of_node(\ ty={}, ty0={}, id={:?}, minimum_lifetime={:?})", @@ -1207,9 +1203,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match sub_pat.node { // `ref x` pattern PatKind::Binding(..) => { - mc.tables.validate_hir_id(sub_pat.hir_id); - let bm = *mc.tables.pat_binding_modes.get(&sub_pat.hir_id.local_id) - .expect("missing binding mode"); + let bm = *mc.tables.pat_binding_modes().get(sub_pat.hir_id) + .expect("missing binding mode"); if let ty::BindByReference(mutbl) = bm { self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id, mutbl, sub_cmt); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 111f224c3d1f..6db5c5b1cb0a 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -103,8 +103,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let infer_kind = match self.tables .borrow_mut() - .closure_kinds - .entry(closure_hir_id.local_id) { + .closure_kinds_mut() + .entry(closure_hir_id) { Entry::Occupied(_) => false, Entry::Vacant(entry) => { debug!("check_closure: adding closure {:?} as Fn", closure_node_id); @@ -162,8 +162,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .remove(&closure_def_id.index) { self.tables .borrow_mut() - .closure_kinds - .insert(closure_hir_id.local_id, kind); + .closure_kinds_mut() + .insert(closure_hir_id, kind); } } self.tables.borrow_mut().upvar_capture_map.extend( @@ -482,9 +482,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned() .or_else(|| { let closure_id = self.fcx.tcx.hir.def_index_to_hir_id(closure_id); - let fcx_tables = self.fcx.tables.borrow(); - fcx_tables.validate_hir_id(closure_id); - fcx_tables.closure_kinds.get(&closure_id.local_id).cloned() + self.fcx.tables.borrow().closure_kinds().get(closure_id).cloned() }); if let Some((existing_kind, _)) = closure_kind { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 515bbe49c39b..0e7083b72f5f 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -93,8 +93,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) { debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty); assert!(!ty.needs_infer()); - self.tables.validate_hir_id(hir_id); - self.tables.node_types.insert(hir_id.local_id, ty); + self.tables.node_types_mut().insert(hir_id, ty); } // Hacky hack: During type-checking, we treat *all* operators @@ -110,9 +109,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if inner_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); - tables.validate_hir_id(e.hir_id); - tables.type_dependent_defs.remove(&e.hir_id.local_id); - tables.node_substs.remove(&e.hir_id.local_id); + tables.type_dependent_defs_mut().remove(e.hir_id); + tables.node_substs_mut().remove(e.hir_id); } } hir::ExprBinary(ref op, ref lhs, ref rhs) | @@ -125,19 +123,19 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if lhs_ty.is_scalar() && rhs_ty.is_scalar() { let mut tables = self.fcx.tables.borrow_mut(); - tables.validate_hir_id(e.hir_id); - tables.type_dependent_defs.remove(&e.hir_id.local_id); - tables.node_substs.remove(&e.hir_id.local_id); + tables.type_dependent_defs_mut().remove(e.hir_id); + tables.node_substs_mut().remove(e.hir_id); match e.node { hir::ExprBinary(..) => { if !op.node.is_by_value() { - tables.adjustments.get_mut(&lhs.hir_id.local_id).map(|a| a.pop()); - tables.adjustments.get_mut(&rhs.hir_id.local_id).map(|a| a.pop()); + let mut adjustments = tables.adjustments_mut(); + adjustments.get_mut(lhs.hir_id).map(|a| a.pop()); + adjustments.get_mut(rhs.hir_id).map(|a| a.pop()); } }, hir::ExprAssignOp(..) => { - tables.adjustments.get_mut(&lhs.hir_id.local_id).map(|a| a.pop()); + tables.adjustments_mut().get_mut(lhs.hir_id).map(|a| a.pop()); }, _ => {}, } @@ -186,14 +184,13 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_pat(&mut self, p: &'gcx hir::Pat) { match p.node { hir::PatKind::Binding(..) => { - let bm = { - let fcx_tables = self.fcx.tables.borrow(); - fcx_tables.validate_hir_id(p.hir_id); - *fcx_tables.pat_binding_modes.get(&p.hir_id.local_id) - .expect("missing binding mode") - }; - self.tables.validate_hir_id(p.hir_id); - self.tables.pat_binding_modes.insert(p.hir_id.local_id, bm); + let bm = *self.fcx + .tables + .borrow() + .pat_binding_modes() + .get(p.hir_id) + .expect("missing binding mode"); + self.tables.pat_binding_modes_mut().insert(p.hir_id, bm); } _ => {} }; @@ -233,23 +230,36 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); - for (&id, closure_ty) in fcx_tables.closure_tys.iter() { + for (&id, closure_ty) in fcx_tables.closure_tys().iter() { let hir_id = hir::HirId { owner: fcx_tables.local_id_root.index, local_id: id, }; let closure_ty = self.resolve(closure_ty, &hir_id); - self.tables.closure_tys.insert(id, closure_ty); + self.tables.closure_tys_mut().insert(hir_id, closure_ty); } - for (&id, &closure_kind) in fcx_tables.closure_kinds.iter() { - self.tables.closure_kinds.insert(id, closure_kind); + for (&id, &closure_kind) in fcx_tables.closure_kinds().iter() { + let hir_id = hir::HirId { + owner: fcx_tables.local_id_root.index, + local_id: id, + }; + self.tables.closure_kinds_mut().insert(hir_id, closure_kind); } } fn visit_cast_types(&mut self) { - self.tables.cast_kinds.extend( - self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value))); + let fcx_tables = self.fcx.tables.borrow(); + let fcx_cast_kinds = fcx_tables.cast_kinds(); + let mut self_cast_kinds = self.tables.cast_kinds_mut(); + + for (&local_id, &cast_kind) in fcx_cast_kinds.iter() { + let hir_id = hir::HirId { + owner: fcx_tables.local_id_root.index, + local_id, + }; + self_cast_kinds.insert(hir_id, cast_kind); + } } fn visit_free_region_map(&mut self) { @@ -293,20 +303,18 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { }); let hir_id = self.tcx().hir.node_to_hir_id(node_id); - self.tables.validate_hir_id(hir_id); - self.tables.node_types.insert(hir_id.local_id, outside_ty); + self.tables.node_types_mut().insert(hir_id, outside_ty); } } fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) { - { - let mut fcx_tables = self.fcx.tables.borrow_mut(); - fcx_tables.validate_hir_id(hir_id); - // Export associated path extensions and method resultions. - if let Some(def) = fcx_tables.type_dependent_defs.remove(&hir_id.local_id) { - self.tables.validate_hir_id(hir_id); - self.tables.type_dependent_defs.insert(hir_id.local_id, def); - } + // Export associated path extensions and method resultions. + if let Some(def) = self.fcx + .tables + .borrow_mut() + .type_dependent_defs_mut() + .remove(hir_id) { + self.tables.type_dependent_defs_mut().insert(hir_id, def); } // Resolve any borrowings for the node with id `node_id` @@ -319,20 +327,20 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { debug!("Node {:?} has type {:?}", hir_id, n_ty); // Resolve any substitutions - if let Some(&substs) = self.fcx.tables.borrow().node_substs.get(&hir_id.local_id) { + if let Some(substs) = self.fcx.tables.borrow().node_substs_opt(hir_id) { let substs = self.resolve(&substs, &span); debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); assert!(!substs.needs_infer()); - self.tables.node_substs.insert(hir_id.local_id, substs); + self.tables.node_substs_mut().insert(hir_id, substs); } } fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) { - let adjustment = { - let mut fcx_tables = self.fcx.tables.borrow_mut(); - fcx_tables.validate_hir_id(hir_id); - fcx_tables.adjustments.remove(&hir_id.local_id) - }; + let adjustment = self.fcx + .tables + .borrow_mut() + .adjustments_mut() + .remove(hir_id); match adjustment { None => { debug!("No adjustments for node {:?}", hir_id); @@ -341,8 +349,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { Some(adjustment) => { let resolved_adjustment = self.resolve(&adjustment, &span); debug!("Adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); - self.tables.validate_hir_id(hir_id); - self.tables.adjustments.insert(hir_id.local_id, resolved_adjustment); + self.tables.adjustments_mut().insert(hir_id, resolved_adjustment); } } } @@ -351,13 +358,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); - for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs.iter() { + for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs().iter() { let hir_id = hir::HirId { owner: fcx_tables.local_id_root.index, local_id, }; let fn_sig = self.resolve(fn_sig, &hir_id); - self.tables.liberated_fn_sigs.insert(local_id, fn_sig.clone()); + self.tables.liberated_fn_sigs_mut().insert(hir_id, fn_sig.clone()); } } @@ -365,13 +372,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); - for (&local_id, ftys) in fcx_tables.fru_field_types.iter() { + for (&local_id, ftys) in fcx_tables.fru_field_types().iter() { let hir_id = hir::HirId { owner: fcx_tables.local_id_root.index, local_id, }; let ftys = self.resolve(ftys, &hir_id); - self.tables.fru_field_types.insert(local_id, ftys); + self.tables.fru_field_types_mut().insert(hir_id, ftys); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 30188a7cbdce..91b41eb33a17 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1240,9 +1240,7 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } NodeExpr(&hir::Expr { node: hir::ExprClosure(..), hir_id, .. }) => { - let tables = tcx.typeck_tables_of(def_id); - tables.validate_hir_id(hir_id); - tables.closure_tys[&hir_id.local_id] + tcx.typeck_tables_of(def_id).closure_tys()[hir_id] } x => { From a69eaf62c5e325c96c9924102829a42cbfd37424 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 11 Aug 2017 11:56:26 +0200 Subject: [PATCH 37/88] Improve validation of TypeckTables keys. --- src/librustc/infer/mod.rs | 2 +- src/librustc/lint/context.rs | 4 +- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/effect.rs | 3 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/ty/context.rs | 52 ++++++++++++++++---------- src/librustc_driver/pretty.rs | 3 +- src/librustc_passes/consts.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/writeback.rs | 17 ++++++--- 12 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1a8d570bde03..186eab724db3 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -359,7 +359,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { /// Used only by `rustc_typeck` during body type-checking/inference, /// will initialize `in_progress_tables` with fresh `TypeckTables`. pub fn with_fresh_in_progress_tables(mut self, table_owner: DefId) -> Self { - self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(table_owner))); + self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(Some(table_owner)))); self } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index cd06806ca601..930e8e750908 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -43,7 +43,7 @@ use syntax::ast; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use hir; -use hir::def_id::{DefId, LOCAL_CRATE}; +use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; @@ -986,7 +986,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut cx = LateContext { tcx, - tables: &ty::TypeckTables::empty(DefId::invalid()), + tables: &ty::TypeckTables::empty(None), param_env: ty::ParamEnv::empty(Reveal::UserFacing), access_levels, lint_sess: LintSession::new(&tcx.sess.lint_store), diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 0081555095b2..ed04186eb286 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -427,7 +427,7 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, - tables: &ty::TypeckTables::empty(DefId::invalid()), + tables: &ty::TypeckTables::empty(None), live_symbols: box FxHashSet(), struct_has_extern_repr: false, ignore_non_const_paths: false, diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 6b7280cf0ac4..98934d607032 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -19,7 +19,6 @@ use syntax::ast; use syntax_pos::Span; use hir::{self, PatKind}; use hir::def::Def; -use hir::def_id::DefId; use hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap}; #[derive(Copy, Clone)] @@ -263,7 +262,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = EffectCheckVisitor { tcx, - tables: &ty::TypeckTables::empty(DefId::invalid()), + tables: &ty::TypeckTables::empty(None), body_id: hir::BodyId { node_id: ast::CRATE_NODE_ID }, unsafe_context: UnsafeContext::new(SafeContext), }; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index bd9a413ca617..1e2bb6627afc 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -375,7 +375,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> }); let mut reachable_context = ReachableContext { tcx, - tables: &ty::TypeckTables::empty(DefId::invalid()), + tables: &ty::TypeckTables::empty(None), reachable_symbols: NodeSet(), worklist: Vec::new(), any_library, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ac851f182a0f..d93750ec04e0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -212,7 +212,7 @@ pub struct CommonTypes<'tcx> { } pub struct LocalTableInContext<'a, V: 'a> { - local_id_root: DefId, + local_id_root: Option, data: &'a ItemLocalMap } @@ -223,11 +223,13 @@ pub struct LocalTableInContext<'a, V: 'a> { /// would be in a different frame of reference and using its `local_id` /// would result in lookup errors, or worse, in silently wrong data being /// stored/returned. -fn validate_hir_id_for_typeck_tables(table_id_root: DefId, hir_id: hir::HirId) { +fn validate_hir_id_for_typeck_tables(local_id_root: Option, + hir_id: hir::HirId, + mut_access: bool) { #[cfg(debug_assertions)] { - if table_id_root.is_local() { - if hir_id.owner != table_id_root.index { + if let Some(local_id_root) = local_id_root { + if hir_id.owner != local_id_root.index { ty::tls::with(|tcx| { let node_id = tcx.hir .definitions() @@ -237,21 +239,30 @@ fn validate_hir_id_for_typeck_tables(table_id_root: DefId, hir_id: hir::HirId) { TypeckTables with local_id_root {:?}", tcx.hir.node_to_string(node_id), DefId::local(hir_id.owner), - table_id_root) + local_id_root) }); } + } else { + // We use "Null Object" TypeckTables in some of the analysis passes. + // These are just expected to be empty and their `local_id_root` is + // `None`. Therefore we cannot verify whether a given `HirId` would + // be a valid key for the given table. Instead we make sure that + // nobody tries to write to such a Null Object table. + if mut_access { + bug!("access to invalid TypeckTables") + } } } } impl<'a, V> LocalTableInContext<'a, V> { pub fn contains_key(&self, id: hir::HirId) -> bool { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.data.contains_key(&id.local_id) } pub fn get(&self, id: hir::HirId) -> Option<&V> { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.data.get(&id.local_id) } @@ -269,29 +280,29 @@ impl<'a, V> ::std::ops::Index for LocalTableInContext<'a, V> { } pub struct LocalTableInContextMut<'a, V: 'a> { - local_id_root: DefId, + local_id_root: Option, data: &'a mut ItemLocalMap } impl<'a, V> LocalTableInContextMut<'a, V> { pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, true); self.data.get_mut(&id.local_id) } pub fn entry(&mut self, id: hir::HirId) -> Entry { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, true); self.data.entry(id.local_id) } pub fn insert(&mut self, id: hir::HirId, val: V) -> Option { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, true); self.data.insert(id.local_id, val) } pub fn remove(&mut self, id: hir::HirId) -> Option { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, true); self.data.remove(&id.local_id) } } @@ -299,7 +310,7 @@ impl<'a, V> LocalTableInContextMut<'a, V> { #[derive(RustcEncodable, RustcDecodable)] pub struct TypeckTables<'tcx> { /// The HirId::owner all ItemLocalIds in this table are relative to. - pub local_id_root: DefId, + pub local_id_root: Option, /// Resolved definitions for `::X` associated paths and /// method calls, including those of overloaded operators. @@ -363,7 +374,7 @@ pub struct TypeckTables<'tcx> { } impl<'tcx> TypeckTables<'tcx> { - pub fn empty(local_id_root: DefId) -> TypeckTables<'tcx> { + pub fn empty(local_id_root: Option) -> TypeckTables<'tcx> { TypeckTables { local_id_root, type_dependent_defs: ItemLocalMap(), @@ -388,7 +399,7 @@ impl<'tcx> TypeckTables<'tcx> { match *qpath { hir::QPath::Resolved(_, ref path) => path.def, hir::QPath::TypeRelative(..) => { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.type_dependent_defs.get(&id.local_id).cloned().unwrap_or(Def::Err) } } @@ -436,7 +447,7 @@ impl<'tcx> TypeckTables<'tcx> { } pub fn node_id_to_type_opt(&self, id: hir::HirId) -> Option> { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.node_types.get(&id.local_id).cloned() } @@ -448,12 +459,12 @@ impl<'tcx> TypeckTables<'tcx> { } pub fn node_substs(&self, id: hir::HirId) -> &'tcx Substs<'tcx> { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.node_substs.get(&id.local_id).cloned().unwrap_or(Substs::empty()) } pub fn node_substs_opt(&self, id: hir::HirId) -> Option<&'tcx Substs<'tcx>> { - validate_hir_id_for_typeck_tables(self.local_id_root, id); + validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.node_substs.get(&id.local_id).cloned() } @@ -502,7 +513,7 @@ impl<'tcx> TypeckTables<'tcx> { pub fn expr_adjustments(&self, expr: &hir::Expr) -> &[ty::adjustment::Adjustment<'tcx>] { - validate_hir_id_for_typeck_tables(self.local_id_root, expr.hir_id); + validate_hir_id_for_typeck_tables(self.local_id_root, expr.hir_id, false); self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..]) } @@ -663,6 +674,9 @@ impl<'a, 'gcx, 'tcx> HashStable> for Typeck closure_expr_id } = *up_var_id; + let local_id_root = + local_id_root.expect("trying to hash invalid TypeckTables"); + let var_def_id = DefId { krate: local_id_root.krate, index: var_id, diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 51f5cc4f249f..828136d6b7e4 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -45,7 +45,6 @@ use std::option; use std::path::Path; use std::str::FromStr; -use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::hir::map::blocks; use rustc::hir; @@ -233,7 +232,7 @@ impl PpSourceMode { arenas, id, |tcx, _, _, _| { - let empty_tables = ty::TypeckTables::empty(DefId::invalid()); + let empty_tables = ty::TypeckTables::empty(None); let annotation = TypedAnnotation { tcx: tcx, tables: Cell::new(&empty_tables) diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index a390448f43a9..9185f73974cd 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -471,7 +471,7 @@ 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.hir.krate().visit_all_item_likes(&mut CheckCrateVisitor { tcx: tcx, - tables: &ty::TypeckTables::empty(DefId::invalid()), + tables: &ty::TypeckTables::empty(None), in_fn: false, promotable: false, mut_rvalue_borrows: NodeSet(), diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 6f8c6a5ed3b0..373d7911cf93 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1656,7 +1656,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.hir.krate(); - let empty_tables = ty::TypeckTables::empty(DefId::invalid()); + let empty_tables = ty::TypeckTables::empty(None); // Check privacy of names not checked in previous compilation stages. diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8baea0fd83db..c3d071d27d6e 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -977,7 +977,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(tcx: TyCtxt<'l, 'tcx, 'tcx>, let save_ctxt = SaveContext { tcx: tcx, - tables: &ty::TypeckTables::empty(DefId::invalid()), + tables: &ty::TypeckTables::empty(None), analysis: analysis, span_utils: SpanUtils::new(&tcx.sess), config: find_config(config), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 483b5bb10209..826e8de860b9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -901,7 +901,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Consistency check our TypeckTables instance can hold all ItemLocalIds // it will need to hold. assert_eq!(tables.local_id_root, - DefId::local(tcx.hir.definitions().node_to_hir_id(id).owner)); + Some(DefId::local(tcx.hir.definitions().node_to_hir_id(id).owner))); tables } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 0e7083b72f5f..a363e47a14f2 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -81,7 +81,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { WritebackCx { fcx: fcx, - tables: ty::TypeckTables::empty(DefId::local(owner.owner)), + tables: ty::TypeckTables::empty(Some(DefId::local(owner.owner))), body: body } } @@ -229,10 +229,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_closures(&mut self) { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + let common_local_id_root = fcx_tables.local_id_root.unwrap(); for (&id, closure_ty) in fcx_tables.closure_tys().iter() { let hir_id = hir::HirId { - owner: fcx_tables.local_id_root.index, + owner: common_local_id_root.index, local_id: id, }; let closure_ty = self.resolve(closure_ty, &hir_id); @@ -241,7 +242,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { for (&id, &closure_kind) in fcx_tables.closure_kinds().iter() { let hir_id = hir::HirId { - owner: fcx_tables.local_id_root.index, + owner: common_local_id_root.index, local_id: id, }; self.tables.closure_kinds_mut().insert(hir_id, closure_kind); @@ -251,11 +252,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_cast_types(&mut self) { let fcx_tables = self.fcx.tables.borrow(); let fcx_cast_kinds = fcx_tables.cast_kinds(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); let mut self_cast_kinds = self.tables.cast_kinds_mut(); + let common_local_id_root = fcx_tables.local_id_root.unwrap(); for (&local_id, &cast_kind) in fcx_cast_kinds.iter() { let hir_id = hir::HirId { - owner: fcx_tables.local_id_root.index, + owner: common_local_id_root.index, local_id, }; self_cast_kinds.insert(hir_id, cast_kind); @@ -357,10 +360,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_liberated_fn_sigs(&mut self) { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + let common_local_id_root = fcx_tables.local_id_root.unwrap(); for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs().iter() { let hir_id = hir::HirId { - owner: fcx_tables.local_id_root.index, + owner: common_local_id_root.index, local_id, }; let fn_sig = self.resolve(fn_sig, &hir_id); @@ -371,10 +375,11 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_fru_field_types(&mut self) { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + let common_local_id_root = fcx_tables.local_id_root.unwrap(); for (&local_id, ftys) in fcx_tables.fru_field_types().iter() { let hir_id = hir::HirId { - owner: fcx_tables.local_id_root.index, + owner: common_local_id_root.index, local_id, }; let ftys = self.resolve(ftys, &hir_id); From e5938ef3c4b653db16c60f9a3d19a776a04c5194 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Aug 2017 13:43:31 +0200 Subject: [PATCH 38/88] Add (a lot of) missing links in fmt module docs --- src/liballoc/fmt.rs | 87 ++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index 4847b21c0b3b..5fc583d9e017 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -10,16 +10,16 @@ //! Utilities for formatting and printing `String`s //! -//! This module contains the runtime support for the `format!` syntax extension. +//! This module contains the runtime support for the [`format!`] syntax extension. //! This macro is implemented in the compiler to emit calls to this module in //! order to format arguments at runtime into strings. //! //! # Usage //! -//! The `format!` macro is intended to be familiar to those coming from C's -//! printf/fprintf functions or Python's `str.format` function. +//! The [`format!`] macro is intended to be familiar to those coming from C's +//! `printf`/`fprintf` functions or Python's `str.format` function. //! -//! Some examples of the `format!` extension are: +//! Some examples of the [`format!`] extension are: //! //! ``` //! format!("Hello"); // => "Hello" @@ -67,7 +67,7 @@ //! ## Named parameters //! //! Rust itself does not have a Python-like equivalent of named parameters to a -//! function, but the `format!` macro is a syntax extension which allows it to +//! function, but the [`format!`] macro is a syntax extension which allows it to //! leverage named parameters. Named parameters are listed at the end of the //! argument list and have the syntax: //! @@ -75,7 +75,7 @@ //! identifier '=' expression //! ``` //! -//! For example, the following `format!` expressions all use named argument: +//! For example, the following [`format!`] expressions all use named argument: //! //! ``` //! format!("{argument}", argument = "test"); // => "test" @@ -102,30 +102,30 @@ //! //! If this syntax is used, then the number of characters to print precedes the //! actual object being formatted, and the number of characters must have the -//! type `usize`. +//! type [`usize`]. //! //! ## Formatting traits //! //! When requesting that an argument be formatted with a particular type, you //! are actually requesting that an argument ascribes to a particular trait. -//! This allows multiple actual types to be formatted via `{:x}` (like `i8` as -//! well as `isize`). The current mapping of types to traits is: +//! This allows multiple actual types to be formatted via `{:x}` (like [`i8`] as +//! well as [`isize`]). The current mapping of types to traits is: //! -//! * *nothing* ⇒ [`Display`](trait.Display.html) -//! * `?` ⇒ [`Debug`](trait.Debug.html) +//! * *nothing* ⇒ [`Display`] +//! * `?` ⇒ [`Debug`] //! * `o` ⇒ [`Octal`](trait.Octal.html) //! * `x` ⇒ [`LowerHex`](trait.LowerHex.html) //! * `X` ⇒ [`UpperHex`](trait.UpperHex.html) //! * `p` ⇒ [`Pointer`](trait.Pointer.html) -//! * `b` ⇒ [`Binary`](trait.Binary.html) +//! * `b` ⇒ [`Binary`] //! * `e` ⇒ [`LowerExp`](trait.LowerExp.html) //! * `E` ⇒ [`UpperExp`](trait.UpperExp.html) //! //! What this means is that any type of argument which implements the -//! `fmt::Binary` trait can then be formatted with `{:b}`. Implementations +//! [`fmt::Binary`][`Binary`] trait can then be formatted with `{:b}`. Implementations //! are provided for these traits for a number of primitive types by the //! standard library as well. If no format is specified (as in `{}` or `{:6}`), -//! then the format trait used is the `Display` trait. +//! then the format trait used is the [`Display`] trait. //! //! When implementing a format trait for your own type, you will have to //! implement a method of the signature: @@ -144,15 +144,15 @@ //! should emit output into the `f.buf` stream. It is up to each format trait //! implementation to correctly adhere to the requested formatting parameters. //! The values of these parameters will be listed in the fields of the -//! `Formatter` struct. In order to help with this, the `Formatter` struct also +//! [`Formatter`] struct. In order to help with this, the [`Formatter`] struct also //! provides some helper methods. //! -//! Additionally, the return value of this function is `fmt::Result` which is a -//! type alias of `Result<(), std::fmt::Error>`. Formatting implementations -//! should ensure that they propagate errors from the `Formatter` (e.g., when -//! calling `write!`) however, they should never return errors spuriously. That +//! Additionally, the return value of this function is [`fmt::Result`] which is a +//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations +//! should ensure that they propagate errors from the [`Formatter`] (e.g., when +//! calling [`write!`]) however, they should never return errors spuriously. That //! is, a formatting implementation must and may only return an error if the -//! passed-in `Formatter` returns an error. This is because, contrary to what +//! passed-in [`Formatter`] returns an error. This is because, contrary to what //! the function signature might suggest, string formatting is an infallible //! operation. This function only returns a result because writing to the //! underlying stream might fail and it must provide a way to propagate the fact @@ -209,12 +209,12 @@ //! //! These two formatting traits have distinct purposes: //! -//! - `fmt::Display` implementations assert that the type can be faithfully +//! - [`fmt::Display`][`Display] implementations assert that the type can be faithfully //! represented as a UTF-8 string at all times. It is **not** expected that //! all types implement the `Display` trait. -//! - `fmt::Debug` implementations should be implemented for **all** public types. +//! - [`fmt::Debug`][`Debug`] implementations should be implemented for **all** public types. //! Output will typically represent the internal state as faithfully as possible. -//! The purpose of the `Debug` trait is to facilitate debugging Rust code. In +//! The purpose of the [`Debug`] trait is to facilitate debugging Rust code. In //! most cases, using `#[derive(Debug)]` is sufficient and recommended. //! //! Some examples of the output from both traits: @@ -227,7 +227,7 @@ //! //! ## Related macros //! -//! There are a number of related macros in the `format!` family. The ones that +//! There are a number of related macros in the [`format!`] family. The ones that //! are currently implemented are: //! //! ```ignore (only-for-syntax-highlight) @@ -241,11 +241,11 @@ //! //! ### `write!` //! -//! This and `writeln` are two macros which are used to emit the format string +//! This and [`writeln!`] are two macros which are used to emit the format string //! to a specified stream. This is used to prevent intermediate allocations of //! format strings and instead directly write the output. Under the hood, this -//! function is actually invoking the `write_fmt` function defined on the -//! `std::io::Write` trait. Example usage is: +//! function is actually invoking the [`write_fmt`] function defined on the +//! [`std::io::Write`] trait. Example usage is: //! //! ``` //! # #![allow(unused_must_use)] @@ -256,7 +256,7 @@ //! //! ### `print!` //! -//! This and `println` emit their output to stdout. Similarly to the `write!` +//! This and [`println!`] emit their output to stdout. Similarly to the [`write!`] //! macro, the goal of these macros is to avoid intermediate allocations when //! printing output. Example usage is: //! @@ -288,8 +288,8 @@ //! my_fmt_fn(format_args!(", or a {} too", "function")); //! ``` //! -//! The result of the `format_args!` macro is a value of type `fmt::Arguments`. -//! This structure can then be passed to the `write` and `format` functions +//! The result of the [`format_args!`] macro is a value of type [`fmt::Arguments`]. +//! This structure can then be passed to the [`write`] and [`format`] functions //! inside this module in order to process the format string. //! The goal of this macro is to even further prevent intermediate allocations //! when dealing formatting strings. @@ -384,9 +384,9 @@ //! the `0` flag is specified for numerics, then the implicit fill character is //! `0`. //! -//! The value for the width can also be provided as a `usize` in the list of +//! The value for the width can also be provided as a [`usize`] in the list of //! parameters by using the dollar syntax indicating that the second argument is -//! a `usize` specifying the width, for example: +//! a [`usize`] specifying the width, for example: //! //! ``` //! // All of these print "Hello x !" @@ -474,6 +474,29 @@ //! The literal characters `{` and `}` may be included in a string by preceding //! them with the same character. For example, the `{` character is escaped with //! `{{` and the `}` character is escaped with `}}`. +//! +//! [`format!`]: ../macro.format.html +//! [`usize`]: ../primitive.usize.html +//! [`isize`]: ../primitive.isize.html +//! [`i8`]: ../primitive.i8.html +//! [`Display`]: trait.Display.html +//! [`Binary`]: trait.Binary.html +//! [`fmt::Result`]: type.Result.html +//! [`Result`]: ../result/enum.Result.html +//! [`std::fmt::Error`]: struct.Error.html +//! [`Formatter`]: struct.Formatter.html +//! [`write!`]: ../macro.write.html +//! [`Debug`]: trait.Debug.html +//! [`format!`]: ../macro.format.html +//! [`writeln!`]: ../macro.writeln.html +//! [`write_fmt`]: ../io/trait.Write.html#method.write_fmt +//! [`std::io::Write`]: ../io/trait.Write.html +//! [`println!`]: ../macro.println.html +//! [`write!`]: ../macro.write.html +//! [`format_args!`]: ../macro.format_args.html +//! [`fmt::Arguments`]: struct.Arguments.html +//! [`write`]: fn.write.html +//! [`format`]: fn.format.html #![stable(feature = "rust1", since = "1.0.0")] From 1e4aaea431a7fb87a54fd3dd9600c8a346744ff2 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 11 Aug 2017 16:24:18 -0400 Subject: [PATCH 39/88] address review feedback --- src/doc/rustdoc/src/the-doc-attribute.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index b77565ec2d71..978d7656bdd7 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -46,35 +46,41 @@ These options control how the docs look at a macro level. This form of the `doc` attribute lets you control the favicon of your docs. ```rust,ignore -#![doc(html_favicon_url = "https://foo.com/favicon.ico")] +#![doc(html_favicon_url = "https://example.com/favicon.ico")] ``` This will put `` into your docs, where the string for the attribute goes into the `{}`. +If you don't use this attribute, there will be no favicon. + ### `html_logo_url` This form of the `doc` attribute lets you control the logo in the upper left hand side of the docs. ```rust,ignore -#![doc(html_logo_url = "https://foo.com/logo.jpg")] +#![doc(html_logo_url = "https://example.com/logo.jpg")] ``` This will put `logo` into your docs, where the string for the attribute goes into the `{}`. +If you don't use this attribute, there will be no logo. + ### `html_playground_url` This form of the `doc` attribute lets you control where the "run" buttons on your documentation examples make requests to. ```rust,ignore -#![doc(html_playground_url = "https://playground.foo.com/")] +#![doc(html_playground_url = "https://playground.example.com/")] ``` Now, when you press "run", the button will make a request to this domain. +If you don't use this attribute, there will be no run buttons. + ### `issue_tracker_base_url` This form of the `doc` attribute is mostly only useful for the standard library; @@ -83,7 +89,7 @@ given. `rustdoc` uses this number, plus the base URL given here, to link to the tracking issue. ```rust,ignore -#![doc(issue_tracker_base_url = "https://github.com/foo/foo/issues/")] +#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] ``` ### `html_no_source` From 0b2c9f03efc248680a8e7eeedb6e5f8da5947774 Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Fri, 11 Aug 2017 13:43:33 -0700 Subject: [PATCH 40/88] Fix unused_result lint triggering when a function returns `()` or `!` Add a test for this case --- src/librustc_lint/unused.rs | 2 ++ src/test/ui/issue-43806.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/test/ui/issue-43806.rs diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index ba17df4cdca4..e5b818cd5fb5 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -146,6 +146,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let t = cx.tables.expr_ty(&expr); let ty_warned = match t.sty { + ty::TyTuple(ref tys, _) if tys.is_empty() => return, + ty::TyNever => return, ty::TyAdt(def, _) => check_must_use(cx, def.did, s.span, ""), _ => false, }; diff --git a/src/test/ui/issue-43806.rs b/src/test/ui/issue-43806.rs new file mode 100644 index 000000000000..df7f756127c4 --- /dev/null +++ b/src/test/ui/issue-43806.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. + +// run-pass + +#![deny(unused_results)] + +fn foo() {} + +fn bar() -> ! { + loop {} +} + +fn qux() { + foo(); + bar(); +} + +fn main() {} From 035d4ea2cabb029ce64e7e1bb0cceb0f4b0ad80d Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 11 Aug 2017 16:43:38 -0400 Subject: [PATCH 41/88] rustdoc doc tests --- src/doc/rustdoc/src/documentation-tests.md | 238 ++++++++++++++++++++- 1 file changed, 237 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index cd7d657e1165..4f7736d8df6b 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -1,3 +1,239 @@ # Documentation tests -Coming soon! \ No newline at end of file +`rustdoc` supports executing your documentation examples as tests. This makes sure +that your tests are up to date and working. + +The basic idea is this: + +```rust,ignore +/// # Examples +/// +/// ``` +/// let x = 5; +/// ``` +``` + +The triple backticks start and end code blocks. If this were in a file named `foo.rs`, +running `rustdoc --test foo.rs` will extract this example, and then run it as a test. + +There's some subtlety though! Read on for more details. + +## Pre-processing examples + +In the example above, you'll note something strange: there's no `main` +function! Forcing you to write `main` for every example, no matter how small, +adds friction. So `rustdoc` processes your examples slightly before +running them. Here's the full algorithm rustdoc uses to preprocess examples: + +1. Any leading `#![foo]` attributes are left intact as crate attributes. +2. Some common `allow` attributes are inserted, including + `unused_variables`, `unused_assignments`, `unused_mut`, + `unused_attributes`, and `dead_code`. Small examples often trigger + these lints. +3. If the example does not contain `extern crate`, then `extern crate + ;` is inserted (note the lack of `#[macro_use]`). +4. Finally, if the example does not contain `fn main`, the remainder of the + text is wrapped in `fn main() { your_code }`. + +For more about that caveat in rule 3, see "Documeting Macros" below. + +## Hiding portions of the example + +Sometimes, you need some setup code, or other things that would distract +from your example, but are important to make the tests work. Consider +an example block that looks like this: + +```text +/// Some documentation. +# fn foo() {} +``` + +It will render like this: + +```rust +/// Some documentation. +# fn foo() {} +``` + +Yes, that's right: you can add lines that start with `# `, and they will +be hidden from the output, but will be used when compiling your code. You +can use this to your advantage. In this case, documentation comments need +to apply to some kind of function, so if I want to show you just a +documentation comment, I need to add a little function definition below +it. At the same time, it's only there to satisfy the compiler, so hiding +it makes the example more clear. You can use this technique to explain +longer examples in detail, while still preserving the testability of your +documentation. + +For example, imagine that we wanted to document this code: + +```rust +let x = 5; +let y = 6; +println!("{}", x + y); +``` + +We might want the documentation to end up looking like this: + +> First, we set `x` to five: +> +> ```rust +> let x = 5; +> # let y = 6; +> # println!("{}", x + y); +> ``` +> +> Next, we set `y` to six: +> +> ```rust +> # let x = 5; +> let y = 6; +> # println!("{}", x + y); +> ``` +> +> Finally, we print the sum of `x` and `y`: +> +> ```rust +> # let x = 5; +> # let y = 6; +> println!("{}", x + y); +> ``` + +To keep each code block testable, we want the whole program in each block, but +we don't want the reader to see every line every time. Here's what we put in +our source code: + +```text + First, we set `x` to five: + + ```rust + let x = 5; + # let y = 6; + # println!("{}", x + y); + ``` + + Next, we set `y` to six: + + ```rust + # let x = 5; + let y = 6; + # println!("{}", x + y); + ``` + + Finally, we print the sum of `x` and `y`: + + ```rust + # let x = 5; + # let y = 6; + println!("{}", x + y); + ``` +``` + +By repeating all parts of the example, you can ensure that your example still +compiles, while only showing the parts that are relevant to that part of your +explanation. + +Another case where the use of `#` is handy is when you want to ignore +error handling. Lets say you want the following, + +```rust,ignore +/// use std::io; +/// let mut input = String::new(); +/// io::stdin().read_line(&mut input)?; +``` + +The problem is that `?` returns a `Result` and test functions +don't return anything so this will give a mismatched types error. + +```rust,ignore +/// A doc test using ? +/// +/// ``` +/// use std::io; +/// # fn foo() -> io::Result<()> { +/// let mut input = String::new(); +/// io::stdin().read_line(&mut input)?; +/// # Ok(()) +/// # } +/// ``` +# fn foo() {} +``` + +You can get around this by wrapping the code in a function. This catches +and swallows the `Result` when running tests on the docs. This +pattern appears regularly in the standard library. + +### Documenting macros + +Here’s an example of documenting a macro: + +```rust +/// Panic with a given message unless an expression evaluates to true. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate foo; +/// # fn main() { +/// panic_unless!(1 + 1 == 2, “Math is broken.”); +/// # } +/// ``` +/// +/// ```rust,should_panic +/// # #[macro_use] extern crate foo; +/// # fn main() { +/// panic_unless!(true == false, “I’m broken.”); +/// # } +/// ``` +#[macro_export] +macro_rules! panic_unless { + ($condition:expr, $($rest:expr),+) => ({ if ! $condition { panic!($($rest),+); } }); +} +# fn main() {} +``` + +You’ll note three things: we need to add our own `extern crate` line, so that +we can add the `#[macro_use]` attribute. Second, we’ll need to add our own +`main()` as well (for reasons discussed above). Finally, a judicious use of +`#` to comment out those two things, so they don’t show up in the output. + +## Attributes + +There are a few annotations that are useful to help `rustdoc` do the right +thing when testing your code: + +```rust +/// ```ignore +/// fn foo() { +/// ``` +# fn foo() {} +``` + +The `ignore` directive tells Rust to ignore your code. This is almost never +what you want, as it's the most generic. Instead, consider annotating it +with `text` if it's not code, or using `#`s to get a working example that +only shows the part you care about. + +```rust +/// ```should_panic +/// assert!(false); +/// ``` +# fn foo() {} +``` + +`should_panic` tells `rustdoc` that the code should compile correctly, but +not actually pass as a test. + +```rust +/// ```no_run +/// loop { +/// println!("Hello, world"); +/// } +/// ``` +# fn foo() {} +``` + +The `no_run` attribute will compile your code, but not run it. This is +important for examples such as "Here's how to retrieve a web page," +which you would want to ensure compiles, but might be run in a test +environment that has no network access. \ No newline at end of file From a83d2afbba772f474872aacc6c21f2b5270fc517 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Aug 2017 15:58:26 -0700 Subject: [PATCH 42/88] std: Tag `AllocErr` functions as `#[inline]` None of these require a significant amount of code and using `#[inline]` will allow constructors to get inlined, improving codegen at allocation callsites. --- src/liballoc/allocator.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index 42111301a9fe..181eb7466d7a 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -354,15 +354,19 @@ pub enum AllocErr { } impl AllocErr { + #[inline] pub fn invalid_input(details: &'static str) -> Self { AllocErr::Unsupported { details: details } } + #[inline] pub fn is_memory_exhausted(&self) -> bool { if let AllocErr::Exhausted { .. } = *self { true } else { false } } + #[inline] pub fn is_request_unsupported(&self) -> bool { if let AllocErr::Unsupported { .. } = *self { true } else { false } } + #[inline] pub fn description(&self) -> &str { match *self { AllocErr::Exhausted { .. } => "allocator memory exhausted", From fae60b36cb48b1d5827eaaee656f0ff1a6cc6894 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Aug 2017 15:59:11 -0700 Subject: [PATCH 43/88] std: Tag OOM functions as `#[cold]` This was forgotten from #42727 by accident, but these functions are rarely called and codegen can be improved in LLVM with the `#[cold]` tag. --- src/liballoc/heap.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 1d959ac5bf6d..820f2d958d9a 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -28,6 +28,7 @@ pub mod __core { extern "Rust" { #[allocator] fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[cold] fn __rust_oom(err: *const u8) -> !; fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); fn __rust_usable_size(layout: *const u8, @@ -81,6 +82,7 @@ unsafe impl Alloc for Heap { } #[inline] + #[cold] fn oom(&mut self, err: AllocErr) -> ! { unsafe { __rust_oom(&err as *const AllocErr as *const u8) From 3093bb85f94e6f3c4707674c8b70c28ecfbf3bf9 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 11 Aug 2017 09:01:46 +0800 Subject: [PATCH 44/88] Fix error during cross-platform documentation. --- src/libstd/sys/unix/ext/net.rs | 11 +++++++++++ src/libstd/sys/windows/c.rs | 12 ++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 94b87a6bff49..1644ded5e5ce 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -12,8 +12,19 @@ //! Unix-specific networking functionality +#[cfg(unix)] use libc; +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +mod libc { + pub use libc::c_int; + pub type socklen_t = u32; + pub struct sockaddr; + #[derive(Clone)] + pub struct sockaddr_un; +} + use ascii; use ffi::OsStr; use fmt; diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 4785cefd6b4b..ba54ca6ea182 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -301,7 +301,7 @@ pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; pub const FD_SETSIZE: usize = 64; #[repr(C)] -#[cfg(target_arch = "x86")] +#[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { pub wVersion: WORD, pub wHighVersion: WORD, @@ -312,7 +312,7 @@ pub struct WSADATA { pub lpVendorInfo: *mut u8, } #[repr(C)] -#[cfg(target_arch = "x86_64")] +#[cfg(target_pointer_width = "64")] pub struct WSADATA { pub wVersion: WORD, pub wHighVersion: WORD, @@ -768,6 +768,14 @@ pub struct FLOATING_SAVE_AREA { _Dummy: [u8; 512] // FIXME: Fill this out } +// FIXME(#43348): This structure is used for backtrace only, and a fake +// definition is provided here only to allow rustdoc to pass type-check. This +// will not appear in the final documentation. This should be also defined for +// other architectures supported by Windows such as ARM, and for historical +// interest, maybe MIPS and PowerPC as well. +#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86"))))] +pub enum CONTEXT {} + #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, From ea6f0f060c05da71761ed1cfce5763ddcbe962be Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 11 Aug 2017 23:45:48 -0400 Subject: [PATCH 45/88] Demonstrate `include!` with Rust code, not just a string slice literal. --- src/libstd/macros.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 5e88a46ecc34..d3e367b815ac 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -545,23 +545,28 @@ pub mod builtin { /// Assume there are two files in the same directory with the following /// contents: /// - /// File 'my_str.in': + /// File 'monkeys.in': /// /// ```ignore (only-for-syntax-highlight) - /// "Hello World!" + /// ['🙈', '🙊', '🙉'] + /// .iter() + /// .cycle() + /// .take(6) + /// .collect::() /// ``` /// /// File 'main.rs': /// /// ```ignore (cannot-doctest-external-file-dependency) /// fn main() { - /// let my_str = include!("my_str.in"); - /// println!("{}", my_str); + /// let my_string = include!("monkeys.in"); + /// assert_eq!("🙈🙊🙉🙈🙊🙉", my_string); + /// println!("{}", my_string); /// } /// ``` /// - /// Compiling 'main.rs' and running the resulting binary will print "Hello - /// World!". + /// Compiling 'main.rs' and running the resulting binary will print + /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } From 446ff0d529ff0d3747bcf11b36dd7c60e6a900d5 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 12 Aug 2017 00:22:49 -0400 Subject: [PATCH 46/88] Add complete doc example for `include_bytes!`. --- src/libstd/macros.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index d3e367b815ac..bc170f8ce1be 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -478,9 +478,26 @@ pub mod builtin { /// /// # Examples /// - /// ```ignore (cannot-doctest-external-file-dependency) - /// let secret_key = include_bytes!("secret-key.bin"); + /// Assume there are two files in the same directory with the following + /// contents: + /// + /// File 'spanish.in': + /// + /// ```text + /// adiós /// ``` + /// + /// File 'main.rs': + /// + /// ```ignore (cannot-doctest-external-file-dependency) + /// fn main() { + /// let bytes = include_bytes!("spanish.in"); + /// assert_eq!(bytes, b"adi\xc3\xb3s\n"); + /// print!("{}", String::from_utf8_lossy(bytes)); + /// } + /// ``` + /// + /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } From 8d0d2a572939b2fba74a59db2de0ad4e30484b43 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 12 Aug 2017 00:25:49 -0400 Subject: [PATCH 47/88] Add complete doc example for `include_str!`. --- src/libstd/macros.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index bc170f8ce1be..c426bf8086ee 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -461,9 +461,26 @@ pub mod builtin { /// /// # Examples /// - /// ```ignore (cannot-doctest-external-file-dependency) - /// let secret_key = include_str!("secret-key.ascii"); + /// Assume there are two files in the same directory with the following + /// contents: + /// + /// File 'spanish.in': + /// + /// ```text + /// adiós /// ``` + /// + /// File 'main.rs': + /// + /// ```ignore (cannot-doctest-external-file-dependency) + /// fn main() { + /// let my_str = include_str!("spanish.in"); + /// assert_eq!(my_str, "adiós\n"); + /// print!("{}", my_str); + /// } + /// ``` + /// + /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } From eeb748aa12a3bb7f6bbd1205385fa0a0adbef90c Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Fri, 11 Aug 2017 21:52:16 -0700 Subject: [PATCH 48/88] Don't trigger unused_result on functions returning empty enums --- src/librustc_lint/unused.rs | 8 +++++++- src/test/ui/issue-43806.rs | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index e5b818cd5fb5..7773891b5d06 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -148,7 +148,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let ty_warned = match t.sty { ty::TyTuple(ref tys, _) if tys.is_empty() => return, ty::TyNever => return, - ty::TyAdt(def, _) => check_must_use(cx, def.did, s.span, ""), + ty::TyAdt(def, _) => { + if def.variants.is_empty() { + return; + } else { + check_must_use(cx, def.did, s.span, "") + } + }, _ => false, }; diff --git a/src/test/ui/issue-43806.rs b/src/test/ui/issue-43806.rs index df7f756127c4..7757a503c7e8 100644 --- a/src/test/ui/issue-43806.rs +++ b/src/test/ui/issue-43806.rs @@ -12,15 +12,22 @@ #![deny(unused_results)] +enum Void {} + fn foo() {} fn bar() -> ! { loop {} } +fn baz() -> Void { + loop {} +} + fn qux() { foo(); bar(); + baz(); } fn main() {} From fb45233ed19af29fb38dc4208b3ca2c03244b841 Mon Sep 17 00:00:00 2001 From: Thomas Levy Date: Fri, 11 Aug 2017 22:13:57 -0700 Subject: [PATCH 49/88] Handle DNS label compression in more places --- src/libstd/sys/redox/net/dns/mod.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/libstd/sys/redox/net/dns/mod.rs b/src/libstd/sys/redox/net/dns/mod.rs index 43c4fe7ac9d9..49cde89dc054 100644 --- a/src/libstd/sys/redox/net/dns/mod.rs +++ b/src/libstd/sys/redox/net/dns/mod.rs @@ -102,6 +102,7 @@ impl Dns { } pub fn parse(data: &[u8]) -> Result { + let name_ind = 0b11000000; let mut i = 0; macro_rules! pop_u8 { @@ -147,9 +148,15 @@ impl Dns { () => { { let mut name = String::new(); + let old_i = i; loop { let name_len = pop_u8!(); + if name_len & name_ind == name_ind { + i -= 1; + i = (pop_n16!() - ((name_ind as u16) << 8)) as usize; + continue; + } if name_len == 0 { break; } @@ -161,6 +168,10 @@ impl Dns { } } + if i <= old_i { + i = old_i + 2; + } + name } }; @@ -184,21 +195,8 @@ impl Dns { let mut answers = Vec::new(); for _answer_i in 0..answers_len { - let name_ind = 0b11000000; - let name_test = pop_u8!(); - i -= 1; - answers.push(DnsAnswer { - name: if name_test & name_ind == name_ind { - let name_off = pop_n16!() - ((name_ind as u16) << 8); - let old_i = i; - i = name_off as usize; - let name = pop_name!(); - i = old_i; - name - } else { - pop_name!() - }, + name: pop_name!(), a_type: pop_n16!(), a_class: pop_n16!(), ttl_a: pop_n16!(), From 1126a85e87629f7ec37fc6c4fde43419f4b9947f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Aug 2017 22:24:25 -0700 Subject: [PATCH 50/88] Move config.toml.example to the root dir It's way more discoverable here. --- CONTRIBUTING.md | 2 +- README.md | 2 +- src/bootstrap/config.toml.example => config.toml.example | 0 src/bootstrap/README.md | 2 +- src/bootstrap/config.rs | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename src/bootstrap/config.toml.example => config.toml.example (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04b6fea75a78..5b325110d380 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -99,7 +99,7 @@ Before you can start building the compiler you need to configure the build for your system. In most cases, that will just mean using the defaults provided for Rust. -To change configuration, you must copy the file `src/bootstrap/config.toml.example` +To change configuration, you must copy the file `config.toml.example` to `config.toml` in the directory from which you will be running the build, and change the settings provided. diff --git a/README.md b/README.md index a1f018610753..b6ff6df0aec9 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Read ["Installation"] from [The Book]. ``` > ***Note:*** Install locations can be adjusted by copying the config file - > from `./src/bootstrap/config.toml.example` to `./config.toml`, and + > from `./config.toml.example` to `./config.toml`, and > adjusting the `prefix` option under `[install]`. Various other options, such > as enabling debug information, are also supported, and are documented in > the config file. diff --git a/src/bootstrap/config.toml.example b/config.toml.example similarity index 100% rename from src/bootstrap/config.toml.example rename to config.toml.example diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 1ce99eb893ef..65c1088f5473 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -80,7 +80,7 @@ handled naturally. Next, rustbuild offers a TOML-based configuration system with a `config.toml` file in the same location as `config.mk`. An example of this configuration can -be found at `src/bootstrap/config.toml.example`, and the configuration file +be found at `config.toml.example`, and the configuration file can also be passed as `--config path/to/config.toml` if the build system is being invoked manually (via the python script). diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index ec57bb069e0a..c4d5d4315211 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -35,7 +35,7 @@ use cache::{INTERNER, Interned}; /// Note that this structure is not decoded directly into, but rather it is /// filled out from the decoded forms of the structs below. For documentation /// each field, see the corresponding fields in -/// `src/bootstrap/config.toml.example`. +/// `config.toml.example`. #[derive(Default)] pub struct Config { pub ccache: Option, From 8a4facc3c30d9dfbbfc1ddc6d413dfb0520699c6 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 8 Aug 2017 18:21:20 +0300 Subject: [PATCH 51/88] syntax: #[allow_internal_unsafe] bypasses the unsafe_code lint in macros. --- src/librustc/hir/lowering.rs | 1 + src/librustc_allocator/expand.rs | 1 + src/librustc_lint/builtin.rs | 25 +++++++++++------ src/librustc_plugin/registry.rs | 22 ++++++++++++--- src/librustc_resolve/macros.rs | 2 +- src/libsyntax/ext/base.rs | 16 +++++++---- src/libsyntax/ext/derive.rs | 1 + src/libsyntax/ext/expand.rs | 27 ++++++++++++++----- src/libsyntax/ext/tt/macro_rules.rs | 12 ++++++--- src/libsyntax/feature_gate.rs | 15 +++++++++++ src/libsyntax/std_inject.rs | 1 + src/libsyntax/test.rs | 1 + src/libsyntax_ext/lib.rs | 14 ++++++++-- src/libsyntax_ext/proc_macro_registrar.rs | 1 + src/libsyntax_pos/hygiene.rs | 3 +++ src/libsyntax_pos/lib.rs | 10 +++++++ ...gate-allow-internal-unsafe-nested-macro.rs | 27 +++++++++++++++++++ .../auxiliary/plugin_args.rs | 7 ++++- 18 files changed, 155 insertions(+), 31 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-allow-internal-unsafe-nested-macro.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 421a81c0d234..adf7d901be9c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -404,6 +404,7 @@ impl<'a> LoweringContext<'a> { format: codemap::CompilerDesugaring(Symbol::intern(reason)), span: Some(span), allow_internal_unstable: true, + allow_internal_unsafe: false, }, }); span.ctxt = SyntaxContext::empty().apply_mark(mark); diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 676c3c51ea2a..78b07a33389e 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -79,6 +79,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { format: MacroAttribute(Symbol::intern(name)), span: None, allow_internal_unstable: true, + allow_internal_unsafe: false, } }); let span = Span { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 88432e642903..7767cf434032 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -195,12 +195,23 @@ impl LintPass for UnsafeCode { } } +impl UnsafeCode { + fn report_unsafe(&self, cx: &LateContext, span: Span, desc: &'static str) { + // This comes from a macro that has #[allow_internal_unsafe]. + if span.allows_unsafe() { + return; + } + + cx.span_lint(UNSAFE_CODE, span, desc); + } +} + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) { - cx.span_lint(UNSAFE_CODE, blk.span, "usage of an `unsafe` block"); + self.report_unsafe(cx, blk.span, "usage of an `unsafe` block"); } } } @@ -208,11 +219,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemTrait(hir::Unsafety::Unsafe, ..) => { - cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait") + self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait") } hir::ItemImpl(hir::Unsafety::Unsafe, ..) => { - cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait") + self.report_unsafe(cx, it.span, "implementation of an `unsafe` trait") } _ => return, @@ -228,12 +239,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { _: ast::NodeId) { match fk { FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => { - cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function") + self.report_unsafe(cx, span, "declaration of an `unsafe` function") } FnKind::Method(_, sig, ..) => { if sig.unsafety == hir::Unsafety::Unsafe { - cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method") + self.report_unsafe(cx, span, "implementation of an `unsafe` method") } } @@ -244,9 +255,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) { if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node { if sig.unsafety == hir::Unsafety::Unsafe { - cx.span_lint(UNSAFE_CODE, - item.span, - "declaration of an `unsafe` method") + self.report_unsafe(cx, item.span, "declaration of an `unsafe` method") } } } diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 3027489d65be..aac21f2af0d9 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -102,9 +102,19 @@ impl<'a> Registry<'a> { panic!("user-defined macros may not be named `macro_rules`"); } self.syntax_exts.push((name, match extension { - NormalTT(ext, _, allow_internal_unstable) => { + NormalTT { + expander, + def_info: _, + allow_internal_unstable, + allow_internal_unsafe + } => { let nid = ast::CRATE_NODE_ID; - NormalTT(ext, Some((nid, self.krate_span)), allow_internal_unstable) + NormalTT { + expander, + def_info: Some((nid, self.krate_span)), + allow_internal_unstable, + allow_internal_unsafe + } } IdentTT(ext, _, allow_internal_unstable) => { IdentTT(ext, Some(self.krate_span), allow_internal_unstable) @@ -134,8 +144,12 @@ impl<'a> Registry<'a> { /// It builds for you a `NormalTT` that calls `expander`, /// and also takes care of interning the macro's name. pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) { - self.register_syntax_extension(Symbol::intern(name), - NormalTT(Box::new(expander), None, false)); + self.register_syntax_extension(Symbol::intern(name), NormalTT { + expander: Box::new(expander), + def_info: None, + allow_internal_unstable: false, + allow_internal_unsafe: false, + }); } /// Register a compiler lint pass. diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 98eaa056177e..7572c4aa6802 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -313,7 +313,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn check_unused_macros(&self) { for did in self.unused_macros.iter() { let id_span = match *self.macro_map[did] { - SyntaxExtension::NormalTT(_, isp, _) => isp, + SyntaxExtension::NormalTT { def_info, .. } => def_info, SyntaxExtension::DeclMacro(.., osp) => osp, _ => None, }; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 194d30e25d41..72b2552f64fc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -532,10 +532,16 @@ pub enum SyntaxExtension { /// A normal, function-like syntax extension. /// /// `bytes!` is a `NormalTT`. - /// - /// The `bool` dictates whether the contents of the macro can - /// directly use `#[unstable]` things (true == yes). - NormalTT(Box, Option<(ast::NodeId, Span)>, bool), + NormalTT { + expander: Box, + def_info: Option<(ast::NodeId, Span)>, + /// Whether the contents of the macro can + /// directly use `#[unstable]` things (true == yes). + allow_internal_unstable: bool, + /// Whether the contents of the macro can use `unsafe` + /// without triggering the `unsafe_code` lint. + allow_internal_unsafe: bool, + }, /// A function-like syntax extension that has an extra ident before /// the block. @@ -562,7 +568,7 @@ impl SyntaxExtension { pub fn kind(&self) -> MacroKind { match *self { SyntaxExtension::DeclMacro(..) | - SyntaxExtension::NormalTT(..) | + SyntaxExtension::NormalTT { .. } | SyntaxExtension::IdentTT(..) | SyntaxExtension::ProcMacro(..) => MacroKind::Bang, diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index e7c5d8278d97..38715f7275de 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -64,6 +64,7 @@ pub fn add_derived_markers(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path] format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), span: None, allow_internal_unstable: true, + allow_internal_unsafe: false, }, }); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4843a66a750f..9625602fa4a5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -411,6 +411,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), span: None, allow_internal_unstable: false, + allow_internal_unsafe: false, } }); @@ -458,7 +459,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let path = &mac.node.path; let ident = ident.unwrap_or_else(|| keywords::Invalid.ident()); - let validate_and_set_expn_info = |def_site_span, allow_internal_unstable| { + let validate_and_set_expn_info = |def_site_span, + allow_internal_unstable, + allow_internal_unsafe| { if ident.name != keywords::Invalid.name() { return Err(format!("macro {}! expects no ident argument, given '{}'", path, ident)); } @@ -467,7 +470,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), span: def_site_span, - allow_internal_unstable: allow_internal_unstable, + allow_internal_unstable, + allow_internal_unsafe, }, }); Ok(()) @@ -476,20 +480,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let opt_expanded = match *ext { DeclMacro(ref expand, def_span) => { if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s), - false) { + false, false) { self.cx.span_err(path.span, &msg); return kind.dummy(span); } kind.make_from(expand.expand(self.cx, span, mac.node.stream())) } - NormalTT(ref expandfun, def_info, allow_internal_unstable) => { + NormalTT { + ref expander, + def_info, + allow_internal_unstable, + allow_internal_unsafe + } => { if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s), - allow_internal_unstable) { + allow_internal_unstable, + allow_internal_unsafe) { self.cx.span_err(path.span, &msg); return kind.dummy(span); } - kind.make_from(expandfun.expand(self.cx, span, mac.node.stream())) + kind.make_from(expander.expand(self.cx, span, mac.node.stream())) } IdentTT(ref expander, tt_span, allow_internal_unstable) => { @@ -504,7 +514,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), span: tt_span, - allow_internal_unstable: allow_internal_unstable, + allow_internal_unstable, + allow_internal_unsafe: false, } }); @@ -540,6 +551,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { span: None, // FIXME probably want to follow macro_rules macros here. allow_internal_unstable: false, + allow_internal_unsafe: false, }, }); @@ -578,6 +590,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { format: MacroAttribute(pretty_name), span: None, allow_internal_unstable: false, + allow_internal_unsafe: false, } }; diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 80b6794d1e3c..7b3fe2bd993a 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -269,7 +269,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()]) } - let exp: Box<_> = Box::new(MacroRulesMacroExpander { + let expander: Box<_> = Box::new(MacroRulesMacroExpander { name: def.ident, lhses: lhses, rhses: rhses, @@ -278,9 +278,15 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) if body.legacy { let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable"); - NormalTT(exp, Some((def.id, def.span)), allow_internal_unstable) + let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe"); + NormalTT { + expander, + def_info: Some((def.id, def.span)), + allow_internal_unstable, + allow_internal_unsafe + } } else { - SyntaxExtension::DeclMacro(exp, Some((def.id, def.span))) + SyntaxExtension::DeclMacro(expander, Some((def.id, def.span))) } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index aeb574bc3af3..46ee126b9d90 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -194,6 +194,14 @@ declare_features! ( // rustc internal (active, allow_internal_unstable, "1.0.0", None), + // Allows the use of #[allow_internal_unsafe]. This is an + // attribute on macro_rules! and can't use the attribute handling + // below (it has to be checked before expansion possibly makes + // macros disappear). + // + // rustc internal + (active, allow_internal_unsafe, "1.0.0", None), + // #23121. Array patterns have some hazards yet. (active, slice_patterns, "1.0.0", Some(23121)), @@ -735,6 +743,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG EXPLAIN_ALLOW_INTERNAL_UNSTABLE, cfg_fn!(allow_internal_unstable))), + ("allow_internal_unsafe", Normal, Gated(Stability::Unstable, + "allow_internal_unsafe", + EXPLAIN_ALLOW_INTERNAL_UNSAFE, + cfg_fn!(allow_internal_unsafe))), + ("fundamental", Whitelisted, Gated(Stability::Unstable, "fundamental", "the `#[fundamental]` attribute \ @@ -1045,6 +1058,8 @@ pub const EXPLAIN_TRACE_MACROS: &'static str = "`trace_macros` is not stable enough for use and is subject to change"; pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str = "allow_internal_unstable side-steps feature gating and stability checks"; +pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &'static str = + "allow_internal_unsafe side-steps the unsafe_code lint"; pub const EXPLAIN_CUSTOM_DERIVE: &'static str = "`#[derive]` for custom traits is deprecated and will be removed in the future."; diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index d9ed96f293a8..430976e7d3ce 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -28,6 +28,7 @@ fn ignored_span(sp: Span) -> Span { format: MacroAttribute(Symbol::intern("std_inject")), span: None, allow_internal_unstable: true, + allow_internal_unsafe: false, } }); Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 887479a24724..c05e166e0133 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -291,6 +291,7 @@ fn generate_test_harness(sess: &ParseSess, format: MacroAttribute(Symbol::intern("test")), span: None, allow_internal_unstable: true, + allow_internal_unsafe: false, } }); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 5eab81dd28fc..439538a8b5ee 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -64,7 +64,12 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( register(Symbol::intern(stringify!($name)), - NormalTT(Box::new($f as MacroExpanderFn), None, false)); + NormalTT { + expander: Box::new($f as MacroExpanderFn), + def_info: None, + allow_internal_unstable: false, + allow_internal_unsafe: false, + }); )* } } @@ -112,7 +117,12 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, // format_args uses `unstable` things internally. register(Symbol::intern("format_args"), - NormalTT(Box::new(format::expand_format_args), None, true)); + NormalTT { + expander: Box::new(format::expand_format_args), + def_info: None, + allow_internal_unstable: true, + allow_internal_unsafe: false, + }); for (name, ext) in user_exts { register(name, ext); diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index ab6d73e5061a..700386f68fee 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -368,6 +368,7 @@ fn mk_registrar(cx: &mut ExtCtxt, format: MacroAttribute(Symbol::intern("proc_macro")), span: None, allow_internal_unstable: true, + allow_internal_unsafe: false, } }); let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP }; diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 804b91ab09e3..514cc26666e3 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -310,6 +310,9 @@ pub struct NameAndSpan { /// features internally without forcing the whole crate to opt-in /// to them. pub allow_internal_unstable: bool, + /// Whether the macro is allowed to use `unsafe` internally + /// even if the user crate has `#![forbid(unsafe_code)]`. + pub allow_internal_unsafe: 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. diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 7006f45455e3..e162bc26412f 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -153,6 +153,16 @@ impl Span { } } + /// Check if a span is "internal" to a macro in which `unsafe` + /// can be used without triggering the `unsafe_code` lint + // (that is, a macro marked with `#[allow_internal_unsafe]`). + pub fn allows_unsafe(&self) -> bool { + match self.ctxt.outer().expn_info() { + Some(info) => info.callee.allow_internal_unsafe, + None => false, + } + } + pub fn macro_backtrace(mut self) -> Vec { let mut prev_span = DUMMY_SP; let mut result = vec![]; diff --git a/src/test/compile-fail/feature-gate-allow-internal-unsafe-nested-macro.rs b/src/test/compile-fail/feature-gate-allow-internal-unsafe-nested-macro.rs new file mode 100644 index 000000000000..590dc619f2f1 --- /dev/null +++ b/src/test/compile-fail/feature-gate-allow-internal-unsafe-nested-macro.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. + +// gate-test-allow_internal_unsafe + +#![allow(unused_macros)] + +macro_rules! bar { + () => { + // more layers don't help: + #[allow_internal_unsafe] //~ ERROR allow_internal_unsafe side-steps + macro_rules! baz { + () => {} + } + } +} + +bar!(); + +fn main() {} diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs index 134e36c587be..8da2ae8b29ab 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs @@ -48,5 +48,10 @@ impl TTMacroExpander for Expander { pub fn plugin_registrar(reg: &mut Registry) { let args = reg.args().to_owned(); reg.register_syntax_extension(Symbol::intern("plugin_args"), - NormalTT(Box::new(Expander { args: args, }), None, false)); + NormalTT { + expander: Box::new(Expander { args: args, }), + def_info: None, + allow_internal_unstable: false, + allow_internal_unsafe: false, + }); } From 0cd358742dfcf3fa6b0d8a318cfb5cc748dc905d Mon Sep 17 00:00:00 2001 From: Alexey Tarasov Date: Sat, 12 Aug 2017 18:42:44 +1000 Subject: [PATCH 52/88] Fixes issue 39827: ICE in volatile_store intrinsic - adds handling of zero-sized types for volatile_store. - adds type size checks and warnigns for other volatile intrinsics. - adds a test to check warnings emitting. Cause of the issue While preparing for trans_intrinsic_call() invoke arguments are processed with trans_argument() method which excludes zero-sized types from argument list (to be more correct - all arguments for which ArgKind is Ignore are filtered out). As result volatile_store() intrinsic gets one argument instead of expected address and value. How it is fixed Modification of the trans_argument() method may cause side effects, therefore change was implemented in volatile_store() intrinsic building code itself. Now it checks function signature and if it was specialised with zero-sized type, then emits C_nil() instead of accessing non-existing second argument. Additionally warnings are added for all volatile operations which are specialised with zero-sized arguments. In fact, those operations are omitted in LLVM backend if no memory affected at all, e.g. number of elements is zero or type is zero-sized. This was not explicitly documented before and could lead to potential issues if developer expects volatile behaviour, but type has degraded to zero-sized. --- src/librustc_trans/intrinsic.rs | 52 +++++++++++++++++++++-- src/test/ui/issue-39827.rs | 37 +++++++++++++++++ src/test/ui/issue-39827.stderr | 73 +++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/issue-39827.rs create mode 100644 src/test/ui/issue-39827.stderr diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 9956c28e6412..5ebd9bed5c8c 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -83,6 +83,38 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { Some(ccx.get_intrinsic(&llvm_name)) } +fn warn_if_size_is_weird<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, + tp_ty: Ty<'tcx>, + count: ValueRef, + span: Span, + name: &str) { + let ccx = bcx.ccx; + let lltp_ty = type_of::type_of(ccx, tp_ty); + let ty_size = machine::llsize_of(ccx, lltp_ty); + let total = const_to_uint( bcx.mul(ty_size, count) ); + + if total > 0 { + return; + } + + let text = format!("suspicious monomorphization of `{}` intrinsic", name); + let note = match name + { + "volatile_load" | "volatile_store" => + format!("'{}' was specialized with zero-sized type '{}'", + name, tp_ty), + _ => format!("'{}' was specialized with type '{}', number of \ + elements is {}", + name, tp_ty, + const_to_uint(count)) + }; + + let sess = bcx.sess(); + sess.struct_span_warn(span, &text) + .note(¬e) + .emit(); +} + /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, /// add them to librustc_trans/trans/context.rs @@ -217,17 +249,24 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "volatile_copy_nonoverlapping_memory" => { - copy_intrinsic(bcx, false, true, substs.type_at(0), llargs[0], llargs[1], llargs[2]) + let tp_ty = substs.type_at(0); + warn_if_size_is_weird(bcx, tp_ty, llargs[2], span, name); + copy_intrinsic(bcx, false, true, tp_ty, llargs[0], llargs[1], llargs[2]) } "volatile_copy_memory" => { - copy_intrinsic(bcx, true, true, substs.type_at(0), llargs[0], llargs[1], llargs[2]) + let tp_ty = substs.type_at(0); + warn_if_size_is_weird(bcx, tp_ty, llargs[2], span, name); + copy_intrinsic(bcx, true, true, tp_ty, llargs[0], llargs[1], llargs[2]) } "volatile_set_memory" => { - memset_intrinsic(bcx, true, substs.type_at(0), llargs[0], llargs[1], llargs[2]) + let tp_ty = substs.type_at(0); + warn_if_size_is_weird(bcx, tp_ty, llargs[2], span, name); + memset_intrinsic(bcx, true, tp_ty, llargs[0], llargs[1], llargs[2]) } "volatile_load" => { let tp_ty = substs.type_at(0); let mut ptr = llargs[0]; + warn_if_size_is_weird(bcx, tp_ty, C_uint(ccx,1usize), span, name); if let Some(ty) = fn_ty.ret.cast { ptr = bcx.pointercast(ptr, ty.ptr_to()); } @@ -239,6 +278,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, }, "volatile_store" => { let tp_ty = substs.type_at(0); + warn_if_size_is_weird(bcx, tp_ty, C_uint(ccx,1usize), span, name); if type_is_fat_ptr(bcx.ccx, tp_ty) { bcx.volatile_store(llargs[1], get_dataptr(bcx, llargs[0])); bcx.volatile_store(llargs[2], get_meta(bcx, llargs[0])); @@ -246,7 +286,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let val = if fn_ty.args[1].is_indirect() { bcx.load(llargs[1], None) } else { - from_immediate(bcx, llargs[1]) + if !type_is_zero_size(ccx, tp_ty) { + from_immediate(bcx, llargs[1]) + } else { + C_nil(ccx) + } }; let ptr = bcx.pointercast(llargs[0], val_ty(val).ptr_to()); let store = bcx.volatile_store(val, ptr); diff --git a/src/test/ui/issue-39827.rs b/src/test/ui/issue-39827.rs new file mode 100644 index 000000000000..86a3f67b40a8 --- /dev/null +++ b/src/test/ui/issue-39827.rs @@ -0,0 +1,37 @@ +// 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(core_intrinsics)] + +use std::intrinsics::{ volatile_copy_memory, volatile_store, volatile_load, + volatile_copy_nonoverlapping_memory, + volatile_set_memory }; + +fn main () { + let mut dst_pair = (1, 2); + let src_pair = (3, 4); + let mut dst_empty = (); + let src_empty = (); + + const COUNT_0: usize = 0; + const COUNT_100: usize = 100; + + unsafe { + volatile_copy_memory(&mut dst_pair, &dst_pair, COUNT_0); + volatile_copy_nonoverlapping_memory(&mut dst_pair, &src_pair, 0); + volatile_copy_memory(&mut dst_empty, &dst_empty, 100); + volatile_copy_nonoverlapping_memory(&mut dst_empty, &src_empty, + COUNT_100); + volatile_set_memory(&mut dst_empty, 0, COUNT_100); + volatile_set_memory(&mut dst_pair, 0, COUNT_0); + volatile_store(&mut dst_empty, ()); + volatile_store(&mut dst_empty, src_empty); + volatile_load(&src_empty); + } +} diff --git a/src/test/ui/issue-39827.stderr b/src/test/ui/issue-39827.stderr new file mode 100644 index 000000000000..228309872f93 --- /dev/null +++ b/src/test/ui/issue-39827.stderr @@ -0,0 +1,73 @@ +warning: suspicious monomorphization of `volatile_copy_memory` intrinsic + --> $DIR/issue-39827.rs:26:9 + | +26 | volatile_copy_memory(&mut dst_pair, &dst_pair, COUNT_0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_copy_memory' was specialized with type '(i32, i32)', number of elements is 0 + +warning: suspicious monomorphization of `volatile_copy_nonoverlapping_memory` intrinsic + --> $DIR/issue-39827.rs:27:9 + | +27 | volatile_copy_nonoverlapping_memory(&mut dst_pair, &src_pair, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_copy_nonoverlapping_memory' was specialized with type '(i32, i32)', number of elements is 0 + +warning: suspicious monomorphization of `volatile_copy_memory` intrinsic + --> $DIR/issue-39827.rs:28:9 + | +28 | volatile_copy_memory(&mut dst_empty, &dst_empty, 100); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_copy_memory' was specialized with type '()', number of elements is 100 + +warning: suspicious monomorphization of `volatile_copy_nonoverlapping_memory` intrinsic + --> $DIR/issue-39827.rs:29:9 + | +29 | / volatile_copy_nonoverlapping_memory(&mut dst_empty, &src_empty, +30 | | COUNT_100); + | |______________________________________________________^ + | + = note: 'volatile_copy_nonoverlapping_memory' was specialized with type '()', number of elements is 100 + +warning: suspicious monomorphization of `volatile_set_memory` intrinsic + --> $DIR/issue-39827.rs:31:9 + | +31 | volatile_set_memory(&mut dst_empty, 0, COUNT_100); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_set_memory' was specialized with type '()', number of elements is 100 + +warning: suspicious monomorphization of `volatile_set_memory` intrinsic + --> $DIR/issue-39827.rs:32:9 + | +32 | volatile_set_memory(&mut dst_pair, 0, COUNT_0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_set_memory' was specialized with type '(i32, i32)', number of elements is 0 + +warning: suspicious monomorphization of `volatile_store` intrinsic + --> $DIR/issue-39827.rs:33:9 + | +33 | volatile_store(&mut dst_empty, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_store' was specialized with zero-sized type '()' + +warning: suspicious monomorphization of `volatile_store` intrinsic + --> $DIR/issue-39827.rs:34:9 + | +34 | volatile_store(&mut dst_empty, src_empty); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_store' was specialized with zero-sized type '()' + +warning: suspicious monomorphization of `volatile_load` intrinsic + --> $DIR/issue-39827.rs:35:9 + | +35 | volatile_load(&src_empty); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: 'volatile_load' was specialized with zero-sized type '()' + From 6a607faba43a818e2a9d63f87316256a963277bb Mon Sep 17 00:00:00 2001 From: Alexey Tarasov Date: Sat, 12 Aug 2017 18:43:59 +1000 Subject: [PATCH 53/88] Follow up commit for the issue 39827 - updates documentation on volatile memory intrinsics, now the case of zero-sized types is mentioned explicitly. Volatile memory operations which doesn't affect memory at all are omitted in LLVM backend, e.g. if number of elements is zero or type used in generic specialisation is zero-sized, then LLVM intrinsic or related code is not generated. This was not explicitly documented before in Rust documentation and potentially could cause issues. --- src/libcore/intrinsics.rs | 9 ++++++--- src/libcore/ptr.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fdca8d00d7a7..ad776c8605ac 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1044,20 +1044,23 @@ extern "rust-intrinsic" { /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` /// - /// The volatile parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero. pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` /// - /// The volatile parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero.. pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a /// size of `count` * `size_of::()` and an alignment of /// `min_align_of::()`. /// - /// The volatile parameter is set to `true`, so it will not be optimized out. + /// The volatile parameter is set to `true`, so it will not be optimized out + /// unless size is equal to zero. pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); /// Perform a volatile load from the `src` pointer. diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 60cf1a205306..b37e3a5236d1 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -384,6 +384,12 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// over time. That being said, the semantics will almost always end up pretty /// similar to [C11's definition of volatile][c11]. /// +/// Compiler shouldn't change relative order or number of volatile memory +/// operations, however this implies that memory operation actually takes place. +/// If a zero-sized type is used in a specialisation of `read_volatile`, value +/// is known at any time and can not be modified outside of program control. +/// In this case such operation may be omitted by compiler backend. +/// /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf /// /// # Safety @@ -427,6 +433,12 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// over time. That being said, the semantics will almost always end up pretty /// similar to [C11's definition of volatile][c11]. /// +/// Compiler shouldn't change relative order or number of volatile memory +/// operations, however this implies that memory operation actually takes place. +/// If a zero-sized type is used in a specialisation of `write_volatile`, value +/// is known at any time and can not be modified outside of program control. +/// In this case such operation may be omitted by compiler backend. +/// /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf /// /// # Safety From 03584a2d8c76036bf380cdbb759f3e57033f5301 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 12 Aug 2017 10:48:57 +0200 Subject: [PATCH 54/88] Less cfg's --- src/librustc_driver/driver.rs | 7 ------- src/librustc_driver/lib.rs | 29 +++++++++++++++++++++-------- src/librustc_driver/test.rs | 1 - src/librustc_trans_utils/link.rs | 31 ++++--------------------------- 4 files changed, 25 insertions(+), 43 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c6d2d75e9377..c3de39fc9753 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -73,10 +73,7 @@ pub fn compile_input(sess: &Session, output: &Option, addl_plugins: Option>, control: &CompileController) -> CompileResult { - #[cfg(feature="llvm")] use rustc_trans::back::write::OngoingCrateTranslation; - #[cfg(not(feature="llvm"))] - type OngoingCrateTranslation = (); macro_rules! controller_entry_point { ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ @@ -393,7 +390,6 @@ pub struct CompileState<'a, 'tcx: 'a> { pub resolutions: Option<&'a Resolutions>, pub analysis: Option<&'a ty::CrateAnalysis>, pub tcx: Option>, - #[cfg(feature="llvm")] pub trans: Option<&'a trans::CrateTranslation>, } @@ -420,7 +416,6 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { resolutions: None, analysis: None, tcx: None, - #[cfg(feature="llvm")] trans: None, } } @@ -942,7 +937,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, mir::provide(&mut local_providers); reachable::provide(&mut local_providers); rustc_privacy::provide(&mut local_providers); - #[cfg(feature="llvm")] trans::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); @@ -955,7 +949,6 @@ 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); - #[cfg(feature="llvm")] trans::provide(&mut extern_providers); ty::provide_extern(&mut extern_providers); traits::provide_extern(&mut extern_providers); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 91ba7ed1958e..ea7af4e1ae13 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -71,8 +71,6 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; -#[cfg(feature="llvm")] -use rustc_trans::back::write::{RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::CompileIncomplete; @@ -207,6 +205,25 @@ impl MetadataLoaderTrait for NoLLvmMetadataLoader { } } +#[cfg(feature="llvm")] +mod rustc_trans { + use rustc::ty::maps::Providers; + pub fn init(_sess: &Session) {} + pub fn enable_llvm_debug() {} + pub fn provide(_providers: &mut Providers) {} + pub struct CrateTranslation(()); + pub mod back { + pub mod write { + pub struct OngoingCrateTranslation(()); + } + } + mod diagnostics { + register_long_diagnostics! {} + } + + pub use diagnostics::DIAGNOSTICS; +} + // Parse args and run the compiler. This is the primary entry point for rustc. // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. @@ -232,7 +249,6 @@ pub fn run_compiler<'a>(args: &[String], let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); if sopts.debugging_opts.debug_llvm { - #[cfg(feature="llvm")] rustc_trans::enable_llvm_debug(); } @@ -262,7 +278,6 @@ pub fn run_compiler<'a>(args: &[String], let mut sess = session::build_session_with_codemap( sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest, ); - #[cfg(feature="llvm")] rustc_trans::init(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); @@ -544,7 +559,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { None, descriptions.clone(), cstore.clone()); - #[cfg(feature="llvm")] rustc_trans::init(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg.clone()); @@ -803,7 +817,7 @@ impl RustcDefaultCalls { PrintRequest::RelocationModels => { println!("Available relocation models:"); #[cfg(feature="llvm")] - for &(name, _) in RELOC_MODEL_ARGS.iter() { + for &(name, _) in rustc_trans::back::write::RELOC_MODEL_ARGS.iter() { println!(" {}", name); } println!(""); @@ -811,7 +825,7 @@ impl RustcDefaultCalls { PrintRequest::CodeModels => { println!("Available code models:"); #[cfg(feature="llvm")] - for &(name, _) in CODE_GEN_MODEL_ARGS.iter(){ + for &(name, _) in rustc_trans::back::write::CODE_GEN_MODEL_ARGS.iter(){ println!(" {}", name); } println!(""); @@ -1285,7 +1299,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry { all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); - #[cfg(feature="llvm")] all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 7f65a8b97cd6..f3f934ccde50 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -114,7 +114,6 @@ fn test_env(source_string: &str, diagnostic_handler, Rc::new(CodeMap::new(FilePathMapping::empty())), cstore.clone()); - #[cfg(feature="llvm")] rustc_trans::init(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let input = config::Input::Str { diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_trans_utils/link.rs index 29bb062d34cf..264158f0de9e 100644 --- a/src/librustc_trans_utils/link.rs +++ b/src/librustc_trans_utils/link.rs @@ -8,34 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::session::config::{self, /*NoDebugInfo,*/ OutputFilenames, Input, OutputType}; -/*use rustc::session::filesearch; -use rustc::session::search_paths::PathKind; -*/use rustc::session::Session; -use rustc::middle::cstore;/*::{self, LinkMeta, NativeLibrary, LibSource, LinkagePreference, - NativeLibraryKind};*/ -/*use rustc::middle::dependency_format::Linkage; -use rustc::util::common::time; -use rustc::util::fs::fix_windows_verbatim_for_gcc; -use rustc::dep_graph::{DepKind, DepNode}; -use rustc::hir::def_id::CrateNum; -use rustc::hir::svh::Svh; -use rustc_back::tempdir::TempDir; -use rustc_back::{PanicStrategy, RelroLevel}; -use rustc_incremental::IncrementalHashesMap;*/ - -/*use std::ascii; -use std::char; -use std::env; -use std::ffi::OsString; -use std::fs; -use std::io::{self, Read, Write}; -use std::mem; -*/use std::path::PathBuf;/*{Path, PathBuf}; -use std::process::Command; -use std::str;*/ +use rustc::session::config::{self, OutputFilenames, Input, OutputType}; +use rustc::session::Session; +use rustc::middle::cstore; +use std::path::PathBuf; use syntax::ast; -//use syntax::attr; use syntax_pos::Span; pub fn find_crate_name(sess: Option<&Session>, From 64503b6ee7e6b861f5c1dc8e27a97cf231b59685 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sat, 12 Aug 2017 18:00:57 +0900 Subject: [PATCH 55/88] Include 'let' keyword to the span for ast::Local --- 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 7bf4c6799b3c..15f05df58b50 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3587,7 +3587,7 @@ impl<'a> Parser<'a> { /// Parse a local variable declaration fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { - let lo = self.span; + let lo = self.prev_span; let pat = self.parse_pat()?; let ty = if self.eat(&token::Colon) { From 92892d3beb2ab858c6e73df0cf732d2c6f83a4aa Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 8 Aug 2017 18:22:51 +0300 Subject: [PATCH 56/88] Check #[thread_local] statics correctly in the compiler. --- src/librustc/middle/mem_categorization.rs | 8 ++- src/librustc_mir/diagnostics.rs | 1 + src/librustc_mir/transform/qualify_consts.rs | 20 +++++- src/libstd/lib.rs | 1 + src/libstd/thread/local.rs | 62 +++++++++---------- src/test/compile-fail/issue-17954.rs | 25 ++++++++ src/test/compile-fail/issue-43733-2.rs | 39 ++++++++++++ src/test/compile-fail/issue-43733.rs | 41 ++++++++++++ src/test/compile-fail/thread-local-in-ctfe.rs | 38 ++++++++++++ .../auxiliary/thread-local-extern-static.rs | 11 ++-- src/test/run-pass/issue-30756.rs | 2 +- .../run-pass/thread-local-extern-static.rs | 18 ++++-- 12 files changed, 223 insertions(+), 43 deletions(-) create mode 100644 src/test/compile-fail/issue-17954.rs create mode 100644 src/test/compile-fail/issue-43733-2.rs create mode 100644 src/test/compile-fail/issue-43733.rs create mode 100644 src/test/compile-fail/thread-local-in-ctfe.rs diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b4993aafc4c9..5533ab518954 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -643,7 +643,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Ok(self.cat_rvalue_node(id, span, expr_ty)) } - Def::Static(_, mutbl) => { + Def::Static(def_id, mutbl) => { + // `#[thread_local]` statics may not outlive the current function. + for attr in &self.tcx.get_attrs(def_id)[..] { + if attr.check_name("thread_local") { + return Ok(self.cat_rvalue_node(id, span, expr_ty)); + } + } Ok(Rc::new(cmt_ { id:id, span:span, diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 6530b356e33f..34170a6609c4 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -442,4 +442,5 @@ static A : &'static u32 = &S.a; // ok! register_diagnostics! { E0526, // shuffle indices are not constant + E0625, // thread-local statics cannot be accessed at compile-time } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8321d9b99ae8..2ecffdf9fdf7 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -484,8 +484,20 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } }, - Lvalue::Static(_) => { + Lvalue::Static(ref global) => { self.add(Qualif::STATIC); + + if self.mode != Mode::Fn { + for attr in &self.tcx.get_attrs(global.def_id)[..] { + if attr.check_name("thread_local") { + span_err!(self.tcx.sess, self.span, E0625, + "thread-local statics cannot be \ + accessed at compile-time"); + return; + } + } + } + if self.mode == Mode::Const || self.mode == Mode::ConstFn { span_err!(self.tcx.sess, self.span, E0013, "{}s cannot refer to statics, use \ @@ -998,6 +1010,12 @@ impl MirPass for QualifyAndPromoteConstants { // Statics must be Sync. if mode == Mode::Static { + // `#[thread_local]` statics don't have to be `Sync`. + for attr in &tcx.get_attrs(def_id)[..] { + if attr.check_name("thread_local") { + return; + } + } let ty = mir.return_ty; tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f7748aa3f041..f95fc8a1b1a4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -243,6 +243,7 @@ #![feature(allocator_api)] #![feature(alloc_system)] #![feature(allocator_internals)] +#![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(box_syntax)] diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 0172f89e05b6..48f611a34394 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -91,13 +91,13 @@ pub struct LocalKey { // // Note that the thunk is itself unsafe because the returned lifetime of the // slot where data lives, `'static`, is not actually valid. The lifetime - // here is actually `'thread`! + // here is actually slightly shorter than the currently running thread! // // Although this is an extra layer of indirection, it should in theory be // trivially devirtualizable by LLVM because the value of `inner` never // changes and the constant should be readonly within a crate. This mainly // only runs into problems when TLS statics are exported across crates. - inner: fn() -> Option<&'static UnsafeCell>>, + inner: unsafe fn() -> Option<&'static UnsafeCell>>, // initialization routine to invoke to create a value init: fn() -> T, @@ -157,12 +157,13 @@ macro_rules! thread_local { issue = "0")] #[macro_export] #[allow_internal_unstable] +#[cfg_attr(not(stage0), allow_internal_unsafe)] macro_rules! __thread_local_inner { ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => { $(#[$attr])* $vis static $name: $crate::thread::LocalKey<$t> = { fn __init() -> $t { $init } - fn __getit() -> $crate::option::Option< + unsafe fn __getit() -> $crate::option::Option< &'static $crate::cell::UnsafeCell< $crate::option::Option<$t>>> { @@ -178,7 +179,9 @@ macro_rules! __thread_local_inner { __KEY.get() } - $crate::thread::LocalKey::new(__getit, __init) + unsafe { + $crate::thread::LocalKey::new(__getit, __init) + } }; } } @@ -252,8 +255,8 @@ impl LocalKey { #[unstable(feature = "thread_local_internals", reason = "recently added to create a key", issue = "0")] - pub const fn new(inner: fn() -> Option<&'static UnsafeCell>>, - init: fn() -> T) -> LocalKey { + pub const unsafe fn new(inner: unsafe fn() -> Option<&'static UnsafeCell>>, + init: fn() -> T) -> LocalKey { LocalKey { inner: inner, init: init, @@ -391,6 +394,7 @@ pub mod fast { } } + #[cfg(stage0)] unsafe impl ::marker::Sync for Key { } impl Key { @@ -402,14 +406,12 @@ pub mod fast { } } - pub fn get(&'static self) -> Option<&'static UnsafeCell>> { - unsafe { - if mem::needs_drop::() && self.dtor_running.get() { - return None - } - self.register_dtor(); + pub unsafe fn get(&self) -> Option<&'static UnsafeCell>> { + if mem::needs_drop::() && self.dtor_running.get() { + return None } - Some(&self.inner) + self.register_dtor(); + Some(&*(&self.inner as *const _)) } unsafe fn register_dtor(&self) { @@ -478,26 +480,24 @@ pub mod os { } } - pub fn get(&'static self) -> Option<&'static UnsafeCell>> { - unsafe { - let ptr = self.os.get() as *mut Value; - if !ptr.is_null() { - if ptr as usize == 1 { - return None - } - return Some(&(*ptr).value); + pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell>> { + let ptr = self.os.get() as *mut Value; + if !ptr.is_null() { + if ptr as usize == 1 { + return None } - - // If the lookup returned null, we haven't initialized our own - // local copy, so do that now. - let ptr: Box> = box Value { - key: self, - value: UnsafeCell::new(None), - }; - let ptr = Box::into_raw(ptr); - self.os.set(ptr as *mut u8); - Some(&(*ptr).value) + return Some(&(*ptr).value); } + + // If the lookup returned null, we haven't initialized our own + // local copy, so do that now. + let ptr: Box> = box Value { + key: self, + value: UnsafeCell::new(None), + }; + let ptr = Box::into_raw(ptr); + self.os.set(ptr as *mut u8); + Some(&(*ptr).value) } } diff --git a/src/test/compile-fail/issue-17954.rs b/src/test/compile-fail/issue-17954.rs new file mode 100644 index 000000000000..4befe3ebc865 --- /dev/null +++ b/src/test/compile-fail/issue-17954.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. + +#![feature(thread_local)] + +#[thread_local] +static FOO: u8 = 3; + +fn main() { + let a = &FOO; + //~^ ERROR borrowed value does not live long enough + //~| does not live long enough + //~| NOTE borrowed value must be valid for the static lifetime + + std::thread::spawn(move || { + println!("{}", a); + }); +} //~ temporary value only lives until here diff --git a/src/test/compile-fail/issue-43733-2.rs b/src/test/compile-fail/issue-43733-2.rs new file mode 100644 index 000000000000..3dff34c2ebb1 --- /dev/null +++ b/src/test/compile-fail/issue-43733-2.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. + +#![feature(const_fn, drop_types_in_const)] +#![feature(cfg_target_thread_local, thread_local_internals)] + +// On platforms *without* `#[thread_local]`, use +// a custom non-`Sync` type to fake the same error. +#[cfg(not(target_thread_local))] +struct Key { + _data: std::cell::UnsafeCell>, + _flag: std::cell::Cell, +} + +#[cfg(not(target_thread_local))] +impl Key { + const fn new() -> Self { + Key { + _data: std::cell::UnsafeCell::new(None), + _flag: std::cell::Cell::new(false), + } + } +} + +#[cfg(target_thread_local)] +use std::thread::__FastLocalKeyInner as Key; + +static __KEY: Key<()> = Key::new(); +//~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied +//~| ERROR `std::cell::Cell: std::marker::Sync` is not satisfied + +fn main() {} diff --git a/src/test/compile-fail/issue-43733.rs b/src/test/compile-fail/issue-43733.rs new file mode 100644 index 000000000000..a4aad21a9f83 --- /dev/null +++ b/src/test/compile-fail/issue-43733.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. + +#![feature(const_fn, drop_types_in_const)] +#![feature(cfg_target_thread_local, thread_local_internals)] + +type Foo = std::cell::RefCell; + +#[cfg(target_thread_local)] +static __KEY: std::thread::__FastLocalKeyInner = + std::thread::__FastLocalKeyInner::new(); + +#[cfg(not(target_thread_local))] +static __KEY: std::thread::__OsLocalKeyInner = + std::thread::__OsLocalKeyInner::new(); + +fn __getit() -> std::option::Option< + &'static std::cell::UnsafeCell< + std::option::Option>> +{ + __KEY.get() //~ ERROR invocation of unsafe method requires unsafe +} + +static FOO: std::thread::LocalKey = + std::thread::LocalKey::new(__getit, Default::default); +//~^ ERROR call to unsafe function requires unsafe + +fn main() { + FOO.with(|foo| println!("{}", foo.borrow())); + std::thread::spawn(|| { + FOO.with(|foo| *foo.borrow_mut() += "foo"); + }).join().unwrap(); + FOO.with(|foo| println!("{}", foo.borrow())); +} diff --git a/src/test/compile-fail/thread-local-in-ctfe.rs b/src/test/compile-fail/thread-local-in-ctfe.rs new file mode 100644 index 000000000000..720e15991c05 --- /dev/null +++ b/src/test/compile-fail/thread-local-in-ctfe.rs @@ -0,0 +1,38 @@ +// 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(const_fn, thread_local)] + +#[thread_local] +static A: u32 = 1; + +static B: u32 = A; +//~^ ERROR thread-local statics cannot be accessed at compile-time +//~| ERROR cannot refer to other statics by value +//~| WARN non-constant path in constant expression + +static C: &u32 = &A; +//~^ ERROR thread-local statics cannot be accessed at compile-time + +const D: u32 = A; +//~^ ERROR thread-local statics cannot be accessed at compile-time +//~| ERROR cannot refer to statics by value +//~| WARN non-constant path in constant expression + +const E: &u32 = &A; +//~^ ERROR thread-local statics cannot be accessed at compile-time + +const fn f() -> u32 { + A + //~^ ERROR thread-local statics cannot be accessed at compile-time + //~| ERROR cannot refer to statics by value +} + +fn main() {} diff --git a/src/test/run-pass/auxiliary/thread-local-extern-static.rs b/src/test/run-pass/auxiliary/thread-local-extern-static.rs index d1971a5e1aea..e9457886be80 100644 --- a/src/test/run-pass/auxiliary/thread-local-extern-static.rs +++ b/src/test/run-pass/auxiliary/thread-local-extern-static.rs @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(thread_local)] -#![feature(cfg_target_thread_local)] +#![feature(cfg_target_thread_local, const_fn, thread_local)] #![crate_type = "lib"] +#[cfg(target_thread_local)] +use std::cell::Cell; + #[no_mangle] -#[cfg_attr(target_thread_local, thread_local)] -pub static FOO: u32 = 3; +#[cfg(target_thread_local)] +#[thread_local] +pub static FOO: Cell = Cell::new(3); diff --git a/src/test/run-pass/issue-30756.rs b/src/test/run-pass/issue-30756.rs index d21b42f8c876..621607e5f6fa 100644 --- a/src/test/run-pass/issue-30756.rs +++ b/src/test/run-pass/issue-30756.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(unsafe_code)] +#![forbid(unsafe_code)] thread_local!(static FOO: u8 = 1); diff --git a/src/test/run-pass/thread-local-extern-static.rs b/src/test/run-pass/thread-local-extern-static.rs index 87188db9dc0e..09c8b64776c7 100644 --- a/src/test/run-pass/thread-local-extern-static.rs +++ b/src/test/run-pass/thread-local-extern-static.rs @@ -11,18 +11,26 @@ // ignore-windows // aux-build:thread-local-extern-static.rs -#![feature(thread_local)] -#![feature(cfg_target_thread_local)] +#![feature(cfg_target_thread_local, thread_local)] +#[cfg(target_thread_local)] extern crate thread_local_extern_static; +#[cfg(target_thread_local)] +use std::cell::Cell; + +#[cfg(target_thread_local)] extern { - #[cfg_attr(target_thread_local, thread_local)] - static FOO: u32; + #[thread_local] + static FOO: Cell; } +#[cfg(target_thread_local)] fn main() { unsafe { - assert_eq!(FOO, 3); + assert_eq!(FOO.get(), 3); } } + +#[cfg(not(target_thread_local))] +fn main() {} From a746129bdb50186994c6f62769ff043bb58f6fd7 Mon Sep 17 00:00:00 2001 From: Tej Chajed Date: Sat, 12 Aug 2017 12:28:29 +0100 Subject: [PATCH 57/88] Update GitHub pull request documentation link --- CONTRIBUTING.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04b6fea75a78..a8ab9ff48b48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -237,10 +237,13 @@ Some common invocations of `x.py` are: ## Pull Requests Pull requests are the primary mechanism we use to change Rust. GitHub itself -has some [great documentation][pull-requests] on using the Pull Request -feature. We use the 'fork and pull' model described there. +has some [great documentation][pull-requests] on using the Pull Request feature. +We use the "fork and pull" model [described here][development-models], where +contributors push changes to their personal fork and create pull requests to +bring those changes into the source repository. -[pull-requests]: https://help.github.com/articles/using-pull-requests/ +[pull-requests]: https://help.github.com/articles/about-pull-requests/ +[development-models]: https://help.github.com/articles/about-collaborative-development-models/ Please make pull requests against the `master` branch. From 36ba8ee4444301c3d0194a0f17268910d4ec0492 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 12 Aug 2017 19:15:01 +0800 Subject: [PATCH 58/88] Fix `-Z hir-stats` always panics (fix #43232). --- src/librustc_passes/hir_stats.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 29fac5463e55..c6bc045f0de3 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -125,6 +125,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { self.visit_impl_item(nested_impl_item) } + fn visit_nested_body(&mut self, body_id: hir::BodyId) { + let nested_body = self.krate.unwrap().body(body_id); + self.visit_body(nested_body) + } + fn visit_item(&mut self, i: &'v hir::Item) { self.record("Item", Id::Node(i.id), i); hir_visit::walk_item(self, i) From 3ab86fbab281ca059731c31fa2aee5d9afc7e6dc Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Fri, 11 Aug 2017 20:34:14 +0200 Subject: [PATCH 59/88] Fix some typos --- src/bootstrap/builder.rs | 4 +-- src/bootstrap/doc.rs | 2 +- src/liballoc/allocator.rs | 6 ++--- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 2 +- src/libcore/ops/place.rs | 2 +- src/libgraphviz/lib.rs | 2 +- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 2 +- src/librustc/infer/at.rs | 2 +- src/librustc/infer/higher_ranked/mod.rs | 2 +- src/librustc/infer/lattice.rs | 2 +- src/librustc/infer/region_inference/mod.rs | 2 +- src/librustc/lint/context.rs | 2 +- src/librustc/mir/mod.rs | 2 +- src/librustc/session/mod.rs | 4 +-- src/librustc/traits/error_reporting.rs | 4 +-- src/librustc/traits/project.rs | 2 +- .../traits/specialize/specialization_graph.rs | 4 +-- .../ty/inhabitedness/def_id_forest.rs | 4 +-- src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/maps.rs | 2 +- src/librustc/util/common.rs | 2 +- src/librustc_borrowck/borrowck/check_loans.rs | 2 +- src/librustc_const_eval/eval.rs | 2 +- src/librustc_driver/driver.rs | 2 +- src/librustc_mir/build/scope.rs | 2 +- src/librustc_mir/dataflow/mod.rs | 6 ++--- src/librustc_mir/transform/erase_regions.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_save_analysis/json_dumper.rs | 2 +- src/librustc_save_analysis/sig.rs | 4 +-- src/librustc_trans/base.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/mir/mod.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 10 ++++---- src/librustc_typeck/check/wfcheck.rs | 2 +- src/libstd/fs.rs | 2 +- src/libstd/net/tcp.rs | 2 +- src/libstd/net/udp.rs | 2 +- src/libstd/panic.rs | 2 +- src/libstd/panicking.rs | 25 ++++++++++--------- src/libstd/primitive_docs.rs | 2 +- src/libstd/sys/redox/ext/fs.rs | 2 +- src/libstd/sys/redox/ext/process.rs | 2 +- src/libstd/sys/unix/ext/fs.rs | 4 +-- src/libstd/sys/unix/ext/net.rs | 2 +- src/libstd/sys/unix/ext/process.rs | 2 +- src/libstd/sys/windows/ext/fs.rs | 2 +- src/libsyntax/ast.rs | 6 ++--- src/libsyntax/codemap.rs | 4 +-- 53 files changed, 83 insertions(+), 82 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d7f795e40553..f49e0223fcb5 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -333,7 +333,7 @@ impl<'a> Builder<'a> { StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths); } - /// Obtain a compiler at a given stage and for a given host. Explictly does + /// Obtain a compiler at a given stage and for a given host. Explicitly does /// not take `Compiler` since all `Compiler` instances are meant to be /// obtained through this function, since it ensures that they are valid /// (i.e., built and assembled). @@ -501,7 +501,7 @@ impl<'a> Builder<'a> { // crates). Let's say, for example that rustc itself depends on the // bitflags crate. If an external crate then depends on the // bitflags crate as well, we need to make sure they don't - // conflict, even if they pick the same verison of bitflags. We'll + // conflict, even if they pick the same version of bitflags. We'll // want to make sure that e.g. a plugin and rustc each get their // own copy of bitflags. diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 1ee578bb62b1..8d5d9f09ba95 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -306,7 +306,7 @@ impl Step for Standalone { /// /// This will list all of `src/doc` looking for markdown files and appropriately /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and - /// `STAMP` alongw ith providing the various header/footer HTML we've cutomized. + /// `STAMP` along with providing the various header/footer HTML we've customized. /// /// In the end, this is just a glorified wrapper around rustdoc! fn run(self, builder: &Builder) { diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index 3ea7d349c9cd..7b6700bfd492 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -240,7 +240,7 @@ impl Layout { /// /// Returns `Some((k, offset))`, where `k` is layout of the concatenated /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded witnin the concatenated record + /// start of the `next` embedded within the concatenated record /// (assuming that the record itself starts at offset 0). /// /// On arithmetic overflow, returns `None`. @@ -297,7 +297,7 @@ impl Layout { /// /// Returns `(k, offset)`, where `k` is layout of the concatenated /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded witnin the concatenated record + /// start of the `next` embedded within the concatenated record /// (assuming that the record itself starts at offset 0). /// /// (The `offset` is always the same as `self.size()`; we use this @@ -544,7 +544,7 @@ pub unsafe trait Alloc { /// practice this means implementors should eschew allocating, /// especially from `self` (directly or indirectly). /// - /// Implementions of the allocation and reallocation methods + /// Implementations of the allocation and reallocation methods /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from /// panicking (or aborting) in the event of memory exhaustion; /// instead they should return an appropriate error from the diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 322b137e99f0..3ed5d2df1aba 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -653,7 +653,7 @@ impl String { /// * `capacity` needs to be the correct value. /// /// Violating these may cause problems like corrupting the allocator's - /// internal datastructures. + /// internal data structures. /// /// The ownership of `ptr` is effectively transferred to the /// `String` which may then deallocate, reallocate or change the diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 160c0ba2ab0e..5f68e59289d7 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -374,7 +374,7 @@ impl Vec { /// * `capacity` needs to be the capacity that the pointer was allocated with. /// /// Violating these may cause problems like corrupting the allocator's - /// internal datastructures. For example it is **not** safe + /// internal data structures. For example it is **not** safe /// to build a `Vec` from a pointer to a C `char` array and a `size_t`. /// /// The ownership of `ptr` is effectively transferred to the diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs index 19da887cbbfb..9fb171e7b924 100644 --- a/src/libcore/ops/place.rs +++ b/src/libcore/ops/place.rs @@ -66,7 +66,7 @@ pub trait Place { /// or `Copy`, since the `make_place` method takes `self` by value. #[unstable(feature = "placement_new_protocol", issue = "27779")] pub trait Placer { - /// `Place` is the intermedate agent guarding the + /// `Place` is the intermediate agent guarding the /// uninitialized state for `Data`. type Place: InPlace; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 7412a01e11e1..c01938f5e117 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -548,7 +548,7 @@ impl<'a> LabelText<'a> { } /// Renders text as string suitable for a label in a .dot file. - /// This includes quotes or suitable delimeters. + /// This includes quotes or suitable delimiters. pub fn to_dot_string(&self) -> String { match self { &LabelStr(ref s) => format!("\"{}\"", s.escape_default()), diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 57198d8ca0b7..2a0c76d99bfb 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -87,7 +87,7 @@ pub enum NestedVisitorMap<'this, 'tcx: 'this> { /// Do not visit nested item-like things, but visit nested things /// that are inside of an item-like. /// - /// **This is the most common choice.** A very commmon pattern is + /// **This is the most common choice.** A very common pattern is /// to use `visit_all_item_likes()` as an outer loop, /// and to have the visitor that visits the contents of each item /// using this setting. diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 45b1d6c18410..919b205fdf95 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -248,7 +248,7 @@ pub struct Map<'hir> { pub forest: &'hir Forest, /// Same as the dep_graph in forest, just available with one fewer - /// deref. This is a gratuitious micro-optimization. + /// deref. This is a gratuitous micro-optimization. pub dep_graph: DepGraph, /// NodeIds are sequential integers from 0, so we can be diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index efe0504aa18c..7f408900dece 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -496,7 +496,7 @@ impl Crate { &self.impl_items[&id] } - /// Visits all items in the crate in some determinstic (but + /// Visits all items in the crate in some deterministic (but /// unspecified) order. If you just need to process every item, /// but don't care about nesting, this method is the best choice. /// diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs index 756e0b5f9fb6..3fd7ee276729 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -169,7 +169,7 @@ impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> { } /// Sets the "trace" values that will be used for - /// error-repporting, but doesn't actually perform any operation + /// error-reporting, but doesn't actually perform any operation /// yet (this is useful when you want to set the trace using /// distinct values from those you wish to operate upon). pub fn trace(self, diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 9ecc8b0e66b9..0d02420457e6 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -589,7 +589,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { (result, map) } - /// Searches the region constriants created since `snapshot` was started + /// Searches the region constraints created since `snapshot` was started /// and checks to determine whether any of the skolemized regions created /// in `skol_map` would "escape" -- meaning that they are related to /// other regions in some way. If so, the higher-ranked subtyping doesn't diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index d4d090f0153d..d5c1163cfc1b 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -46,7 +46,7 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> // 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 + // relates `v` to `a` first, which may help us to avoid unnecessary // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 57f2f748b246..5588b6d9add1 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -128,7 +128,7 @@ pub enum UndoLogEntry<'tcx> { /// We added the given `given` AddGiven(Region<'tcx>, ty::RegionVid), - /// We added a GLB/LUB "combinaton variable" + /// We added a GLB/LUB "combination variable" AddCombination(CombineMapType, TwoRegions<'tcx>), /// During skolemization, we sometimes purge entries from the undo diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6ee06dc0a816..17b5f6ad9543 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -69,7 +69,7 @@ pub struct LintStore { /// is true if the lint group was added by a plugin. lint_groups: FxHashMap<&'static str, (Vec, bool)>, - /// Extra info for future incompatibility lints, descibing the + /// Extra info for future incompatibility lints, describing the /// issue or RFC that caused the incompatibility. future_incompatible: FxHashMap, } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 1e8dda0addf4..74ce68b351df 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -695,7 +695,7 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { impl<'tcx> TerminatorKind<'tcx> { /// Write the "head" part of the terminator; that is, its name and the data it uses to pick the - /// successor basic block, if any. The only information not inlcuded is the list of possible + /// successor basic block, if any. The only information not included is the list of possible /// successors, which may be rendered differently between the text and the graphviz format. pub fn fmt_head(&self, fmt: &mut W) -> fmt::Result { use self::TerminatorKind::*; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index be39f95b9889..3aea0722d0e2 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -112,7 +112,7 @@ pub struct Session { /// Map from imported macro spans (which consist of /// the localized span for the macro body) to the - /// macro name and defintion span in the source crate. + /// macro name and definition span in the source crate. pub imported_macro_spans: RefCell>, incr_comp_session: RefCell, @@ -828,7 +828,7 @@ pub fn compile_result_from_err_count(err_count: usize) -> CompileResult { #[inline(never)] pub fn bug_fmt(file: &'static str, line: u32, args: fmt::Arguments) -> ! { // this wrapper mostly exists so I don't have to write a fully - // qualified path of None:: inside the bug!() macro defintion + // qualified path of None:: inside the bug!() macro definition opt_span_bug_fmt(file, line, None::, args); } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f0fc6998c9e5..f23071de6474 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -111,8 +111,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - // returns if `cond` not occuring implies that `error` does not occur - i.e. that - // `error` occuring implies that `cond` occurs. + // returns if `cond` not occurring implies that `error` does not occur - i.e. that + // `error` occurring implies that `cond` occurs. fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 7cce9c398bb4..e70258007e46 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1364,7 +1364,7 @@ impl<'tcx> ProjectionCache<'tcx> { } /// Try to start normalize `key`; returns an error if - /// normalization already occured (this error corresponds to a + /// normalization already occurred (this error corresponds to a /// cache hit, so it's actually a good thing). fn try_start(&mut self, key: ty::ProjectionTy<'tcx>) -> Result<(), ProjectionCacheEntry<'tcx>> { diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 611137562a90..8b31cb599e45 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> Children { } /// Attempt to insert an impl into this set of children, while comparing for - /// specialiation relationships. + /// specialization relationships. fn insert(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, impl_def_id: DefId, @@ -206,7 +206,7 @@ impl<'a, 'gcx, 'tcx> Graph { // if the reference itself contains an earlier error (e.g., due to a // resolution failure), then we just insert the impl at the top level of - // the graph and claim that there's no overlap (in order to supress + // the graph and claim that there's no overlap (in order to suppress // bogus errors). if trait_ref.references_error() { debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \ diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs index 231600f95ac6..896682e2370e 100644 --- a/src/librustc/ty/inhabitedness/def_id_forest.rs +++ b/src/librustc/ty/inhabitedness/def_id_forest.rs @@ -24,7 +24,7 @@ use ty::{DefId, DefIdTree}; #[derive(Clone)] pub struct DefIdForest { /// The minimal set of DefIds required to represent the whole set. - /// If A and B are DefIds in the DefIdForest, and A is a desecendant + /// If A and B are DefIds in the DefIdForest, and A is a descendant /// of B, then only B will be in root_ids. /// We use a SmallVec here because (for its use for cacheing inhabitedness) /// its rare that this will contain even two ids. @@ -61,7 +61,7 @@ impl<'a, 'gcx, 'tcx> DefIdForest { self.root_ids.is_empty() } - /// Test whether the forest conains a given DefId. + /// Test whether the forest contains a given DefId. pub fn contains(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, id: DefId) -> bool diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 73b577e2e876..76a20ed8f302 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -125,7 +125,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// If possible, this pushes a global path resolving to `external_def_id` that is visible /// from at least one local module and returns true. If the crate defining `external_def_id` is - /// declared with an `extern crate`, the path is guarenteed to use the `extern crate`. + /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`. pub fn try_push_visible_item_path(self, buffer: &mut T, external_def_id: DefId) -> bool where T: ItemPathBuffer { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index b871b36c9485..a640da31eec2 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -587,7 +587,7 @@ macro_rules! define_maps { } // FIXME(eddyb) Get more valid Span's on queries. - // def_span guard is necesary to prevent a recursive loop, + // def_span guard is necessary to prevent a recursive loop, // default_span calls def_span query internally. if span == DUMMY_SP && stringify!($name) != "def_span" { span = key.default_span(tcx) diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 244b7f359688..885be8464eb3 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -224,7 +224,7 @@ pub trait MemoizationMap { type Key: Clone; type Value: Clone; - /// If `key` is present in the map, return the valuee, + /// If `key` is present in the map, return the value, /// otherwise invoke `op` and store the value in the map. /// /// NB: if the receiver is a `DepTrackingMap`, special care is diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index e70b7f89a676..c34bf4c3d284 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -472,7 +472,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { if new_loan.span == old_loan.span { // Both borrows are happening in the same place - // Meaning the borrow is occuring in a loop + // Meaning the borrow is occurring in a loop err.span_label( new_loan.span, format!("mutable borrow starts here in previous \ diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index eb45fd9c0e0a..a1581b160412 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -106,7 +106,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { } /// Evaluate a constant expression in a context where the expression isn't - /// guaranteed to be evaluatable. + /// guaranteed to be evaluable. pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> { if self.tables.tainted_by_errors { signal!(e, TypeckError); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c6d2d75e9377..83bed33b1118 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -974,7 +974,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir); passes.push_pass(MIR_CONST, mir::transform::rustc_peek::SanityCheck); - // We compute "constant qualifications" betwen MIR_CONST and MIR_VALIDATED. + // We compute "constant qualifications" between MIR_CONST and MIR_VALIDATED. // What we need to run borrowck etc. passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a4a89a7f8185..ce64f88d18e1 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -113,7 +113,7 @@ pub struct Scope<'tcx> { /// for unwinding, for several reasons: /// * clang doesn't emit llvm.lifetime.end for C++ unwinding /// * LLVM's memory dependency analysis can't handle it atm - /// * pollutting the cleanup MIR with StorageDead creates + /// * polluting the cleanup MIR with StorageDead creates /// landing pads even though there's no actual destructors /// * freeing up stack space has no effect during unwinding needs_cleanup: bool, diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index d7ad9f9c09ae..7c0137b18c02 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -333,11 +333,11 @@ pub trait BitDenotation { /// basic block) according to the effects of evaluating statement. /// /// This is used, in particular, for building up the - /// "transfer-function" represnting the overall-effect of the + /// "transfer-function" representing the overall-effect of the /// block, represented via GEN and KILL sets. /// /// The statement is identified as `bb_data[idx_stmt]`, where - /// `bb_data` is the sequence of statements identifed by `bb` in + /// `bb_data` is the sequence of statements identified by `bb` in /// the MIR. fn statement_effect(&self, sets: &mut BlockSets, @@ -349,7 +349,7 @@ pub trait BitDenotation { /// the terminator. /// /// This is used, in particular, for building up the - /// "transfer-function" represnting the overall-effect of the + /// "transfer-function" representing the overall-effect of the /// block, represented via GEN and KILL sets. /// /// The effects applied here cannot depend on which branch the diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index baf0522896c9..89de847231c8 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! This pass erases all early-bound regions from the types occuring in the MIR. +//! This pass erases all early-bound regions from the types occurring in the MIR. //! We want to do this once just before trans, so trans does not have to take //! care erasing regions all over the place. //! NOTE: We do NOT erase regions of statements that are relevant for diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b4f9ba4e8f78..da170e7fe22c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1621,7 +1621,7 @@ impl<'a> Resolver<'a> { return Some(module.parent.unwrap()); } - let mut module_expansion = module.expansion.modern(); // for backward compatability + let mut module_expansion = module.expansion.modern(); // for backward compatibility while let Some(parent) = module.parent { let parent_expansion = parent.expansion.modern(); if module_expansion.is_descendant_of(parent_expansion) && diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 30a698e63514..8dd191f4375e 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -109,7 +109,7 @@ impl<'b, O: DumpOutput + 'b> JsonDumper { } if data.kind == DefKind::Mod && data.span.file_name.to_str().unwrap() != data.value { // If the module is an out-of-line defintion, then we'll make the - // defintion the first character in the module's file and turn the + // definition the first character in the module's file and turn the // the declaration into a reference to it. let rf = Ref { kind: RefKind::Mod, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 3557b4752e7e..6ef499694aa4 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -387,7 +387,7 @@ impl Sig for ast::Item { sig.text.push('('); for i in &decl.inputs { - // FIXME shoudl descend into patterns to add defs. + // FIXME should descend into patterns to add defs. sig.text.push_str(&pprust::pat_to_string(&i.pat)); sig.text.push_str(": "); let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?; @@ -922,7 +922,7 @@ fn make_method_signature(id: NodeId, sig.text.push('('); for i in &m.decl.inputs { - // FIXME shoudl descend into patterns to add defs. + // FIXME should descend into patterns to add defs. sig.text.push_str(&pprust::pat_to_string(&i.pat)); sig.text.push_str(": "); let nested = i.ty.make(sig.text.len(), Some(i.id), scx)?; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 63df33913ca7..b4a2891f94c2 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -488,7 +488,7 @@ impl Lifetime { // on), and `ptr` is nonzero-sized, then extracts the size of `ptr` // and the intrinsic for `lt` and passes them to `emit`, which is in // charge of generating code to call the passed intrinsic on whatever - // block of generated code is targetted for the intrinsic. + // block of generated code is targeted for the intrinsic. // // If LLVM lifetime intrinsic support is disabled (i.e. optimizations // off) or `ptr` is zero-sized, then no-op (does not call `emit`). diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6e36073107b5..8cb2c2809f4f 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -36,7 +36,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, qualified: bool, output: &mut String) { - // When targeting MSVC, emit C++ style type names for compatability with + // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) let cpp_like_names = cx.sess().target.target.options.is_like_msvc; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index a7f12babb10f..d0f7f27d5a81 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { (scope, source_info.span) } else { // Walk up the macro expansion chain until we reach a non-expanded span. - // We also stop at the function body level because no line stepping can occurr + // We also stop at the function body level because no line stepping can occur // at the level above that. let mut span = source_info.span; while span.ctxt != NO_EXPANSION && span.ctxt != self.mir.span.ctxt { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 1ccb1e64a98e..a1c987f22e05 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -219,7 +219,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// `lookup_method_in_trait` is used for overloaded operators. /// It does a very narrow slice of what the normal probe/confirm path does. /// In particular, it doesn't really do any probing: it simply constructs - /// an obligation for aparticular trait with the given self-type and checks + /// an obligation for a particular trait with the given self-type and checks /// whether that trait is implemented. /// /// FIXME(#18741) -- It seems likely that we can consolidate some of this diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 697d9de931a8..17611af5ac41 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -529,7 +529,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// `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 + /// tail expression) from a `Always` setting, we will issue a /// warning. This corresponds to something like `{return; /// foo();}` or `{return; 22}`, where we would warn on the /// `foo()` or `22`. @@ -538,7 +538,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// (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 + /// diverging flag is true, which means that a diverging value was /// wrapped (e.g., `let x: ! = foo(return)`). /// /// To repeat the last point: an expression represents dead-code @@ -1895,7 +1895,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| { if let ty::TyAnon(def_id, substs) = ty.sty { // Use the same type variable if the exact same TyAnon appears more - // than once in the return type (e.g. if it's pased to a type alias). + // than once in the return type (e.g. if it's passed to a type alias). let id = self.tcx.hir.as_local_node_id(def_id).unwrap(); if let Some(ty_var) = self.anon_types.borrow().get(&id) { return ty_var; @@ -4244,7 +4244,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a - /// suggetion can be made, `None` otherwise. + /// suggestion can be made, `None` otherwise. pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> { // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or // `while` before reaching it, as block tail returns are not available in them. @@ -4312,7 +4312,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// ``` /// /// This routine checks if the return expression in a block would make sense on its own as a - /// statement and the return type has been left as defaultor has been specified as `()`. If so, + /// statement and the return type has been left as default or has been specified as `()`. If so, /// it suggests adding a semicolon. fn suggest_missing_semicolon(&self, err: &mut DiagnosticBuilder<'tcx>, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index cf5882bb9bdb..31e14a6b630d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -255,7 +255,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // We want to ensure: // // 1) that there are no items contained within - // the trait defintion + // the trait definition // // 2) that the definition doesn't violate the no-super trait rule // for auto traits. diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 062186ef7086..1e692abaff2f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -657,7 +657,7 @@ impl OpenOptions { /// This function will return an error under a number of different /// circumstances. Some of these error conditions are listed here, together /// with their [`ErrorKind`]. The mapping to [`ErrorKind`]s is not part of - /// the compatiblity contract of the function, especially the `Other` kind + /// the compatibility contract of the function, especially the `Other` kind /// might change to more specific kinds in the future. /// /// * [`NotFound`]: The specified file does not exist and neither `create` diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index fdeca8bc5cac..20fd50ff6309 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -351,7 +351,7 @@ impl TcpStream { self.0.write_timeout() } - /// Receives data on the socket from the remote adress to which it is + /// Receives data on the socket from the remote address to which it is /// connected, without removing that data from the queue. On success, /// returns the number of bytes peeked. /// diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 80151dc2b445..9aff98978853 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -622,7 +622,7 @@ impl UdpSocket { self.0.recv(buf) } - /// Receives data on the socket from the remote adress to which it is + /// Receives data on the socket from the remote address to which it is /// connected, without removing that data from the queue. On success, /// returns the number of bytes peeked. /// diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 10b3209257ef..97b09b7e2ad9 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -37,7 +37,7 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location}; /// In Rust a function can "return" early if it either panics or calls a /// function which transitively panics. This sort of control flow is not always /// anticipated, and has the possibility of causing subtle bugs through a -/// combination of two criticial components: +/// combination of two critical components: /// /// 1. A data structure is in a temporarily invalid state when the thread /// panics. diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 04e1a579decd..99567bd08bbf 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -171,7 +171,7 @@ pub fn take_hook() -> Box { /// use std::panic; /// /// panic::set_hook(Box::new(|panic_info| { -/// println!("panic occured: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); +/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); /// })); /// /// panic!("Normal panic"); @@ -196,7 +196,7 @@ impl<'a> PanicInfo<'a> { /// use std::panic; /// /// panic::set_hook(Box::new(|panic_info| { - /// println!("panic occured: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); + /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); /// })); /// /// panic!("Normal panic"); @@ -221,9 +221,10 @@ impl<'a> PanicInfo<'a> { /// /// panic::set_hook(Box::new(|panic_info| { /// if let Some(location) = panic_info.location() { - /// println!("panic occured in file '{}' at line {}", location.file(), location.line()); + /// println!("panic occurred in file '{}' at line {}", location.file(), + /// location.line()); /// } else { - /// println!("panic occured but can't get location information..."); + /// println!("panic occurred but can't get location information..."); /// } /// })); /// @@ -249,9 +250,9 @@ impl<'a> PanicInfo<'a> { /// /// panic::set_hook(Box::new(|panic_info| { /// if let Some(location) = panic_info.location() { -/// println!("panic occured in file '{}' at line {}", location.file(), location.line()); +/// println!("panic occurred in file '{}' at line {}", location.file(), location.line()); /// } else { -/// println!("panic occured but can't get location information..."); +/// println!("panic occurred but can't get location information..."); /// } /// })); /// @@ -275,9 +276,9 @@ impl<'a> Location<'a> { /// /// panic::set_hook(Box::new(|panic_info| { /// if let Some(location) = panic_info.location() { - /// println!("panic occured in file '{}'", location.file()); + /// println!("panic occurred in file '{}'", location.file()); /// } else { - /// println!("panic occured but can't get location information..."); + /// println!("panic occurred but can't get location information..."); /// } /// })); /// @@ -297,9 +298,9 @@ impl<'a> Location<'a> { /// /// panic::set_hook(Box::new(|panic_info| { /// if let Some(location) = panic_info.location() { - /// println!("panic occured at line {}", location.line()); + /// println!("panic occurred at line {}", location.line()); /// } else { - /// println!("panic occured but can't get location information..."); + /// println!("panic occurred but can't get location information..."); /// } /// })); /// @@ -320,9 +321,9 @@ impl<'a> Location<'a> { /// /// panic::set_hook(Box::new(|panic_info| { /// if let Some(location) = panic_info.location() { - /// println!("panic occured at column {}", location.column()); + /// println!("panic occurred at column {}", location.column()); /// } else { - /// println!("panic occured but can't get location information..."); + /// println!("panic occurred but can't get location information..."); /// } /// })); /// diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 7be319d1954e..c52899db4373 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -906,7 +906,7 @@ mod prim_ref { } /// These markers can be combined, so `unsafe extern "stdcall" fn()` is a valid type. /// /// Like references in rust, function pointers are assumed to not be null, so if you want to pass a -/// function pointer over FFI and be able to accomodate null pointers, make your type +/// function pointer over FFI and be able to accommodate null pointers, make your type /// `Option` with your required signature. /// /// Function pointers implement the following traits: diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 9a0d1e06da32..5d4edc2cf92c 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -121,7 +121,7 @@ pub trait OpenOptionsExt { #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&mut self, mode: u32) -> &mut Self; - /// Pass custom flags to the `flags` agument of `open`. + /// Pass custom flags to the `flags` argument of `open`. /// /// The bits that define the access mode are masked out with `O_ACCMODE`, to /// ensure they do not interfere with the access mode set by Rusts options. diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index c59524974bf2..e68e180acf1c 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -47,7 +47,7 @@ pub trait CommandExt { /// # Notes /// /// This closure will be run in the context of the child process after a - /// `fork`. This primarily means that any modificatons made to memory on + /// `fork`. This primarily means that any modifications made to memory on /// behalf of this closure will **not** be visible to the parent process. /// This is often a very constrained environment where normal operations /// like `malloc` or acquiring a mutex are not guaranteed to work (due to diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 26710bf61d51..a94585723a1e 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -46,7 +46,7 @@ pub trait FileExt { /// /// The current file cursor is not affected by this function. /// - /// When writing beyond the end of the file, the file is appropiately + /// When writing beyond the end of the file, the file is appropriately /// extended and the intermediate bytes are initialized with the value 0. /// /// Note that similar to `File::write`, it is not an error to return a @@ -168,7 +168,7 @@ pub trait OpenOptionsExt { #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&mut self, mode: u32) -> &mut Self; - /// Pass custom flags to the `flags` agument of `open`. + /// Pass custom flags to the `flags` argument of `open`. /// /// The bits that define the access mode are masked out with `O_ACCMODE`, to /// ensure they do not interfere with the access mode set by Rusts options. diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 7701ae25b418..d9ab07fe5097 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -327,7 +327,7 @@ impl UnixStream { /// /// The returned `UnixStream` is a reference to the same stream that this /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propogated to the other + /// data, and options set on one stream will be propagated to the other /// stream. /// /// # Examples diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 2961c4ec5824..cde21b089a20 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -47,7 +47,7 @@ pub trait CommandExt { /// # Notes /// /// This closure will be run in the context of the child process after a - /// `fork`. This primarily means that any modificatons made to memory on + /// `fork`. This primarily means that any modifications made to memory on /// behalf of this closure will **not** be visible to the parent process. /// This is often a very constrained environment where normal operations /// like `malloc` or acquiring a mutex are not guaranteed to work (due to diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index a1c63e335884..d58a3505154d 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -66,7 +66,7 @@ pub trait FileExt { /// from the current cursor. The current cursor **is** affected by this /// function, it is set to the end of the write. /// - /// When writing beyond the end of the file, the file is appropiately + /// When writing beyond the end of the file, the file is appropriately /// extended and the intermediate bytes are left uninitialized. /// /// Note that similar to `File::write`, it is not an error to return a diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 857d9a753cc4..38ef79822c7b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -563,8 +563,8 @@ pub enum PatKind { TupleStruct(Path, Vec>, Option), /// A possibly qualified path pattern. - /// Unquailfied path patterns `A::B::C` can legally refer to variants, structs, constants - /// or associated constants. Quailfied path patterns `::B::C`/`::B::C` can + /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants + /// or associated constants. Qualified path patterns `::B::C`/`::B::C` can /// only legally refer to associated constants. Path(Option, Path), @@ -1838,7 +1838,7 @@ pub struct Item { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ItemKind { - /// An`extern crate` item, with optional original crate name. + /// An `extern crate` item, with optional original crate name. /// /// E.g. `extern crate foo` or `extern crate foo_bar as foo` ExternCrate(Option), diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index bfdcae7641dd..6c48b4cadd84 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -761,7 +761,7 @@ mod tests { } /// Given a string like " ~~~~~~~~~~~~ ", produces a span - /// coverting that range. The idea is that the string has the same + /// converting that range. The idea is that the string has the same /// length as the input, and we uncover the byte positions. Note /// that this can span lines and so on. fn span_from_selection(input: &str, selection: &str) -> Span { @@ -771,7 +771,7 @@ mod tests { 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 + /// Test span_to_snippet and span_to_lines for a span converting 3 /// lines in the middle of a file. #[test] fn span_to_snippet_and_lines_spanning_multiple_lines() { From f0fb7ab0e7a25a516d32f01bf9d7e0e30e054ec3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Aug 2017 13:46:12 +0200 Subject: [PATCH 60/88] Add missing link in fmt::format function --- src/liballoc/fmt.rs | 42 +++++++++++++++-------------- src/librustc_typeck/check/demand.rs | 4 +-- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index 5fc583d9e017..480fb4b9eaa2 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -149,7 +149,7 @@ //! //! Additionally, the return value of this function is [`fmt::Result`] which is a //! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations -//! should ensure that they propagate errors from the [`Formatter`] (e.g., when +//! should ensure that they propagate errors from the [`Formatter`][`Formatter`] (e.g., when //! calling [`write!`]) however, they should never return errors spuriously. That //! is, a formatting implementation must and may only return an error if the //! passed-in [`Formatter`] returns an error. This is because, contrary to what @@ -209,7 +209,7 @@ //! //! These two formatting traits have distinct purposes: //! -//! - [`fmt::Display`][`Display] implementations assert that the type can be faithfully +//! - [`fmt::Display`][`Display`] implementations assert that the type can be faithfully //! represented as a UTF-8 string at all times. It is **not** expected that //! all types implement the `Display` trait. //! - [`fmt::Debug`][`Debug`] implementations should be implemented for **all** public types. @@ -357,7 +357,7 @@ //! * `-` - Currently not used //! * `#` - This flag is indicates that the "alternate" form of printing should //! be used. The alternate forms are: -//! * `#?` - pretty-print the `Debug` formatting +//! * `#?` - pretty-print the [`Debug`] formatting //! * `#x` - precedes the argument with a `0x` //! * `#X` - precedes the argument with a `0x` //! * `#b` - precedes the argument with a `0b` @@ -475,25 +475,25 @@ //! them with the same character. For example, the `{` character is escaped with //! `{{` and the `}` character is escaped with `}}`. //! -//! [`format!`]: ../macro.format.html -//! [`usize`]: ../primitive.usize.html -//! [`isize`]: ../primitive.isize.html -//! [`i8`]: ../primitive.i8.html +//! [`format!`]: ../../macro.format.html +//! [`usize`]: ../../std/primitive.usize.html +//! [`isize`]: ../../std/primitive.isize.html +//! [`i8`]: ../../std/primitive.i8.html //! [`Display`]: trait.Display.html //! [`Binary`]: trait.Binary.html //! [`fmt::Result`]: type.Result.html -//! [`Result`]: ../result/enum.Result.html +//! [`Result`]: ../../std/result/enum.Result.html //! [`std::fmt::Error`]: struct.Error.html //! [`Formatter`]: struct.Formatter.html -//! [`write!`]: ../macro.write.html +//! [`write!`]: ../../std/macro.write.html //! [`Debug`]: trait.Debug.html -//! [`format!`]: ../macro.format.html -//! [`writeln!`]: ../macro.writeln.html -//! [`write_fmt`]: ../io/trait.Write.html#method.write_fmt -//! [`std::io::Write`]: ../io/trait.Write.html -//! [`println!`]: ../macro.println.html -//! [`write!`]: ../macro.write.html -//! [`format_args!`]: ../macro.format_args.html +//! [`format!`]: ../../std/macro.format.html +//! [`writeln!`]: ../../std/macro.writeln.html +//! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt +//! [`std::io::Write`]: ../../std/io/trait.Write.html +//! [`println!`]: ../../std/macro.println.html +//! [`write!`]: ../../std/macro.write.html +//! [`format_args!`]: ../../std/macro.format_args.html //! [`fmt::Arguments`]: struct.Arguments.html //! [`write`]: fn.write.html //! [`format`]: fn.format.html @@ -521,10 +521,10 @@ pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; use string; -/// The `format` function takes an `Arguments` struct and returns the resulting +/// The `format` function takes an [`Arguments`] struct and returns the resulting /// formatted string. /// -/// The `Arguments` instance can be created with the `format_args!` macro. +/// The [`Arguments`] instance can be created with the [`format_args!`] macro. /// /// # Examples /// @@ -537,7 +537,7 @@ use string; /// assert_eq!(s, "Hello, world!"); /// ``` /// -/// Please note that using [`format!`][format!] might be preferrable. +/// Please note that using [`format!`] might be preferrable. /// Example: /// /// ``` @@ -545,7 +545,9 @@ use string; /// assert_eq!(s, "Hello, world!"); /// ``` /// -/// [format!]: ../macro.format.html +/// [`Arguments`]: struct.Arguments.html +/// [`format_args!`]: ../../std/macro.format_args.html +/// [`format!`]: ../../std/macro.format.html #[stable(feature = "rust1", since = "1.0.0")] pub fn format(args: Arguments) -> string::String { let capacity = args.estimated_capacity(); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 7bb8a251354e..fc241c023cda 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); None - }, + } Err(e) => { Some(self.report_mismatched_types(cause, expected, actual, e)) } @@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Checks that the type of `expr` can be coerced to `expected`. // - // NB: This code relies on `self.diverges` to be accurate. In + // 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_diag(&self, From 6bdba82ba18fe69ac448f81b10bbbc7d0c10bce1 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Tue, 8 Aug 2017 14:34:37 +0200 Subject: [PATCH 61/88] std::ops docs: incorporated changes suggested in review * fixed link typos and copy-paster errors * rewrote Fn* explanations * `RHS = Self` -> `RHS` is `Self` (added that to all applicable places as well) * fixed up some links * s/MutDeref/DerefMut * removed remaining superfluous `fn main()`s * fixed some minor phrasings and factual errors and inaccuracies std::ops docs: Fix phrasing and factual errors/inaccuracies --- src/libcore/ops/arith.rs | 14 +++--- src/libcore/ops/bit.rs | 6 +++ src/libcore/ops/deref.rs | 2 +- src/libcore/ops/function.rs | 93 ++++++++++++++++++++++++------------- src/libcore/ops/index.rs | 4 +- src/libcore/ops/range.rs | 21 +++------ 6 files changed, 82 insertions(+), 58 deletions(-) diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 97fd8651b047..62007caedd3f 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -10,8 +10,8 @@ /// The addition operator `+`. /// -/// Note that `RHS = Self` by default, but this is not mandatory. For example, -/// [`std::time::SystemTime`] implements `Add`, which permits +/// Note that `RHS` is `Self` by default, but this is not mandatory. For +/// example, [`std::time::SystemTime`] implements `Add`, which permits /// operations of the form `SystemTime = SystemTime + Duration`. /// /// [`std::time::SystemTime`]: ../../std/time/struct.SystemTime.html @@ -105,8 +105,8 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The subtraction operator `-`. /// -/// Note that `RHS = Self` by default, but this is not mandatory. For example, -/// [std::time::SystemTime] implements `Sub`, which permits +/// Note that `RHS` is `Self` by default, but this is not mandatory. For +/// example, [`std::time::SystemTime`] implements `Sub`, which permits /// operations of the form `SystemTime = SystemTime - Duration`. /// /// [`std::time::SystemTime`]: ../../std/time/struct.SystemTime.html @@ -200,7 +200,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The multiplication operator `*`. /// -/// Note that `RHS = Self` by default, but this is not mandatory. +/// Note that `RHS` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -317,7 +317,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// The division operator `/`. /// -/// Note that `RHS = Self` by default, but this is not mandatory. +/// Note that `RHS` is `Self` by default, but this is not mandatory. /// /// # Examples /// @@ -455,6 +455,8 @@ div_impl_float! { f32 f64 } /// The remainder operator `%`. /// +/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// /// # Examples /// /// This example implements `Rem` on a `SplitSlice` object. After `Rem` is diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index e6fadf616b02..0bc5e554cb34 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -68,6 +68,8 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// The bitwise AND operator `&`. /// +/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// /// # Examples /// /// An implementation of `BitAnd` for a wrapper around `bool`. @@ -147,6 +149,8 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// The bitwise OR operator `|`. /// +/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// /// # Examples /// /// An implementation of `BitOr` for a wrapper around `bool`. @@ -226,6 +230,8 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// The bitwise XOR operator `^`. /// +/// Note that `RHS` is `Self` by default, but this is not mandatory. +/// /// # Examples /// /// An implementation of `BitXor` that lifts `^` to a wrapper around `bool`. diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index ac5ff1556f4d..a2e7c44cb249 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -111,7 +111,7 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// /// # More on `Deref` coercion /// -/// If `T` implements `MutDeref`, and `x` is a value of type `T`, +/// If `T` implements `DerefMut`, and `x` is a value of type `T`, /// then: /// * In mutable contexts, `*x` on non-pointer types is equivalent to /// `*Deref::deref(&x)`. diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index 5a61e9b68b86..2cc4e72817ff 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -8,27 +8,39 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// A version of the call operator that takes an immutable receiver. +/// The version of the call operator that takes an immutable receiver. /// -/// Closures only taking immutable references to captured variables -/// automatically implement this trait, which allows them to be invoked. -/// For mutably referenced captures, see [`FnMut`], and for consuming the -/// capture, see [`FnOnce`]. +/// Instances of `Fn` can be called repeatedly without mutating state. /// -/// You can use the [`Fn`] traits when you want to accept a closure as a -/// parameter. Since both [`FnMut`] and [`FnOnce`] are supertraits of `Fn`, any -/// instance of `Fn` can be used where a [`FnMut`] or [`FnOnce`] is expected. +/// *This trait (`Fn`) is not to be confused with [function pointers][] +/// (`fn`).* +/// +/// `Fn` is implemented automatically by closures which only take immutable +/// references to captured variables or don't capture anything at all, as well +/// as (safe) [function pointers][] (with some caveats, see their documentation +/// for more details). Additionally, for any type `F` that implements `Fn`, `&F` +/// implements `Fn`, too. +/// +/// Since both [`FnMut`] and [`FnOnce`] are supertraits of `Fn`, any +/// instance of `Fn` can be used as a parameter where a [`FnMut`] or [`FnOnce`] +/// is expected. +/// +/// Use `Fn` as a bound when you want to accept a parameter of function-like +/// type and need to call it repeatedly and without mutating state (e.g. when +/// calling it concurrently). If you do not need such strict requirements, use +/// [`FnMut`] or [`FnOnce`] as bounds. /// /// See the [chapter on closures in *The Rust Programming Language*][book] for -/// more information about closures in general. +/// some more information on this topic. /// /// Also of note is the special syntax for `Fn` traits (e.g. /// `Fn(usize, bool) -> usize`). Those interested in the technical details of -/// this can refer to [the relevant section in *The Rustonomicon*][nomicon]. +/// this can refer to [the relevant section in the *Rustonomicon*][nomicon]. /// /// [book]: ../../book/second-edition/ch13-01-closures.html /// [`FnMut`]: trait.FnMut.html /// [`FnOnce`]: trait.FnOnce.html +/// [function pointers]: ../../std/primitive.fn.html /// [nomicon]: ../../nomicon/hrtb.html /// /// # Examples @@ -61,29 +73,36 @@ pub trait Fn : FnMut { extern "rust-call" fn call(&self, args: Args) -> Self::Output; } -/// A version of the call operator that takes a mutable receiver. +/// The version of the call operator that takes a mutable receiver. /// -/// Closures that might mutably reference captured variables automatically -/// implement this trait, which allows them to be invoked. For immutably -/// referenced captures, see [`Fn`], and for consuming the captures, see -/// [`FnOnce`]. +/// Instances of `FnMut` can be called repeatedly and may mutate state. /// -/// You can use the [`Fn`] traits when you want to accept a closure as a -/// parameter. Since [`FnOnce`] is a supertrait of `FnMut`, any instance of -/// `FnMut` can be used where a [`FnOnce`] is expected, and since [`Fn`] is a -/// subtrait of `FnMut`, any instance of [`Fn`] can be used where [`FnMut`] is -/// expected. +/// `FnMut` is implemented automatically by closures which take mutable +/// references to captured variables, as well as all types that implement +/// [`Fn`], e.g. (safe) [function pointers][] (since `FnMut` is a supertrait of +/// [`Fn`]). Additionally, for any type `F` that implements `FnMut`, `&mut F` +/// implements `FnMut`, too. +/// +/// Since [`FnOnce`] is a supertrait of `FnMut`, any instance of `FnMut` can be +/// used where a [`FnOnce`] is expected, and since [`Fn`] is a subtrait of +/// `FnMut`, any instance of [`Fn`] can be used where `FnMut` is expected. +/// +/// Use `FnMut` as a bound when you want to accept a parameter of function-like +/// type and need to call it repeatedly, while allowing it to mutate state. +/// If you don't want the parameter to mutate state, use [`Fn`] as a +/// bound; if you don't need to call it repeatedly, use [`FnOnce`]. /// /// See the [chapter on closures in *The Rust Programming Language*][book] for -/// more information about closures in general. +/// some more information on this topic. /// /// Also of note is the special syntax for `Fn` traits (e.g. /// `Fn(usize, bool) -> usize`). Those interested in the technical details of -/// this can refer to [the relevant section in *The Rustonomicon*][nomicon]. +/// this can refer to [the relevant section in the *Rustonomicon*][nomicon]. /// /// [book]: ../../book/second-edition/ch13-01-closures.html -/// [`Fn`]: trait.Fnhtml +/// [`Fn`]: trait.Fn.html /// [`FnOnce`]: trait.FnOnce.html +/// [function pointers]: ../../std/primitive.fn.html /// [nomicon]: ../../nomicon/hrtb.html /// /// # Examples @@ -127,27 +146,35 @@ pub trait FnMut : FnOnce { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } -/// A version of the call operator that takes a by-value receiver. +/// The version of the call operator that takes a by-value receiver. /// -/// Closures that might take ownership of captured variables automatically -/// implement this trait, which allows them to be invoked. For immutably -/// referenced captures, see [`Fn`], and for mutably referenced captures, -/// see [`FnMut`]. +/// Instances of `FnOnce` can be called, but might not be callable multiple +/// times. Because of this, if the only thing known about a type is that it +/// implements `FnOnce`, it can only be called once. /// -/// You can use the [`Fn`] traits when you want to accept a closure as a -/// parameter. Since both [`Fn`] and [`FnMut`] are subtraits of `FnOnce`, any -/// instance of [`Fn`] or [`FnMut`] can be used where a `FnOnce` is expected. +/// `FnOnce` is implemented automatically by closure that might consume captured +/// variables, as well as all types that implement [`FnMut`], e.g. (safe) +/// [function pointers][] (since `FnOnce` is a supertrait of [`FnMut`]). +/// +/// Since both [`Fn`] and [`FnMut`] are subtraits of `FnOnce`, any instance of +/// [`Fn`] or [`FnMut`] can be used where a `FnOnce` is expected. +/// +/// Use `FnOnce` as a bound when you want to accept a parameter of function-like +/// type and only need to call it once. If you need to call the parameter +/// repeatedly, use [`FnMut`] as a bound; if you also need it to not mutate +/// state, use [`Fn`]. /// /// See the [chapter on closures in *The Rust Programming Language*][book] for -/// more information about closures in general. +/// some more information on this topic. /// /// Also of note is the special syntax for `Fn` traits (e.g. /// `Fn(usize, bool) -> usize`). Those interested in the technical details of -/// this can refer to [the relevant section in *The Rustonomicon*][nomicon]. +/// this can refer to [the relevant section in the *Rustonomicon*][nomicon]. /// /// [book]: ../../book/second-edition/ch13-01-closures.html /// [`Fn`]: trait.Fn.html /// [`FnMut`]: trait.FnMut.html +/// [function pointers]: ../../std/primitive.fn.html /// [nomicon]: ../../nomicon/hrtb.html /// /// # Examples diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index 0652421511aa..d65c0aba5048 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -77,11 +77,9 @@ pub trait Index { /// `container[index]` is actually syntactic sugar for /// `*container.index_mut(index)`, but only when used as a mutable value. If /// an immutable value is requested, the [`Index`] trait is used instead. This -/// allows nice things such as `v[index] = value` if the type of `value` -/// implements [`Copy`]. +/// allows nice things such as `v[index] = value`. /// /// [`Index`]: ../../std/ops/trait.Index.html -/// [`Copy`]: ../../std/marker/trait.Copy.html /// /// # Examples /// diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 6a405cfdb980..463a50491a86 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -12,7 +12,7 @@ use fmt; /// An unbounded range (`..`). /// -/// `RangeFull` is primarily used as a [slicing index], it's shorthand is `..`. +/// `RangeFull` is primarily used as a [slicing index], its shorthand is `..`. /// It cannot serve as an [`Iterator`] because it doesn't have a starting point. /// /// # Examples @@ -101,7 +101,6 @@ impl> Range { /// ``` /// #![feature(range_contains)] /// - /// # fn main() { /// assert!(!(3..5).contains(2)); /// assert!( (3..5).contains(3)); /// assert!( (3..5).contains(4)); @@ -109,7 +108,6 @@ impl> Range { /// /// assert!(!(3..3).contains(3)); /// assert!(!(3..2).contains(3)); - /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (self.start <= item) && (item < self.end) @@ -163,11 +161,9 @@ impl> RangeFrom { /// ``` /// #![feature(range_contains)] /// - /// # fn main() { /// assert!(!(3..).contains(2)); /// assert!( (3..).contains(3)); /// assert!( (3..).contains(1_000_000_000)); - /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (self.start <= item) @@ -191,6 +187,8 @@ impl> RangeFrom { /// a `for` loop directly. This won't compile: /// /// ```compile_fail,E0277 +/// // error[E0277]: the trait bound `std::ops::RangeTo<{integer}>: +/// // std::iter::Iterator` is not satisfied /// for i in ..5 { /// // ... /// } @@ -234,11 +232,9 @@ impl> RangeTo { /// ``` /// #![feature(range_contains)] /// - /// # fn main() { /// assert!( (..5).contains(-1_000_000_000)); /// assert!( (..5).contains(4)); /// assert!(!(..5).contains(5)); - /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (item < self.end) @@ -255,14 +251,12 @@ impl> RangeTo { /// ``` /// #![feature(inclusive_range,inclusive_range_syntax)] /// -/// # fn main() { /// assert_eq!((3...5), std::ops::RangeInclusive { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3...5).sum()); /// /// let arr = [0, 1, 2, 3]; /// assert_eq!(arr[ ...2], [0,1,2 ]); /// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive -/// # } /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -295,7 +289,6 @@ impl> RangeInclusive { /// ``` /// #![feature(range_contains,inclusive_range_syntax)] /// - /// # fn main() { /// assert!(!(3...5).contains(2)); /// assert!( (3...5).contains(3)); /// assert!( (3...5).contains(4)); @@ -304,7 +297,6 @@ impl> RangeInclusive { /// /// assert!( (3...3).contains(3)); /// assert!(!(3...2).contains(3)); - /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end @@ -330,6 +322,9 @@ impl> RangeInclusive { /// /// ```compile_fail,E0277 /// #![feature(inclusive_range_syntax)] +/// +/// // error[E0277]: the trait bound `std::ops::RangeToInclusive<{integer}>: +/// // std::iter::Iterator` is not satisfied /// for i in ...5 { /// // ... /// } @@ -341,11 +336,9 @@ impl> RangeInclusive { /// ``` /// #![feature(inclusive_range_syntax)] /// -/// # fn main() { /// let arr = [0, 1, 2, 3]; /// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive /// assert_eq!(arr[1...2], [ 1,2 ]); -/// # } /// ``` /// /// [`IntoIterator`]: ../iter/trait.Iterator.html @@ -377,11 +370,9 @@ impl> RangeToInclusive { /// ``` /// #![feature(range_contains,inclusive_range_syntax)] /// - /// # fn main() { /// assert!( (...5).contains(-1_000_000_000)); /// assert!( (...5).contains(5)); /// assert!(!(...5).contains(6)); - /// # } /// ``` pub fn contains(&self, item: Idx) -> bool { (item <= self.end) From 3a831653d06ceef975b80ef4e41ee0679b44c364 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Aug 2017 16:00:09 -0700 Subject: [PATCH 62/88] std: Unsafe-away runtime checks in `Vec` The `RawVec` type has a number of invariants that it upholds throughout its execution, and as a result many of the runtime checks imposed by using `Layout` in a "raw" fashion aren't actually necessary. For example a `RawVec`'s capacity is intended to always match the layout which "fits" the allocation, so we don't need any runtime checks when retrieving the current `Layout` for a vector. Consequently, this adds a safe `current_layout` function which internally uses the `from_size_align_unchecked` function. Along the same lines we know that most construction of new layouts will not overflow. All allocations in `RawVec` are kept below `isize::MAX` and valid alignments are also kept low enough that we're guaranteed that `Layout` for a doubled vector will never overflow and will always succeed construction. Consequently a few locations can use `from_size_align_unchecked` in addition when constructing the *new* layout to allocate (or reallocate), which allows for eliding some more runtime checks. Overall this should significant improve performance for an important function, `RawVec::double`. This commit removes four runtime jumps before `__rust_realloc` is called, as well as one after it's called. --- src/liballoc/raw_vec.rs | 207 +++++++++++++++++++++++++--------------- 1 file changed, 129 insertions(+), 78 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index ca55831220da..6090fc3942a5 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use allocator::{Alloc, Layout}; -use core::ptr::{self, Unique}; -use core::mem; -use core::slice; -use heap::Heap; -use super::boxed::Box; -use core::ops::Drop; use core::cmp; +use core::mem; +use core::ops::Drop; +use core::ptr::{self, Unique}; +use core::slice; +use heap::{Alloc, Layout, Heap}; +use super::boxed::Box; /// A low-level utility for more ergonomically allocating, reallocating, and deallocating /// a buffer of memory on the heap without having to worry about all the corner cases @@ -222,6 +221,20 @@ impl RawVec { &mut self.a } + fn current_layout(&self) -> Option { + if self.cap == 0 { + None + } else { + // We have an allocated chunk of memory, so we can bypass runtime + // checks to get our current layout. + unsafe { + let align = mem::align_of::(); + let size = mem::size_of::() * self.cap; + Some(Layout::from_size_align_unchecked(size, align)) + } + } + } + /// Doubles the size of the type's backing allocation. This is common enough /// to want to do that it's easiest to just have a dedicated method. Slightly /// more efficient logic can be provided for this than the general case. @@ -280,27 +293,40 @@ impl RawVec { // 0, getting to here necessarily means the RawVec is overfull. assert!(elem_size != 0, "capacity overflow"); - let (new_cap, ptr_res) = if self.cap == 0 { - // skip to 4 because tiny Vec's are dumb; but not if that would cause overflow - let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; - let ptr_res = self.a.alloc_array::(new_cap); - (new_cap, ptr_res) - } else { - // Since we guarantee that we never allocate more than isize::MAX bytes, - // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow - let new_cap = 2 * self.cap; - let new_alloc_size = new_cap * elem_size; - alloc_guard(new_alloc_size); - let ptr_res = self.a.realloc_array(self.ptr, self.cap, new_cap); - (new_cap, ptr_res) + let (new_cap, uniq) = match self.current_layout() { + Some(cur) => { + // Since we guarantee that we never allocate more than + // isize::MAX bytes, `elem_size * self.cap <= isize::MAX` as + // a precondition, so this can't overflow. Additionally the + // alignment will never be too large as to "not be + // satisfiable", so `Layout::from_size_align` will always + // return `Some`. + // + // tl;dr; we bypass runtime checks due to dynamic assertions + // in this module, allowing us to use + // `from_size_align_unchecked`. + let new_cap = 2 * self.cap; + let new_size = new_cap * elem_size; + let new_layout = Layout::from_size_align_unchecked(new_size, cur.align()); + alloc_guard(new_size); + let ptr_res = self.a.realloc(self.ptr.as_ptr() as *mut u8, + cur, + new_layout); + match ptr_res { + Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)), + Err(e) => self.a.oom(e), + } + } + None => { + // skip to 4 because tiny Vec's are dumb; but not if that + // would cause overflow + let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; + match self.a.alloc_array::(new_cap) { + Ok(ptr) => (new_cap, ptr), + Err(e) => self.a.oom(e), + } + } }; - - // If allocate or reallocate fail, we'll get `null` back - let uniq = match ptr_res { - Err(err) => self.a.oom(err), - Ok(uniq) => uniq, - }; - self.ptr = uniq; self.cap = new_cap; } @@ -323,21 +349,27 @@ impl RawVec { pub fn double_in_place(&mut self) -> bool { unsafe { let elem_size = mem::size_of::(); + let old_layout = match self.current_layout() { + Some(layout) => layout, + None => return false, // nothing to double + }; // since we set the capacity to usize::MAX when elem_size is // 0, getting to here necessarily means the RawVec is overfull. assert!(elem_size != 0, "capacity overflow"); - // Since we guarantee that we never allocate more than isize::MAX bytes, - // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow + // Since we guarantee that we never allocate more than isize::MAX + // bytes, `elem_size * self.cap <= isize::MAX` as a precondition, so + // this can't overflow. + // + // Similarly like with `double` above we can go straight to + // `Layout::from_size_align_unchecked` as we know this won't + // overflow and the alignment is sufficiently small. let new_cap = 2 * self.cap; - let new_alloc_size = new_cap * elem_size; - - alloc_guard(new_alloc_size); - + let new_size = new_cap * elem_size; + alloc_guard(new_size); let ptr = self.ptr() as *mut _; - let old_layout = Layout::new::().repeat(self.cap).unwrap().0; - let new_layout = Layout::new::().repeat(new_cap).unwrap().0; + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); match self.a.grow_in_place(ptr, old_layout, new_layout) { Ok(_) => { // We can't directly divide `size`. @@ -373,8 +405,6 @@ impl RawVec { /// Aborts on OOM pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { unsafe { - let elem_size = mem::size_of::(); - // NOTE: we don't early branch on ZSTs here because we want this // to actually catch "asking for more than usize::MAX" in that case. // If we make it past the first branch then we are guaranteed to @@ -388,21 +418,22 @@ impl RawVec { // Nothing we can really do about these checks :( let new_cap = used_cap.checked_add(needed_extra_cap).expect("capacity overflow"); - let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow"); - alloc_guard(new_alloc_size); - - let result = if self.cap == 0 { - self.a.alloc_array::(new_cap) - } else { - self.a.realloc_array(self.ptr, self.cap, new_cap) + let new_layout = match Layout::array::(new_cap) { + Some(layout) => layout, + None => panic!("capacity overflow"), }; - - // If allocate or reallocate fail, we'll get `null` back - let uniq = match result { - Err(err) => self.a.oom(err), - Ok(uniq) => uniq, + alloc_guard(new_layout.size()); + let res = match self.current_layout() { + Some(layout) => { + let old_ptr = self.ptr.as_ptr() as *mut u8; + self.a.realloc(old_ptr, layout, new_layout) + } + None => self.a.alloc(new_layout), + }; + let uniq = match res { + Ok(ptr) => Unique::new_unchecked(ptr as *mut T), + Err(e) => self.a.oom(e), }; - self.ptr = uniq; self.cap = new_cap; } @@ -411,17 +442,14 @@ impl RawVec { /// Calculates the buffer's new size given that it'll hold `used_cap + /// needed_extra_cap` elements. This logic is used in amortized reserve methods. /// Returns `(new_capacity, new_alloc_size)`. - fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize) -> (usize, usize) { - let elem_size = mem::size_of::(); + fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize) -> usize { // Nothing we can really do about these checks :( let required_cap = used_cap.checked_add(needed_extra_cap) .expect("capacity overflow"); // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`. let double_cap = self.cap * 2; // `double_cap` guarantees exponential growth. - let new_cap = cmp::max(double_cap, required_cap); - let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow"); - (new_cap, new_alloc_size) + cmp::max(double_cap, required_cap) } /// Ensures that the buffer contains at least enough space to hold @@ -489,21 +517,25 @@ impl RawVec { return; } - let (new_cap, new_alloc_size) = self.amortized_new_size(used_cap, needed_extra_cap); + let new_cap = self.amortized_new_size(used_cap, needed_extra_cap); + + let new_layout = match Layout::array::(new_cap) { + Some(layout) => layout, + None => panic!("capacity overflow"), + }; // FIXME: may crash and burn on over-reserve - alloc_guard(new_alloc_size); - - let result = if self.cap == 0 { - self.a.alloc_array::(new_cap) - } else { - self.a.realloc_array(self.ptr, self.cap, new_cap) + alloc_guard(new_layout.size()); + let res = match self.current_layout() { + Some(layout) => { + let old_ptr = self.ptr.as_ptr() as *mut u8; + self.a.realloc(old_ptr, layout, new_layout) + } + None => self.a.alloc(new_layout), }; - - let uniq = match result { - Err(err) => self.a.oom(err), - Ok(uniq) => uniq, + let uniq = match res { + Ok(ptr) => Unique::new_unchecked(ptr as *mut T), + Err(e) => self.a.oom(e), }; - self.ptr = uniq; self.cap = new_cap; } @@ -536,21 +568,24 @@ impl RawVec { // Don't actually need any more capacity. If the current `cap` is 0, we can't // reallocate in place. // Wrapping in case they give a bad `used_cap` - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap || self.cap == 0 { + let old_layout = match self.current_layout() { + Some(layout) => layout, + None => return false, + }; + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return false; } - let (new_cap, new_alloc_size) = self.amortized_new_size(used_cap, needed_extra_cap); - // FIXME: may crash and burn on over-reserve - alloc_guard(new_alloc_size); + let new_cap = self.amortized_new_size(used_cap, needed_extra_cap); // Here, `cap < used_cap + needed_extra_cap <= new_cap` // (regardless of whether `self.cap - used_cap` wrapped). // Therefore we can safely call grow_in_place. let ptr = self.ptr() as *mut _; - let old_layout = Layout::new::().repeat(self.cap).unwrap().0; let new_layout = Layout::new::().repeat(new_cap).unwrap().0; + // FIXME: may crash and burn on over-reserve + alloc_guard(new_layout.size()); match self.a.grow_in_place(ptr, old_layout, new_layout) { Ok(_) => { self.cap = new_cap; @@ -599,9 +634,24 @@ impl RawVec { } } else if self.cap != amount { unsafe { - match self.a.realloc_array(self.ptr, self.cap, amount) { + // We know here that our `amount` is greater than zero. This + // implies, via the assert above, that capacity is also greater + // than zero, which means that we've got a current layout that + // "fits" + // + // We also know that `self.cap` is greater than `amount`, and + // consequently we don't need runtime checks for creating either + // layout + let old_size = elem_size * self.cap; + let new_size = elem_size * amount; + let align = mem::align_of::(); + let old_layout = Layout::from_size_align_unchecked(old_size, align); + let new_layout = Layout::from_size_align_unchecked(new_size, align); + match self.a.realloc(self.ptr.as_ptr() as *mut u8, + old_layout, + new_layout) { + Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T), Err(err) => self.a.oom(err), - Ok(uniq) => self.ptr = uniq, } } self.cap = amount; @@ -631,10 +681,11 @@ impl RawVec { /// Frees the memory owned by the RawVec *without* trying to Drop its contents. pub unsafe fn dealloc_buffer(&mut self) { let elem_size = mem::size_of::(); - if elem_size != 0 && self.cap != 0 { - let ptr = self.ptr() as *mut u8; - let layout = Layout::new::().repeat(self.cap).unwrap().0; - self.a.dealloc(ptr, layout); + if elem_size != 0 { + if let Some(layout) = self.current_layout() { + let ptr = self.ptr() as *mut u8; + self.a.dealloc(ptr, layout); + } } } } From 44ffb61623741f86fca9f2f51d49dc1778310ee1 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 29 Jul 2017 22:12:53 -0600 Subject: [PATCH 63/88] Unify flags into config. This introduces a slight change in behavior, where we unilaterally respect the --host and --target parameters passed for all sanity checking and runtime configuration. --- src/bootstrap/bin/main.rs | 7 ++-- src/bootstrap/builder.rs | 31 +++++++----------- src/bootstrap/cc.rs | 31 ++++++++---------- src/bootstrap/check.rs | 19 +++-------- src/bootstrap/clean.rs | 2 +- src/bootstrap/compile.rs | 4 +-- src/bootstrap/config.rs | 67 ++++++++++++++++++++++++++++++++------- src/bootstrap/dist.rs | 2 +- src/bootstrap/flags.rs | 15 ++++++--- src/bootstrap/install.rs | 2 +- src/bootstrap/lib.rs | 55 +++++++++++--------------------- src/bootstrap/sanity.rs | 8 ++--- 12 files changed, 126 insertions(+), 117 deletions(-) diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index 5ef18b89841f..d02bc7972ae9 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -21,11 +21,10 @@ extern crate bootstrap; use std::env; -use bootstrap::{Flags, Config, Build}; +use bootstrap::{Config, Build}; fn main() { let args = env::args().skip(1).collect::>(); - let flags = Flags::parse(&args); - let config = Config::parse(&flags.build, flags.config.clone()); - Build::new(flags, config).build(); + let config = Config::parse(&args); + Build::new(config).build(); } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d7f795e40553..a6cbb0134127 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -120,28 +120,21 @@ impl StepDescription { fn maybe_run(&self, builder: &Builder, path: Option<&Path>) { let build = builder.build; let hosts = if self.only_build_targets || self.only_build { - &build.config.host[..1] + build.build_triple() } else { &build.hosts }; - // Determine the actual targets participating in this rule. - // NOTE: We should keep the full projection from build triple to - // the hosts for the dist steps, now that the hosts array above is - // truncated to avoid duplication of work in that case. Therefore - // the original non-shadowed hosts array is used below. + // Determine the targets participating in this rule. let targets = if self.only_hosts { - // If --target was specified but --host wasn't specified, - // don't run any host-only tests. Also, respect any `--host` - // overrides as done for `hosts`. - if build.flags.host.len() > 0 { - &build.flags.host[..] - } else if build.flags.target.len() > 0 { + // If --target was specified but --host wasn't specified, don't run + // any host-only tests. + if build.config.hosts.is_empty() && !build.config.targets.is_empty() { &[] } else if self.only_build { - &build.config.host[..1] + build.build_triple() } else { - &build.config.host[..] + &build.hosts } } else { &build.targets @@ -288,7 +281,7 @@ impl<'a> Builder<'a> { let builder = Builder { build: build, - top_stage: build.flags.stage.unwrap_or(2), + top_stage: build.config.stage.unwrap_or(2), kind: kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -307,7 +300,7 @@ impl<'a> Builder<'a> { } pub fn run(build: &Build) { - let (kind, paths) = match build.flags.cmd { + let (kind, paths) = match build.config.cmd { Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]), @@ -319,7 +312,7 @@ impl<'a> Builder<'a> { let builder = Builder { build: build, - top_stage: build.flags.stage.unwrap_or(2), + top_stage: build.config.stage.unwrap_or(2), kind: kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -543,12 +536,12 @@ impl<'a> Builder<'a> { // Ignore incremental modes except for stage0, since we're // not guaranteeing correctness across builds if the compiler // is changing under your feet.` - if self.flags.incremental && compiler.stage == 0 { + if self.config.incremental && compiler.stage == 0 { let incr_dir = self.incremental_dir(compiler); cargo.env("RUSTC_INCREMENTAL", incr_dir); } - if let Some(ref on_fail) = self.flags.on_fail { + if let Some(ref on_fail) = self.config.on_fail { cargo.env("RUSTC_ON_FAIL", on_fail); } diff --git a/src/bootstrap/cc.rs b/src/bootstrap/cc.rs index 739904e4f7c5..0f25da8a238d 100644 --- a/src/bootstrap/cc.rs +++ b/src/bootstrap/cc.rs @@ -32,6 +32,7 @@ //! everything. use std::process::Command; +use std::iter; use build_helper::{cc2ar, output}; use gcc; @@ -43,47 +44,41 @@ use cache::Interned; pub fn find(build: &mut Build) { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. - // - // This includes targets that aren't necessarily passed on the commandline - // (FIXME: Perhaps it shouldn't?) - for target in &build.config.target { + for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) { let mut cfg = gcc::Config::new(); cfg.cargo_metadata(false).opt_level(0).debug(false) - .target(target).host(&build.build); + .target(&target).host(&build.build); let config = build.config.target_config.get(&target); if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { cfg.compiler(cc); } else { - set_compiler(&mut cfg, "gcc", *target, config, build); + set_compiler(&mut cfg, "gcc", target, config, build); } let compiler = cfg.get_compiler(); - let ar = cc2ar(compiler.path(), target); - build.verbose(&format!("CC_{} = {:?}", target, compiler.path())); + let ar = cc2ar(compiler.path(), &target); + build.verbose(&format!("CC_{} = {:?}", &target, compiler.path())); if let Some(ref ar) = ar { - build.verbose(&format!("AR_{} = {:?}", target, ar)); + build.verbose(&format!("AR_{} = {:?}", &target, ar)); } - build.cc.insert(*target, (compiler, ar)); + build.cc.insert(target, (compiler, ar)); } // For all host triples we need to find a C++ compiler as well - // - // This includes hosts that aren't necessarily passed on the commandline - // (FIXME: Perhaps it shouldn't?) - for host in &build.config.host { + for host in build.hosts.iter().cloned().chain(iter::once(build.build)) { let mut cfg = gcc::Config::new(); cfg.cargo_metadata(false).opt_level(0).debug(false).cpp(true) - .target(host).host(&build.build); - let config = build.config.target_config.get(host); + .target(&host).host(&build.build); + let config = build.config.target_config.get(&host); if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); } else { - set_compiler(&mut cfg, "g++", *host, config, build); + set_compiler(&mut cfg, "g++", host, config, build); } let compiler = cfg.get_compiler(); build.verbose(&format!("CXX_{} = {:?}", host, compiler.path())); - build.cxx.insert(*host, compiler); + build.cxx.insert(host, compiler); } } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index c65f5a9fb48b..0351e9b81585 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -625,7 +625,7 @@ impl Step for Compiletest { cmd.arg("--system-llvm"); } - cmd.args(&build.flags.cmd.test_args()); + cmd.args(&build.config.cmd.test_args()); if build.is_verbose() { cmd.arg("--verbose"); @@ -820,7 +820,7 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) { cmd.arg(markdown); cmd.env("RUSTC_BOOTSTRAP", "1"); - let test_args = build.flags.cmd.test_args().join(" "); + let test_args = build.config.cmd.test_args().join(" "); cmd.arg("--test-args").arg(test_args); if build.config.quiet_tests { @@ -1051,7 +1051,7 @@ impl Step for Crate { cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); cargo.arg("--"); - cargo.args(&build.flags.cmd.test_args()); + cargo.args(&build.config.cmd.test_args()); if build.config.quiet_tests { cargo.arg("--quiet"); @@ -1147,6 +1147,7 @@ pub struct Distcheck; impl Step for Distcheck { type Output = (); + const ONLY_BUILD: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { run.path("distcheck") @@ -1160,16 +1161,6 @@ impl Step for Distcheck { fn run(self, builder: &Builder) { let build = builder.build; - if *build.build != *"x86_64-unknown-linux-gnu" { - return - } - if !build.config.host.iter().any(|s| s == "x86_64-unknown-linux-gnu") { - return - } - if !build.config.target.iter().any(|s| s == "x86_64-unknown-linux-gnu") { - return - } - println!("Distcheck"); let dir = build.out.join("tmp").join("distcheck"); let _ = fs::remove_dir_all(&dir); @@ -1236,7 +1227,7 @@ impl Step for Bootstrap { if !build.fail_fast { cmd.arg("--no-fail-fast"); } - cmd.arg("--").args(&build.flags.cmd.test_args()); + cmd.arg("--").args(&build.config.cmd.test_args()); try_run(build, &mut cmd); } diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 308a0ab3076d..119340a0190c 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -26,7 +26,7 @@ pub fn clean(build: &Build) { rm_rf(&build.out.join("tmp")); rm_rf(&build.out.join("dist")); - for host in build.config.host.iter() { + for host in &build.hosts { let entries = match build.out.join(host).read_dir() { Ok(iter) => iter, Err(_) => continue, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 92a42b59212b..a6702300c811 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -679,10 +679,10 @@ impl Step for Assemble { // link to these. (FIXME: Is that correct? It seems to be correct most // of the time but I think we do link to these for stage2/bin compilers // when not performing a full bootstrap). - if builder.build.flags.keep_stage.map_or(false, |s| target_compiler.stage <= s) { + if builder.build.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) { builder.verbose("skipping compilation of compiler due to --keep-stage"); let compiler = build_compiler; - for stage in 0..min(target_compiler.stage, builder.flags.keep_stage.unwrap()) { + for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) { let target_compiler = builder.compiler(stage, target_compiler.host); let target = target_compiler.host; builder.ensure(StdLink { compiler, target_compiler, target }); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c4d5d4315211..c0494bd7fd08 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -19,11 +19,14 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::path::PathBuf; use std::process; +use std::cmp; use num_cpus; use toml; use util::{exe, push_exe_path}; use cache::{INTERNER, Interned}; +use flags::Flags; +pub use flags::Subcommand; /// Global configuration for the entire build and/or bootstrap. /// @@ -52,6 +55,14 @@ pub struct Config { pub sanitizers: bool, pub profiler: bool, + pub on_fail: Option, + pub stage: Option, + pub keep_stage: Option, + pub src: PathBuf, + pub jobs: Option, + pub cmd: Subcommand, + pub incremental: bool, + // llvm codegen options pub llvm_enabled: bool, pub llvm_assertions: bool, @@ -79,8 +90,8 @@ pub struct Config { pub rust_dist_src: bool, pub build: Interned, - pub host: Vec>, - pub target: Vec>, + pub hosts: Vec>, + pub targets: Vec>, pub local_rebuild: bool, // dist misc @@ -265,7 +276,9 @@ struct TomlTarget { } impl Config { - pub fn parse(build: &str, file: Option) -> Config { + pub fn parse(args: &[String]) -> Config { + let flags = Flags::parse(&args); + let file = flags.config.clone(); let mut config = Config::default(); config.llvm_enabled = true; config.llvm_optimize = true; @@ -277,11 +290,19 @@ impl Config { config.docs = true; config.rust_rpath = true; config.rust_codegen_units = 1; - config.build = INTERNER.intern_str(build); + config.build = flags.build; config.channel = "dev".to_string(); config.codegen_tests = true; config.rust_dist_src = true; + config.on_fail = flags.on_fail; + config.stage = flags.stage; + config.src = flags.src; + config.jobs = flags.jobs; + config.cmd = flags.cmd; + config.incremental = flags.incremental; + config.keep_stage = flags.keep_stage; + let toml = file.map(|file| { let mut f = t!(File::open(&file)); let mut contents = String::new(); @@ -298,20 +319,41 @@ impl Config { let build = toml.build.clone().unwrap_or(Build::default()); set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x))); - config.host.push(config.build.clone()); + config.hosts.push(config.build.clone()); for host in build.host.iter() { let host = INTERNER.intern_str(host); - if !config.host.contains(&host) { - config.host.push(host); + if !config.hosts.contains(&host) { + config.hosts.push(host); } } - for target in config.host.iter().cloned() + for target in config.hosts.iter().cloned() .chain(build.target.iter().map(|s| INTERNER.intern_str(s))) { - if !config.target.contains(&target) { - config.target.push(target); + if !config.targets.contains(&target) { + config.targets.push(target); } } + config.hosts = if !flags.host.is_empty() { + for host in flags.host.iter() { + if !config.hosts.contains(host) { + panic!("specified host `{}` is not in configuration", host); + } + } + flags.host + } else { + config.hosts + }; + config.targets = if !flags.target.is_empty() { + for target in flags.target.iter() { + if !config.targets.contains(target) { + panic!("specified target `{}` is not in configuration", target); + } + } + flags.target + } else { + config.targets + }; + config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); config.python = build.python.map(PathBuf::from); @@ -327,6 +369,7 @@ impl Config { set(&mut config.sanitizers, build.sanitizers); set(&mut config.profiler, build.profiler); set(&mut config.openssl_static, build.openssl_static); + config.verbose = cmp::max(config.verbose, flags.verbose); if let Some(ref install) = toml.install { config.prefix = install.prefix.clone().map(PathBuf::from); @@ -505,11 +548,11 @@ impl Config { match key { "CFG_BUILD" if value.len() > 0 => self.build = INTERNER.intern_str(value), "CFG_HOST" if value.len() > 0 => { - self.host.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); + self.hosts.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); } "CFG_TARGET" if value.len() > 0 => { - self.target.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); + self.targets.extend(value.split(" ").map(|s| INTERNER.intern_str(s))); } "CFG_EXPERIMENTAL_TARGETS" if value.len() > 0 => { self.llvm_experimental_targets = Some(value.to_string()); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c322d75dd5b4..e467ba49b973 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -546,7 +546,7 @@ impl Step for Std { // We want to package up as many target libraries as possible // for the `rust-std` package, so if this is a host target we // depend on librustc and otherwise we just depend on libtest. - if build.config.host.iter().any(|t| t == target) { + if build.hosts.iter().any(|t| t == target) { builder.ensure(compile::Rustc { compiler, target }); } else { builder.ensure(compile::Test { compiler, target }); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 1a3a008ed261..b20801971f19 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -34,6 +34,7 @@ pub struct Flags { pub stage: Option, pub keep_stage: Option, pub build: Interned, + pub host: Vec>, pub target: Vec>, pub config: Option, @@ -68,6 +69,14 @@ pub enum Subcommand { }, } +impl Default for Subcommand { + fn default() -> Subcommand { + Subcommand::Build { + paths: vec![PathBuf::from("nowhere")], + } + } +} + impl Flags { pub fn parse(args: &[String]) -> Flags { let mut extra_help = String::new(); @@ -243,10 +252,8 @@ Arguments: // 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::parse(&flags.build, cfg_file.clone()); - config.build = flags.build.clone(); - let mut build = Build::new(flags, config); + let config = Config::parse(&["build".to_string()]); + let mut build = Build::new(config); metadata::build(&mut build); let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index ebfda1e619bd..89690e444d1f 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -28,7 +28,7 @@ pub fn install_docs(builder: &Builder, stage: u32, host: Interned) { } pub fn install_std(builder: &Builder, stage: u32) { - for target in builder.build.config.target.iter() { + for target in &builder.build.targets { install_sh(builder, "std", "rust-std", stage, Some(*target)); } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a8485d1d152d..e1d2779057f9 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -136,13 +136,13 @@ extern crate toml; extern crate libc; use std::cell::Cell; -use std::cmp; use std::collections::{HashSet, HashMap}; use std::env; use std::fs::{self, File}; use std::io::Read; use std::path::{PathBuf, Path}; use std::process::Command; +use std::slice; use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; @@ -187,7 +187,7 @@ mod job { } pub use config::Config; -pub use flags::{Flags, Subcommand}; +use flags::Subcommand; use cache::{Interned, INTERNER}; /// A structure representing a Rust compiler. @@ -215,9 +215,6 @@ pub struct Build { // User-specified configuration via config.toml config: Config, - // User-specified configuration via CLI flags - flags: Flags, - // Derived properties from the above two configurations src: PathBuf, out: PathBuf, @@ -288,9 +285,9 @@ impl Build { /// line and the filesystem `config`. /// /// By default all build output will be placed in the current directory. - pub fn new(flags: Flags, config: Config) -> Build { + pub fn new(config: Config) -> Build { let cwd = t!(env::current_dir()); - let src = flags.src.clone(); + let src = config.src.clone(); let out = cwd.join("build"); let is_sudo = match env::var_os("SUDO_USER") { @@ -306,39 +303,17 @@ impl Build { let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo")); let rls_info = channel::GitInfo::new(&src.join("src/tools/rls")); - let hosts = if !flags.host.is_empty() { - for host in flags.host.iter() { - if !config.host.contains(host) { - panic!("specified host `{}` is not in configuration", host); - } - } - flags.host.clone() - } else { - config.host.clone() - }; - let targets = if !flags.target.is_empty() { - for target in flags.target.iter() { - if !config.target.contains(target) { - panic!("specified target `{}` is not in configuration", target); - } - } - flags.target.clone() - } else { - config.target.clone() - }; - Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), local_rebuild: config.local_rebuild, - fail_fast: flags.cmd.fail_fast(), - verbosity: cmp::max(flags.verbose, config.verbose), + fail_fast: config.cmd.fail_fast(), + verbosity: config.verbose, - build: config.host[0].clone(), - hosts: hosts, - targets: targets, + build: config.build, + hosts: config.hosts.clone(), + targets: config.targets.clone(), - flags: flags, config: config, src: src, out: out, @@ -357,13 +332,19 @@ impl Build { } } + pub fn build_triple(&self) -> &[Interned] { + unsafe { + slice::from_raw_parts(&self.build, 1) + } + } + /// Executes the entire build, as configured by the flags and configuration. pub fn build(&mut self) { unsafe { job::setup(self); } - if let Subcommand::Clean = self.flags.cmd { + if let Subcommand::Clean = self.config.cmd { return clean::clean(self); } @@ -608,7 +589,7 @@ impl Build { /// Returns the number of parallel jobs that have been configured for this /// build. fn jobs(&self) -> u32 { - self.flags.jobs.unwrap_or_else(|| num_cpus::get() as u32) + self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32) } /// Returns the path to the C compiler for the target specified. @@ -727,7 +708,7 @@ impl Build { fn force_use_stage1(&self, compiler: Compiler, target: Interned) -> bool { !self.config.full_bootstrap && compiler.stage >= 2 && - self.config.host.iter().any(|h| *h == target) + self.hosts.iter().any(|h| *h == target) } /// Returns the directory that OpenSSL artifacts are compiled into if diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 7063b28f19d0..436a13500f25 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -85,7 +85,7 @@ pub fn check(build: &mut Build) { } // We need cmake, but only if we're actually building LLVM or sanitizers. - let building_llvm = build.config.host.iter() + let building_llvm = build.hosts.iter() .filter_map(|host| build.config.target_config.get(host)) .any(|config| config.llvm_config.is_none()); if building_llvm || build.config.sanitizers { @@ -114,7 +114,7 @@ pub fn check(build: &mut Build) { // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. - for target in &build.config.target { + for target in &build.targets { // On emscripten we don't actually need the C compiler to just // build the target artifacts, only for testing. For the sake // of easier bot configuration, just skip detection. @@ -128,7 +128,7 @@ pub fn check(build: &mut Build) { } } - for host in build.config.host.iter() { + for host in &build.hosts { cmd_finder.must_have(build.cxx(*host).unwrap()); // The msvc hosts don't use jemalloc, turn it off globally to @@ -144,7 +144,7 @@ pub fn check(build: &mut Build) { panic!("FileCheck executable {:?} does not exist", filecheck); } - for target in &build.config.target { + for target in &build.targets { // Can't compile for iOS unless we're on macOS if target.contains("apple-ios") && !build.build.contains("apple-darwin") { From 84d9a6ee8cb40ea3dc390b8f4e2862289cb14f7e Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 29 Jul 2017 22:26:28 -0600 Subject: [PATCH 64/88] Allow specifiying targets and hosts not in the config file. We no longer care about the source of this information, so there is no reason to restrict users. --- src/bootstrap/config.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index c0494bd7fd08..e1c60b5d1914 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -334,21 +334,11 @@ impl Config { } } config.hosts = if !flags.host.is_empty() { - for host in flags.host.iter() { - if !config.hosts.contains(host) { - panic!("specified host `{}` is not in configuration", host); - } - } flags.host } else { config.hosts }; config.targets = if !flags.target.is_empty() { - for target in flags.target.iter() { - if !config.targets.contains(target) { - panic!("specified target `{}` is not in configuration", target); - } - } flags.target } else { config.targets From 5290c6c8f158004b19fa38aab36ac29511ec1a8a Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 29 Jul 2017 22:45:49 -0600 Subject: [PATCH 65/88] Allow overriding build triple via flag. We first check the configuration, then passed parameters (--build), then fall back to the auto-detection that bootstrap.py does. Fixes #39673. --- src/bootstrap/config.rs | 6 +++++- src/bootstrap/flags.rs | 6 ++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e1c60b5d1914..008dbbe89142 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -290,7 +290,6 @@ impl Config { config.docs = true; config.rust_rpath = true; config.rust_codegen_units = 1; - config.build = flags.build; config.channel = "dev".to_string(); config.codegen_tests = true; config.rust_dist_src = true; @@ -319,6 +318,11 @@ impl Config { let build = toml.build.clone().unwrap_or(Build::default()); set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x))); + set(&mut config.build, flags.build); + if config.build.is_empty() { + // set by bootstrap.py + config.build = INTERNER.intern_str(&env::var("BUILD").unwrap()); + } config.hosts.push(config.build.clone()); for host in build.host.iter() { let host = INTERNER.intern_str(host); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index b20801971f19..a9cefb65f496 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -33,7 +33,7 @@ pub struct Flags { pub on_fail: Option, pub stage: Option, pub keep_stage: Option, - pub build: Interned, + pub build: Option>, pub host: Vec>, pub target: Vec>, @@ -327,9 +327,7 @@ Arguments: stage: stage, on_fail: matches.opt_str("on-fail"), keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), - build: INTERNER.intern_string(matches.opt_str("build").unwrap_or_else(|| { - env::var("BUILD").unwrap() - })), + build: matches.opt_str("build").map(|s| INTERNER.intern_string(s)), host: split(matches.opt_strs("host")) .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), target: split(matches.opt_strs("target")) From 40dea65ec2675f776a27b67fcb2bb7f29e843da9 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 3 Aug 2017 10:53:56 -0600 Subject: [PATCH 66/88] Add ability to ignore git when building rust. Some users of the build system change the git sha on every build due to utilizing git to push changes to a remote server. This allows them to simply configure that away instead of depending on custom patches to rustbuild. --- config.toml.example | 3 +++ src/bootstrap/channel.rs | 5 +++-- src/bootstrap/config.rs | 4 ++++ src/bootstrap/lib.rs | 6 +++--- src/bootstrap/tool.rs | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/config.toml.example b/config.toml.example index 19678dc77937..962be2e60850 100644 --- a/config.toml.example +++ b/config.toml.example @@ -258,6 +258,9 @@ # saying that the FileCheck executable is missing, you may want to disable this. #codegen-tests = true +# Flag indicating whether git info will be retrieved from .git automatically. +#ignore-git = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index beefaeab90b1..9c1ae83d3828 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -21,6 +21,7 @@ use std::process::Command; use build_helper::output; use Build; +use config::Config; // The version number pub const CFG_RELEASE_NUM: &str = "1.21.0"; @@ -41,9 +42,9 @@ struct Info { } impl GitInfo { - pub fn new(dir: &Path) -> GitInfo { + pub fn new(config: &Config, dir: &Path) -> GitInfo { // See if this even begins to look like a git dir - if !dir.join(".git").exists() { + if config.ignore_git || !dir.join(".git").exists() { return GitInfo { inner: None } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 008dbbe89142..3ec1c205dc00 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -54,6 +54,7 @@ pub struct Config { pub extended: bool, pub sanitizers: bool, pub profiler: bool, + pub ignore_git: bool, pub on_fail: Option, pub stage: Option, @@ -260,6 +261,7 @@ struct Rust { optimize_tests: Option, debuginfo_tests: Option, codegen_tests: Option, + ignore_git: Option, } /// TOML representation of how each build target is configured. @@ -292,6 +294,7 @@ impl Config { config.rust_codegen_units = 1; config.channel = "dev".to_string(); config.codegen_tests = true; + config.ignore_git = false; config.rust_dist_src = true; config.on_fail = flags.on_fail; @@ -410,6 +413,7 @@ impl Config { set(&mut config.use_jemalloc, rust.use_jemalloc); set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); + set(&mut config.ignore_git, rust.ignore_git); config.rustc_default_linker = rust.default_linker.clone(); config.rustc_default_ar = rust.default_ar.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e1d2779057f9..1452a38f6ed2 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -299,9 +299,9 @@ impl Build { } None => false, }; - let rust_info = channel::GitInfo::new(&src); - let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo")); - let rls_info = channel::GitInfo::new(&src.join("src/tools/rls")); + let rust_info = channel::GitInfo::new(&config, &src); + let cargo_info = channel::GitInfo::new(&config, &src.join("src/tools/cargo")); + let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls")); Build { initial_rustc: config.initial_rustc.clone(), diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 862b3e2b1edb..da61ad442899 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -109,7 +109,7 @@ impl Step for ToolBuild { cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel); - let info = GitInfo::new(&dir); + let info = GitInfo::new(&build.config, &dir); if let Some(sha) = info.sha() { cargo.env("CFG_COMMIT_HASH", sha); } From 83b68125e70b2b966439db748a79d36afd274bf3 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 3 Aug 2017 16:06:20 -0600 Subject: [PATCH 67/88] Make the message for building rustdoc slightly nicer --- src/bootstrap/tool.rs | 82 ++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index da61ad442899..3043c95b5f07 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -93,38 +93,48 @@ impl Step for ToolBuild { let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); println!("Building stage{} tool {} ({})", compiler.stage, tool, target); - let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build"); - let dir = build.src.join("src/tools").join(tool); - cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); - - // We don't want to build tools dynamically as they'll be running across - // stages and such and it's just easier if they're not dynamically linked. - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - - if let Some(dir) = build.openssl_install_dir(target) { - cargo.env("OPENSSL_STATIC", "1"); - cargo.env("OPENSSL_DIR", dir); - cargo.env("LIBZ_SYS_STATIC", "1"); - } - - cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel); - - let info = GitInfo::new(&build.config, &dir); - if let Some(sha) = info.sha() { - cargo.env("CFG_COMMIT_HASH", sha); - } - if let Some(sha_short) = info.sha_short() { - cargo.env("CFG_SHORT_COMMIT_HASH", sha_short); - } - if let Some(date) = info.commit_date() { - cargo.env("CFG_COMMIT_DATE", date); - } - + let mut cargo = prepare_tool_cargo(builder, compiler, target, tool); build.run(&mut cargo); build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host)) } } +fn prepare_tool_cargo( + builder: &Builder, + compiler: Compiler, + target: Interned, + tool: &'static str, +) -> Command { + let build = builder.build; + let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build"); + let dir = build.src.join("src/tools").join(tool); + cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); + + // We don't want to build tools dynamically as they'll be running across + // stages and such and it's just easier if they're not dynamically linked. + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + if let Some(dir) = build.openssl_install_dir(target) { + cargo.env("OPENSSL_STATIC", "1"); + cargo.env("OPENSSL_DIR", dir); + cargo.env("LIBZ_SYS_STATIC", "1"); + } + + cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel); + + let info = GitInfo::new(&build.config, &dir); + if let Some(sha) = info.sha() { + cargo.env("CFG_COMMIT_HASH", sha); + } + if let Some(sha_short) = info.sha_short() { + cargo.env("CFG_SHORT_COMMIT_HASH", sha_short); + } + if let Some(date) = info.commit_date() { + cargo.env("CFG_COMMIT_DATE", date); + } + cargo +} + macro_rules! tool { ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => { #[derive(Copy, Clone)] @@ -245,7 +255,9 @@ impl Step for Rustdoc { } fn run(self, builder: &Builder) -> PathBuf { + let build = builder.build; let target_compiler = self.target_compiler; + let target = target_compiler.host; let build_compiler = if target_compiler.stage == 0 { builder.compiler(0, builder.build.build) } else { @@ -255,12 +267,16 @@ impl Step for Rustdoc { builder.compiler(target_compiler.stage - 1, builder.build.build) }; - let tool_rustdoc = builder.ensure(ToolBuild { - compiler: build_compiler, - target: target_compiler.host, - tool: "rustdoc", - mode: Mode::Librustc, - }); + builder.ensure(CleanTools { compiler: build_compiler, target, mode: Mode::Librustc }); + builder.ensure(compile::Rustc { compiler: build_compiler, target }); + + let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); + println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host); + + let mut cargo = prepare_tool_cargo(builder, build_compiler, target, "rustdoc"); + build.run(&mut cargo); + let tool_rustdoc = build.cargo_out(build_compiler, Mode::Tool, target) + .join(exe("rustdoc", &target_compiler.host)); // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { From ad4acbaadf7d093f157e4499b2aedda9d91ec03b Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 3 Aug 2017 19:08:20 -0600 Subject: [PATCH 68/88] Build rustdoc with the stageN compiler in N >= 2. This permits proc macro crates to correctly work with rustdoc. --- src/bootstrap/tool.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 3043c95b5f07..e5783e346f46 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -260,6 +260,10 @@ impl Step for Rustdoc { let target = target_compiler.host; let build_compiler = if target_compiler.stage == 0 { builder.compiler(0, builder.build.build) + } else if target_compiler.stage >= 2 { + // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of + // building rustdoc itself. + target_compiler } else { // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage From facf5a91c458958de1c11cb9c28e14671af9b6fd Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 4 Aug 2017 16:13:01 -0600 Subject: [PATCH 69/88] Build rustdoc only at the top stage --- src/bootstrap/builder.rs | 19 ++++++++----------- src/bootstrap/check.rs | 6 +++--- src/bootstrap/dist.rs | 3 +-- src/bootstrap/doc.rs | 12 ++++++------ src/bootstrap/tool.rs | 6 +++--- 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index a6cbb0134127..d469f7c1722a 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -407,22 +407,19 @@ impl<'a> Builder<'a> { } } - pub fn rustdoc(&self, compiler: Compiler) -> PathBuf { - self.ensure(tool::Rustdoc { target_compiler: compiler }) + pub fn rustdoc(&self, host: Interned) -> PathBuf { + self.ensure(tool::Rustdoc { host }) } - pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command { + pub fn rustdoc_cmd(&self, host: Interned) -> Command { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); + let compiler = self.compiler(self.top_stage, host); cmd .env("RUSTC_STAGE", compiler.stage.to_string()) - .env("RUSTC_SYSROOT", if compiler.is_snapshot(&self.build) { - INTERNER.intern_path(self.build.rustc_snapshot_libdir()) - } else { - self.sysroot(compiler) - }) - .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(compiler)); + .env("RUSTDOC_REAL", self.rustdoc(host)); cmd } @@ -476,7 +473,7 @@ impl<'a> Builder<'a> { .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) .env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" { - self.rustdoc(compiler) + self.rustdoc(compiler.host) } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") }) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 0351e9b81585..d4d6fdc5c1b7 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -164,7 +164,7 @@ impl Step for Cargotest { try_run(build, cmd.arg(&build.initial_cargo) .arg(&out_dir) .env("RUSTC", builder.rustc(compiler)) - .env("RUSTDOC", builder.rustdoc(compiler))); + .env("RUSTDOC", builder.rustdoc(compiler.host))); } } @@ -565,7 +565,7 @@ impl Step for Compiletest { // Avoid depending on rustdoc when we don't need it. if mode == "rustdoc" || mode == "run-make" { - cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler)); + cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); } cmd.arg("--src-base").arg(build.src.join("src/test").join(suite)); @@ -814,7 +814,7 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) { } println!("doc tests for: {}", markdown.display()); - let mut cmd = builder.rustdoc_cmd(compiler); + let mut cmd = builder.rustdoc_cmd(compiler.host); build.add_rust_test_threads(&mut cmd); cmd.arg("--test"); cmd.arg(markdown); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e467ba49b973..bfcfb5f9a37f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -413,8 +413,7 @@ impl Step for Rustc { t!(fs::create_dir_all(image.join("bin"))); cp_r(&src.join("bin"), &image.join("bin")); - install(&builder.ensure(tool::Rustdoc { target_compiler: compiler }), - &image.join("bin"), 0o755); + install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755); // Copy runtime DLLs needed by the compiler if libdir != "bin" { diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 1ee578bb62b1..f0e0874abed6 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -260,7 +260,7 @@ fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned, } impl Step for Rustdoc { @@ -250,13 +250,13 @@ impl Step for Rustdoc { fn make_run(run: RunConfig) { run.builder.ensure(Rustdoc { - target_compiler: run.builder.compiler(run.builder.top_stage, run.host), + host: run.host, }); } fn run(self, builder: &Builder) -> PathBuf { let build = builder.build; - let target_compiler = self.target_compiler; + let target_compiler = builder.compiler(builder.top_stage, self.host); let target = target_compiler.host; let build_compiler = if target_compiler.stage == 0 { builder.compiler(0, builder.build.build) From cec68167fd3787500194f261e2fcbb14381cd317 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 10 Aug 2017 10:12:35 +0500 Subject: [PATCH 70/88] Clean tools after building libstd/libtest/librustc. This fixes the bug we previously had where we'd build a libtest tool after building a libstd tool and clear out the libstd tool. Since we clear out all tools for a given stage on invocations of CleanTools after lib{std, test, rustc} change, we need to make sure that all tools built with that stage will be built after the clearing is done. The fix contained here technically isn't perfect; there is still an edge case of compiling a libstd tool, then compiling libtest, which will clear out the libstd tool and it won't ever get rebuilt within that session of rustbuild. This is where the caching system used today shows it's problems -- in effect, all tools depend on a global counter of the stage being cleared out. We can implement such a counter in a future patch to ensure that tools are rebuilt as needed, but it is deemed unlikely that it will be required in practice, since most if not all tools are built after the relevant stage's std/test/rustc are built, though this is only an opinion and hasn't been verified. --- src/bootstrap/compile.rs | 17 +++++++++++++++++ src/bootstrap/tool.rs | 10 ++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index a6702300c811..33c3638a8947 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -32,6 +32,7 @@ use serde_json; use util::{exe, libdir, is_dylib, copy}; use {Build, Compiler, Mode}; use native; +use tool; use cache::{INTERNER, Interned}; use builder::{Step, RunConfig, ShouldRun, Builder}; @@ -198,6 +199,12 @@ impl Step for StdLink { // for reason why the sanitizers are not built in stage0. copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir); } + + builder.ensure(tool::CleanTools { + compiler: target_compiler, + target: target, + mode: Mode::Libstd, + }); } } @@ -389,6 +396,11 @@ impl Step for TestLink { target); add_to_sysroot(&builder.sysroot_libdir(target_compiler, target), &libtest_stamp(build, compiler, target)); + builder.ensure(tool::CleanTools { + compiler: target_compiler, + target: target, + mode: Mode::Libtest, + }); } } @@ -567,6 +579,11 @@ impl Step for RustcLink { target); add_to_sysroot(&builder.sysroot_libdir(target_compiler, target), &librustc_stamp(build, compiler, target)); + builder.ensure(tool::CleanTools { + compiler: target_compiler, + target: target, + mode: Mode::Librustc, + }); } } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 89b1b1137973..7ccd527b3387 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -23,10 +23,10 @@ use channel::GitInfo; use cache::Interned; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -struct CleanTools { - compiler: Compiler, - target: Interned, - mode: Mode, +pub struct CleanTools { + pub compiler: Compiler, + pub target: Interned, + pub mode: Mode, } impl Step for CleanTools { @@ -82,7 +82,6 @@ impl Step for ToolBuild { let target = self.target; let tool = self.tool; - builder.ensure(CleanTools { compiler, target, mode: self.mode }); match self.mode { Mode::Libstd => builder.ensure(compile::Std { compiler, target }), Mode::Libtest => builder.ensure(compile::Test { compiler, target }), @@ -271,7 +270,6 @@ impl Step for Rustdoc { builder.compiler(target_compiler.stage - 1, builder.build.build) }; - builder.ensure(CleanTools { compiler: build_compiler, target, mode: Mode::Librustc }); builder.ensure(compile::Rustc { compiler: build_compiler, target }); let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); From 657196830fd7fdc03eab87b8afa21601faf07975 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 10 Aug 2017 21:17:42 +0500 Subject: [PATCH 71/88] Correct code to not run host-only tests. --- src/bootstrap/builder.rs | 4 +--- src/bootstrap/config.rs | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d469f7c1722a..db2c6dfeb9f7 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -127,9 +127,7 @@ impl StepDescription { // Determine the targets participating in this rule. let targets = if self.only_hosts { - // If --target was specified but --host wasn't specified, don't run - // any host-only tests. - if build.config.hosts.is_empty() && !build.config.targets.is_empty() { + if build.config.run_host_only { &[] } else if self.only_build { build.build_triple() diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 3ec1c205dc00..aa688fc66e26 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -56,6 +56,8 @@ pub struct Config { pub profiler: bool, pub ignore_git: bool, + pub run_host_only: bool, + pub on_fail: Option, pub stage: Option, pub keep_stage: Option, @@ -305,6 +307,9 @@ impl Config { config.incremental = flags.incremental; config.keep_stage = flags.keep_stage; + // If --target was specified but --host wasn't specified, don't run any host-only tests. + config.run_host_only = flags.host.is_empty() && !flags.target.is_empty(); + let toml = file.map(|file| { let mut f = t!(File::open(&file)); let mut contents = String::new(); @@ -351,6 +356,7 @@ impl Config { config.targets }; + config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); config.python = build.python.map(PathBuf::from); From 82cdf1006e235a318a927b58ab0bc53b7f2a611c Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 13 Aug 2017 05:07:01 +0500 Subject: [PATCH 72/88] Cargotest needs only one rustdoc.exe to exist on Windows --- src/bootstrap/tool.rs | 5 ++++- src/tools/rustdoc/Cargo.toml | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 7ccd527b3387..255ded4c3f63 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -277,8 +277,11 @@ impl Step for Rustdoc { let mut cargo = prepare_tool_cargo(builder, build_compiler, target, "rustdoc"); build.run(&mut cargo); + // Cargo adds a number of paths to the dylib search path on windows, which results in + // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" + // rustdoc a different name. let tool_rustdoc = build.cargo_out(build_compiler, Mode::Tool, target) - .join(exe("rustdoc", &target_compiler.host)); + .join(exe("rustdoc-tool-binary", &target_compiler.host)); // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { diff --git a/src/tools/rustdoc/Cargo.toml b/src/tools/rustdoc/Cargo.toml index b6edb76d7f98..344f617ef95b 100644 --- a/src/tools/rustdoc/Cargo.toml +++ b/src/tools/rustdoc/Cargo.toml @@ -3,8 +3,11 @@ name = "rustdoc-tool" version = "0.0.0" authors = ["The Rust Project Developers"] +# Cargo adds a number of paths to the dylib search path on windows, which results in +# the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" +# rustdoc a different name. [[bin]] -name = "rustdoc" +name = "rustdoc-tool-binary" path = "main.rs" [dependencies] From aea61e6005dabf3a5c85dbb4fda33544c7808f16 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 12 Aug 2017 19:22:03 -0700 Subject: [PATCH 73/88] Fix TcpStream::connect_timeout tracking issue number --- src/libstd/net/tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index fdeca8bc5cac..5c8589f4d4c6 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -147,7 +147,7 @@ impl TcpStream { /// connection request. /// /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html - #[unstable(feature = "tcpstream_connect_timeout", issue = "43709")] + #[unstable(feature = "tcpstream_connect_timeout", issue = "43079")] pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream) } From 01641c70331d704fdab05914f21921e453ae61bb Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 13 Aug 2017 08:58:49 +0500 Subject: [PATCH 74/88] Build rustdoc with the native build triple --- src/bootstrap/tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 255ded4c3f63..d798e8de3dff 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -262,7 +262,7 @@ impl Step for Rustdoc { } else if target_compiler.stage >= 2 { // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of // building rustdoc itself. - target_compiler + builder.compiler(target_compiler.stage, builder.build.build) } else { // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage From faf6b84304dbc96f7bf142973f394f820e390a4c Mon Sep 17 00:00:00 2001 From: Alexey Tarasov Date: Sun, 13 Aug 2017 19:28:04 +1000 Subject: [PATCH 75/88] Addresses comments in PR #43836 - removes warnings introduced in changeset 0cd3587 - makes documentation more neat and grammatically correct --- src/libcore/ptr.rs | 18 +++--- src/librustc_trans/intrinsic.rs | 46 +-------------- src/test/{ui => run-pass}/issue-39827.rs | 5 ++ src/test/ui/issue-39827.stderr | 73 ------------------------ 4 files changed, 16 insertions(+), 126 deletions(-) rename src/test/{ui => run-pass}/issue-39827.rs (89%) delete mode 100644 src/test/ui/issue-39827.stderr diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b37e3a5236d1..e35777d222c0 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -384,11 +384,10 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// over time. That being said, the semantics will almost always end up pretty /// similar to [C11's definition of volatile][c11]. /// -/// Compiler shouldn't change relative order or number of volatile memory -/// operations, however this implies that memory operation actually takes place. -/// If a zero-sized type is used in a specialisation of `read_volatile`, value -/// is known at any time and can not be modified outside of program control. -/// In this case such operation may be omitted by compiler backend. +/// The compiler shouldn't change the relative order or number of volatile +/// memory operations. However, volatile memory operations on zero-sized types +/// (e.g. if a zero-sized type is passed to `read_volatile`) are no-ops +/// and may be ignored. /// /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf /// @@ -433,11 +432,10 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// over time. That being said, the semantics will almost always end up pretty /// similar to [C11's definition of volatile][c11]. /// -/// Compiler shouldn't change relative order or number of volatile memory -/// operations, however this implies that memory operation actually takes place. -/// If a zero-sized type is used in a specialisation of `write_volatile`, value -/// is known at any time and can not be modified outside of program control. -/// In this case such operation may be omitted by compiler backend. +/// The compiler shouldn't change the relative order or number of volatile +/// memory operations. However, volatile memory operations on zero-sized types +/// (e.g. if a zero-sized type is passed to `write_volatile`) are no-ops +/// and may be ignored. /// /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf /// diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5ebd9bed5c8c..033ef988571d 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -83,38 +83,6 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { Some(ccx.get_intrinsic(&llvm_name)) } -fn warn_if_size_is_weird<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, - tp_ty: Ty<'tcx>, - count: ValueRef, - span: Span, - name: &str) { - let ccx = bcx.ccx; - let lltp_ty = type_of::type_of(ccx, tp_ty); - let ty_size = machine::llsize_of(ccx, lltp_ty); - let total = const_to_uint( bcx.mul(ty_size, count) ); - - if total > 0 { - return; - } - - let text = format!("suspicious monomorphization of `{}` intrinsic", name); - let note = match name - { - "volatile_load" | "volatile_store" => - format!("'{}' was specialized with zero-sized type '{}'", - name, tp_ty), - _ => format!("'{}' was specialized with type '{}', number of \ - elements is {}", - name, tp_ty, - const_to_uint(count)) - }; - - let sess = bcx.sess(); - sess.struct_span_warn(span, &text) - .note(¬e) - .emit(); -} - /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, /// add them to librustc_trans/trans/context.rs @@ -249,24 +217,17 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "volatile_copy_nonoverlapping_memory" => { - let tp_ty = substs.type_at(0); - warn_if_size_is_weird(bcx, tp_ty, llargs[2], span, name); - copy_intrinsic(bcx, false, true, tp_ty, llargs[0], llargs[1], llargs[2]) + copy_intrinsic(bcx, false, true, substs.type_at(0), llargs[0], llargs[1], llargs[2]) } "volatile_copy_memory" => { - let tp_ty = substs.type_at(0); - warn_if_size_is_weird(bcx, tp_ty, llargs[2], span, name); - copy_intrinsic(bcx, true, true, tp_ty, llargs[0], llargs[1], llargs[2]) + copy_intrinsic(bcx, true, true, substs.type_at(0), llargs[0], llargs[1], llargs[2]) } "volatile_set_memory" => { - let tp_ty = substs.type_at(0); - warn_if_size_is_weird(bcx, tp_ty, llargs[2], span, name); - memset_intrinsic(bcx, true, tp_ty, llargs[0], llargs[1], llargs[2]) + memset_intrinsic(bcx, true, substs.type_at(0), llargs[0], llargs[1], llargs[2]) } "volatile_load" => { let tp_ty = substs.type_at(0); let mut ptr = llargs[0]; - warn_if_size_is_weird(bcx, tp_ty, C_uint(ccx,1usize), span, name); if let Some(ty) = fn_ty.ret.cast { ptr = bcx.pointercast(ptr, ty.ptr_to()); } @@ -278,7 +239,6 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, }, "volatile_store" => { let tp_ty = substs.type_at(0); - warn_if_size_is_weird(bcx, tp_ty, C_uint(ccx,1usize), span, name); if type_is_fat_ptr(bcx.ccx, tp_ty) { bcx.volatile_store(llargs[1], get_dataptr(bcx, llargs[0])); bcx.volatile_store(llargs[2], get_meta(bcx, llargs[0])); diff --git a/src/test/ui/issue-39827.rs b/src/test/run-pass/issue-39827.rs similarity index 89% rename from src/test/ui/issue-39827.rs rename to src/test/run-pass/issue-39827.rs index 86a3f67b40a8..b753cf5844fa 100644 --- a/src/test/ui/issue-39827.rs +++ b/src/test/run-pass/issue-39827.rs @@ -13,6 +13,11 @@ use std::intrinsics::{ volatile_copy_memory, volatile_store, volatile_load, volatile_copy_nonoverlapping_memory, volatile_set_memory }; +// +// This test ensures that volatile intrinsics can be specialised with +// zero-sized types and, in case of copy/set functions, can accept +// number of elements equal to zero. +// fn main () { let mut dst_pair = (1, 2); let src_pair = (3, 4); diff --git a/src/test/ui/issue-39827.stderr b/src/test/ui/issue-39827.stderr deleted file mode 100644 index 228309872f93..000000000000 --- a/src/test/ui/issue-39827.stderr +++ /dev/null @@ -1,73 +0,0 @@ -warning: suspicious monomorphization of `volatile_copy_memory` intrinsic - --> $DIR/issue-39827.rs:26:9 - | -26 | volatile_copy_memory(&mut dst_pair, &dst_pair, COUNT_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_copy_memory' was specialized with type '(i32, i32)', number of elements is 0 - -warning: suspicious monomorphization of `volatile_copy_nonoverlapping_memory` intrinsic - --> $DIR/issue-39827.rs:27:9 - | -27 | volatile_copy_nonoverlapping_memory(&mut dst_pair, &src_pair, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_copy_nonoverlapping_memory' was specialized with type '(i32, i32)', number of elements is 0 - -warning: suspicious monomorphization of `volatile_copy_memory` intrinsic - --> $DIR/issue-39827.rs:28:9 - | -28 | volatile_copy_memory(&mut dst_empty, &dst_empty, 100); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_copy_memory' was specialized with type '()', number of elements is 100 - -warning: suspicious monomorphization of `volatile_copy_nonoverlapping_memory` intrinsic - --> $DIR/issue-39827.rs:29:9 - | -29 | / volatile_copy_nonoverlapping_memory(&mut dst_empty, &src_empty, -30 | | COUNT_100); - | |______________________________________________________^ - | - = note: 'volatile_copy_nonoverlapping_memory' was specialized with type '()', number of elements is 100 - -warning: suspicious monomorphization of `volatile_set_memory` intrinsic - --> $DIR/issue-39827.rs:31:9 - | -31 | volatile_set_memory(&mut dst_empty, 0, COUNT_100); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_set_memory' was specialized with type '()', number of elements is 100 - -warning: suspicious monomorphization of `volatile_set_memory` intrinsic - --> $DIR/issue-39827.rs:32:9 - | -32 | volatile_set_memory(&mut dst_pair, 0, COUNT_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_set_memory' was specialized with type '(i32, i32)', number of elements is 0 - -warning: suspicious monomorphization of `volatile_store` intrinsic - --> $DIR/issue-39827.rs:33:9 - | -33 | volatile_store(&mut dst_empty, ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_store' was specialized with zero-sized type '()' - -warning: suspicious monomorphization of `volatile_store` intrinsic - --> $DIR/issue-39827.rs:34:9 - | -34 | volatile_store(&mut dst_empty, src_empty); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_store' was specialized with zero-sized type '()' - -warning: suspicious monomorphization of `volatile_load` intrinsic - --> $DIR/issue-39827.rs:35:9 - | -35 | volatile_load(&src_empty); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: 'volatile_load' was specialized with zero-sized type '()' - From 0c97bbf424e976df4de1de0abf8c714095a2924b Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 Aug 2017 12:30:54 +0200 Subject: [PATCH 76/88] Remove some more cfg's --- src/bootstrap/check.rs | 43 ++++++----- src/librustc_driver/driver.rs | 55 +++++++------- src/librustc_driver/lib.rs | 130 ++++++++++++++++++---------------- src/librustc_driver/test.rs | 1 - 4 files changed, 121 insertions(+), 108 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index c65f5a9fb48b..95ac71d948bc 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -618,12 +618,6 @@ impl Step for Compiletest { if let Some(ref dir) = build.lldb_python_dir { cmd.arg("--lldb-python-dir").arg(dir); } - let llvm_config = build.llvm_config(target); - let llvm_version = output(Command::new(&llvm_config).arg("--version")); - cmd.arg("--llvm-version").arg(llvm_version); - if !build.is_rust_llvm(target) { - cmd.arg("--system-llvm"); - } cmd.args(&build.flags.cmd.test_args()); @@ -635,17 +629,32 @@ impl Step for Compiletest { cmd.arg("--quiet"); } - // Only pass correct values for these flags for the `run-make` suite as it - // requires that a C++ compiler was configured which isn't always the case. - if suite == "run-make" { - let llvm_components = output(Command::new(&llvm_config).arg("--components")); - let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); - cmd.arg("--cc").arg(build.cc(target)) - .arg("--cxx").arg(build.cxx(target).unwrap()) - .arg("--cflags").arg(build.cflags(target).join(" ")) - .arg("--llvm-components").arg(llvm_components.trim()) - .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); - } else { + if build.config.llvm_enabled { + let llvm_config = build.llvm_config(target); + let llvm_version = output(Command::new(&llvm_config).arg("--version")); + cmd.arg("--llvm-version").arg(llvm_version); + if !build.is_rust_llvm(target) { + cmd.arg("--system-llvm"); + } + + // Only pass correct values for these flags for the `run-make` suite as it + // requires that a C++ compiler was configured which isn't always the case. + if suite == "run-make" { + let llvm_components = output(Command::new(&llvm_config).arg("--components")); + let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); + cmd.arg("--cc").arg(build.cc(target)) + .arg("--cxx").arg(build.cxx(target).unwrap()) + .arg("--cflags").arg(build.cflags(target).join(" ")) + .arg("--llvm-components").arg(llvm_components.trim()) + .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); + } + } + if suite == "run-make" && !build.config.llvm_enabled { + println!("Ignoring run-make test suite"); + return; + } + + if suite != "run-make" { cmd.arg("--cc").arg("") .arg("--cxx").arg("") .arg("--cflags").arg("") diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c3de39fc9753..82ced4d1bcd0 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![cfg_attr(not(feature="llvm"), allow(dead_code))] + use rustc::hir::{self, map as hir_map}; use rustc::hir::lowering::lower_crate; use rustc::ich::Fingerprint; @@ -19,8 +21,6 @@ use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::middle::{self, stability, reachable}; -#[cfg(feature="llvm")] -use rustc::middle::dependency_format; use rustc::middle::privacy::AccessLevels; use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes}; use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas}; @@ -33,9 +33,7 @@ use rustc_incremental::{self, IncrementalHashesMap}; use rustc_resolve::{MakeGlobMap, Resolver}; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::{self, CStore}; -#[cfg(feature="llvm")] -use rustc_trans::back::{link, write}; -#[cfg(feature="llvm")] +use rustc_trans::back::write; use rustc_trans as trans; use rustc_typeck as typeck; use rustc_privacy; @@ -73,8 +71,6 @@ pub fn compile_input(sess: &Session, output: &Option, addl_plugins: Option>, control: &CompileController) -> CompileResult { - use rustc_trans::back::write::OngoingCrateTranslation; - macro_rules! controller_entry_point { ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ let state = &mut $make_state; @@ -91,10 +87,27 @@ pub fn compile_input(sess: &Session, }} } + if cfg!(not(feature="llvm")) { + use rustc::session::config::CrateType; + if !sess.opts.debugging_opts.no_trans && sess.opts.output_types.should_trans() { + sess.err("LLVM is not supported by this rustc. Please use -Z no-trans to compile") + } + + if sess.opts.crate_types.iter().all(|&t|{ + t != CrateType::CrateTypeRlib && t != CrateType::CrateTypeExecutable + }) { + sess.err( + "LLVM is not supported by this rustc, so non rlib libraries are not supported" + ); + } + + sess.abort_if_errors(); + } + // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = { + let (outputs, trans): (OutputFilenames, write::OngoingCrateTranslation) = { let krate = match phase_1_parse_input(control, sess, input) { Ok(krate) => krate, Err(mut parse_error) => { @@ -214,7 +227,6 @@ pub fn compile_input(sess: &Session, tcx.print_debug_stats(); } - #[cfg(feature="llvm")] let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map, &outputs); @@ -230,24 +242,14 @@ pub fn compile_input(sess: &Session, } } - #[cfg(not(feature="llvm"))] - { - let _ = incremental_hashes_map; - sess.err(&format!("LLVM is not supported by this rustc")); - sess.abort_if_errors(); - unreachable!(); - } - - #[cfg(feature="llvm")] Ok((outputs, trans)) })?? }; #[cfg(not(feature="llvm"))] { - let _ = outputs; - let _ = trans; - unreachable!(); + let (_, _) = (outputs, trans); + sess.fatal("LLVM is not supported by this rustc"); } #[cfg(feature="llvm")] @@ -504,7 +506,6 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } - #[cfg(feature="llvm")] fn state_after_llvm(input: &'a Input, session: &'tcx Session, out_dir: &'a Option, @@ -518,7 +519,6 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } - #[cfg(feature="llvm")] fn state_when_compilation_done(input: &'a Input, session: &'tcx Session, out_dir: &'a Option, @@ -1095,7 +1095,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, /// Run the translation phase to LLVM, after which the AST and analysis can /// be discarded. -#[cfg(feature="llvm")] pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, analysis: ty::CrateAnalysis, incremental_hashes_map: IncrementalHashesMap, @@ -1105,7 +1104,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(time_passes, "resolving dependency formats", - || dependency_format::calculate(tcx)); + || ::rustc::middle::dependency_format::calculate(tcx)); let translation = time(time_passes, @@ -1140,9 +1139,9 @@ pub fn phase_5_run_llvm_passes(sess: &Session, pub fn phase_6_link_output(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) { - time(sess.time_passes(), - "linking", - || link::link_binary(sess, trans, outputs, &trans.crate_name.as_str())); + time(sess.time_passes(), "linking", || { + ::rustc_trans::back::link::link_binary(sess, trans, outputs, &trans.crate_name.as_str()) + }); } fn escape_dep_filename(filename: &str) -> String { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index ea7af4e1ae13..4fc4b8dab2d9 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -28,15 +28,10 @@ #![feature(rustc_diagnostic_macros)] #![feature(set_stdio)] -#[cfg(not(feature="llvm"))] -extern crate ar; - extern crate arena; extern crate getopts; extern crate graphviz; extern crate env_logger; -#[cfg(not(feature="llvm"))] -extern crate owning_ref; extern crate libc; extern crate rustc; extern crate rustc_allocator; @@ -79,13 +74,9 @@ use rustc::session::config::nightly_options; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; -#[cfg(not(feature="llvm"))] -use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; use rustc::util::common::{time, ErrorReported}; -#[cfg(not(feature="llvm"))] -use rustc_back::target::Target; use serialize::json::ToJson; @@ -98,8 +89,6 @@ use std::ffi::OsString; use std::io::{self, Read, Write}; use std::iter::repeat; use std::path::PathBuf; -#[cfg(not(feature="llvm"))] -use std::path::Path; use std::process::{self, Command, Stdio}; use std::rc::Rc; use std::str; @@ -112,15 +101,11 @@ use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; use syntax_pos::{DUMMY_SP, MultiSpan}; -#[cfg(not(feature="llvm"))] -use owning_ref::{OwningRef, ErasedBoxRef}; - #[cfg(test)] pub mod test; pub mod driver; pub mod pretty; -#[cfg(feature="llvm")] pub mod target_features; mod derive_registrar; @@ -167,67 +152,98 @@ pub fn run(run_compiler: F) -> isize } #[cfg(not(feature="llvm"))] -pub struct NoLLvmMetadataLoader; - -#[cfg(not(feature="llvm"))] -pub use NoLLvmMetadataLoader as MetadataLoader; +pub use no_llvm_metadata_loader::NoLLvmMetadataLoader as MetadataLoader; #[cfg(feature="llvm")] pub use rustc_trans::LlvmMetadataLoader as MetadataLoader; #[cfg(not(feature="llvm"))] -impl MetadataLoaderTrait for NoLLvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { - use std::fs::File; - use std::io; - use self::ar::Archive; +mod no_llvm_metadata_loader{ + extern crate ar; + extern crate owning_ref; + + use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait; + use rustc_back::target::Target; + use std::io; + use std::fs::File; + use std::path::Path; + + use self::ar::Archive; + use self::owning_ref::{OwningRef, ErasedBoxRef}; - let file = File::open(filename).map_err(|e|format!("metadata file open err: {:?}", e))?; - let mut archive = Archive::new(file); + pub struct NoLLvmMetadataLoader; - while let Some(entry_result) = archive.next_entry() { - let mut entry = entry_result.map_err(|e|format!("metadata section read err: {:?}", e))?; - if entry.header().identifier() == "rust.metadata.bin" { - let mut buf = Vec::new(); - io::copy(&mut entry, &mut buf).unwrap(); - let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); - return Ok(buf.map_owner_box().erase_owner()); + impl MetadataLoaderTrait for NoLLvmMetadataLoader { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { + let file = File::open(filename).map_err(|e|format!("metadata file open err: {:?}", e))?; + let mut archive = Archive::new(file); + + while let Some(entry_result) = archive.next_entry() { + let mut entry = entry_result.map_err(|e|format!("metadata section read err: {:?}", e))?; + if entry.header().identifier() == "rust.metadata.bin" { + let mut buf = Vec::new(); + io::copy(&mut entry, &mut buf).unwrap(); + let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); + return Ok(buf.map_owner_box().erase_owner()); + } } + + Err("Couldnt find metadata section".to_string()) } - Err("Couldnt find metadata section".to_string()) - } - - fn get_dylib_metadata(&self, - _target: &Target, - _filename: &Path) - -> Result, String> { - panic!("Dylib metadata loading not supported without LLVM") + fn get_dylib_metadata(&self, + _target: &Target, + _filename: &Path) + -> Result, String> { + panic!("Dylib metadata loading not supported without LLVM") + } } } -#[cfg(feature="llvm")] +#[cfg(not(feature="llvm"))] mod rustc_trans { + use syntax_pos::symbol::Symbol; + use rustc::session::Session; + use rustc::session::config::{PrintRequest, OutputFilenames}; + use rustc::ty::{TyCtxt, CrateAnalysis}; use rustc::ty::maps::Providers; + use rustc_incremental::IncrementalHashesMap; + + use self::back::write::OngoingCrateTranslation; + pub fn init(_sess: &Session) {} pub fn enable_llvm_debug() {} pub fn provide(_providers: &mut Providers) {} - pub struct CrateTranslation(()); - pub mod back { - pub mod write { - pub struct OngoingCrateTranslation(()); - } - } - mod diagnostics { - register_long_diagnostics! {} + pub fn print_version() {} + pub fn print_passes() {} + pub fn print(_req: PrintRequest, _sess: &Session) {} + pub fn target_features(_sess: &Session) -> Vec { vec![] } + + pub fn trans_crate<'a, 'tcx>( + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _analysis: CrateAnalysis, + _incr_hashes_map: IncrementalHashesMap, + _output_filenames: &OutputFilenames + ) -> OngoingCrateTranslation { + OngoingCrateTranslation(()) } - pub use diagnostics::DIAGNOSTICS; + pub struct CrateTranslation(()); + + pub mod back { + pub mod write { + pub struct OngoingCrateTranslation(pub (in ::rustc_trans) ()); + + pub const RELOC_MODEL_ARGS: [(&'static str, ()); 0] = []; + pub const CODE_GEN_MODEL_ARGS: [(&'static str, ()); 0] = []; + } + } + + __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } } // Parse args and run the compiler. This is the primary entry point for rustc. // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. -#[cfg_attr(not(feature="llvm"), allow(unused_mut))] pub fn run_compiler<'a>(args: &[String], callbacks: &mut CompilerCalls<'a>, file_loader: Option>, @@ -282,7 +298,6 @@ pub fn run_compiler<'a>(args: &[String], rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg); - #[cfg(feature="llvm")] target_features::add_configuration(&mut cfg, &sess); sess.parse_sess.config = cfg; @@ -535,7 +550,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { Compilation::Continue } - #[cfg_attr(not(feature="llvm"), allow(unused_mut))] fn no_input(&mut self, matches: &getopts::Matches, sopts: &config::Options, @@ -562,7 +576,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { rustc_trans::init(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg.clone()); - #[cfg(feature="llvm")] target_features::add_configuration(&mut cfg, &sess); sess.parse_sess.config = cfg; let should_stop = @@ -816,7 +829,6 @@ impl RustcDefaultCalls { } PrintRequest::RelocationModels => { println!("Available relocation models:"); - #[cfg(feature="llvm")] for &(name, _) in rustc_trans::back::write::RELOC_MODEL_ARGS.iter() { println!(" {}", name); } @@ -824,17 +836,13 @@ impl RustcDefaultCalls { } PrintRequest::CodeModels => { println!("Available code models:"); - #[cfg(feature="llvm")] for &(name, _) in rustc_trans::back::write::CODE_GEN_MODEL_ARGS.iter(){ println!(" {}", name); } println!(""); } PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => { - #[cfg(feature="llvm")] rustc_trans::print(*req, sess); - #[cfg(not(feature="llvm"))] - panic!("LLVM not supported by this rustc") } } } @@ -873,7 +881,6 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); - #[cfg(feature="llvm")] rustc_trans::print_version(); } } @@ -1171,7 +1178,6 @@ pub fn handle_options(args: &[String]) -> Option { } if cg_flags.contains(&"passes=list".to_string()) { - #[cfg(feature="llvm")] rustc_trans::print_passes(); return None; } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f3f934ccde50..b187cdaa480e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -14,7 +14,6 @@ use driver; use rustc::dep_graph::DepGraph; use rustc_lint; use rustc_resolve::MakeGlobMap; -#[cfg(feature="llvm")] use rustc_trans; use rustc::middle::lang_items; use rustc::middle::free_region::FreeRegionMap; From 6135b2dff5951605d6f3d1189b280532e629d595 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 Aug 2017 15:56:35 +0200 Subject: [PATCH 77/88] Fix tidy errors --- src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 82ced4d1bcd0..84b1ade6d8b2 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -95,7 +95,7 @@ pub fn compile_input(sess: &Session, if sess.opts.crate_types.iter().all(|&t|{ t != CrateType::CrateTypeRlib && t != CrateType::CrateTypeExecutable - }) { + }) && !sess.opts.crate_types.is_empty() { sess.err( "LLVM is not supported by this rustc, so non rlib libraries are not supported" ); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4fc4b8dab2d9..f8cd2280cafe 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -157,28 +157,36 @@ pub use no_llvm_metadata_loader::NoLLvmMetadataLoader as MetadataLoader; pub use rustc_trans::LlvmMetadataLoader as MetadataLoader; #[cfg(not(feature="llvm"))] -mod no_llvm_metadata_loader{ +mod no_llvm_metadata_loader { extern crate ar; extern crate owning_ref; - + use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait; use rustc_back::target::Target; use std::io; use std::fs::File; use std::path::Path; - + use self::ar::Archive; use self::owning_ref::{OwningRef, ErasedBoxRef}; pub struct NoLLvmMetadataLoader; impl MetadataLoaderTrait for NoLLvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { - let file = File::open(filename).map_err(|e|format!("metadata file open err: {:?}", e))?; + fn get_rlib_metadata( + &self, + _: &Target, + filename: &Path + ) -> Result, String> { + let file = File::open(filename).map_err(|e| { + format!("metadata file open err: {:?}", e) + })?; let mut archive = Archive::new(file); while let Some(entry_result) = archive.next_entry() { - let mut entry = entry_result.map_err(|e|format!("metadata section read err: {:?}", e))?; + let mut entry = entry_result.map_err(|e| { + format!("metadata section read err: {:?}", e) + })?; if entry.header().identifier() == "rust.metadata.bin" { let mut buf = Vec::new(); io::copy(&mut entry, &mut buf).unwrap(); From bf0eb6a22d2ae9630f5e1223d775885e0d880d91 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 Aug 2017 16:47:47 +0200 Subject: [PATCH 78/88] Change a #[cfg()] to a cfg!() --- src/librustc_driver/driver.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 84b1ade6d8b2..51121669aef4 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -246,8 +246,7 @@ pub fn compile_input(sess: &Session, })?? }; - #[cfg(not(feature="llvm"))] - { + if cfg!(not(feature="llvm")) { let (_, _) = (outputs, trans); sess.fatal("LLVM is not supported by this rustc"); } From 1c28cf5b68e38d58ad14d0e145746a0e435cfe23 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 Aug 2017 16:49:09 +0200 Subject: [PATCH 79/88] Change run-make ignore message --- src/bootstrap/check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 95ac71d948bc..7b9b316a2a4b 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -650,7 +650,7 @@ impl Step for Compiletest { } } if suite == "run-make" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite"); + println!("Ignoring run-make test suite as they generally dont work without LLVM"); return; } From 61ab991405fe848c4c3b48b7fece443d84bc893b Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 Aug 2017 16:50:17 +0200 Subject: [PATCH 80/88] Update driver.rs --- src/librustc_driver/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 51121669aef4..0e08849b1ffb 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -107,7 +107,7 @@ pub fn compile_input(sess: &Session, // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, trans): (OutputFilenames, write::OngoingCrateTranslation) = { + let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = { let krate = match phase_1_parse_input(control, sess, input) { Ok(krate) => krate, Err(mut parse_error) => { From a2adb7db6861a7e3bab1d3f11b33a5935984d366 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 13 Aug 2017 16:59:54 +0300 Subject: [PATCH 81/88] ast_validation: forbid "nonstandard" literal patterns Since #42886, macros can create "nonstandard" PatKind::Lit patterns, that contain path expressions instead of the usual literal expr. These can cause trouble, including ICEs. We *could* map these nonstandard patterns to PatKind::Path patterns during HIR lowering, but that would be much effort for little gain, and I think is too risky for beta. So let's just forbid them during AST validation. Fixes #43250. --- src/librustc_passes/ast_validation.rs | 27 +++++++++++++++++++++------ src/test/compile-fail/issue-43250.rs | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/issue-43250.rs diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2643ed2a3c07..b22f8112d7a3 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -94,10 +94,25 @@ impl<'a> AstValidator<'a> { } } - /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus) - fn check_expr_within_pat(&self, expr: &Expr) { + /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus), + /// or path for ranges. + /// + /// FIXME: do we want to allow expr -> pattern conversion to create path expressions? + /// That means making this work: + /// + /// ```rust,ignore (FIXME) + /// struct S; + /// macro_rules! m { + /// ($a:expr) => { + /// let $a = S; + /// } + /// } + /// m!(S); + /// ``` + fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { match expr.node { - ExprKind::Lit(..) | ExprKind::Path(..) => {} + ExprKind::Lit(..) => {} + ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, ref inner) if match inner.node { ExprKind::Lit(_) => true, _ => false } => {} _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \ @@ -332,11 +347,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_pat(&mut self, pat: &'a Pat) { match pat.node { PatKind::Lit(ref expr) => { - self.check_expr_within_pat(expr); + self.check_expr_within_pat(expr, false); } PatKind::Range(ref start, ref end, _) => { - self.check_expr_within_pat(start); - self.check_expr_within_pat(end); + self.check_expr_within_pat(start, true); + self.check_expr_within_pat(end, true); } _ => {} } diff --git a/src/test/compile-fail/issue-43250.rs b/src/test/compile-fail/issue-43250.rs new file mode 100644 index 000000000000..e1d34f339dc6 --- /dev/null +++ b/src/test/compile-fail/issue-43250.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. + +fn main() { + let mut y; + const C: u32 = 0; + macro_rules! m { + ($a:expr) => { + let $a = 0; + } + } + m!(y); + //~^ ERROR arbitrary expressions aren't allowed in patterns + m!(C); + //~^ ERROR arbitrary expressions aren't allowed in patterns +} From 005bc2c3a5e20c14638e5df3f2338cbbb949c760 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 Aug 2017 18:51:07 +0200 Subject: [PATCH 82/88] Fix error --- src/librustc_driver/driver.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 0e08849b1ffb..fa5dcaa9f815 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -71,6 +71,7 @@ pub fn compile_input(sess: &Session, output: &Option, addl_plugins: Option>, control: &CompileController) -> CompileResult { + use rustc_trans::back::write::OngoingCrateTranslation; macro_rules! controller_entry_point { ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ let state = &mut $make_state; From 81f481d3c6687b3693eb447f6b1b095d7389bfb9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Aug 2017 17:06:17 -0700 Subject: [PATCH 83/88] Don't inline debug methods The inner methods aren't inlined, so this puts more pressure on LLVM for literally no benefit. Closes #43843 --- src/libcore/fmt/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 193c8b9f925f..97839844087c 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1347,7 +1347,6 @@ impl<'a> Formatter<'a> { /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] - #[inline] pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> { builders::debug_struct_new(self, name) } @@ -1375,7 +1374,6 @@ impl<'a> Formatter<'a> { /// println!("{:?}", Foo(10, "Hello World".to_string())); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] - #[inline] pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> { builders::debug_tuple_new(self, name) } @@ -1400,7 +1398,6 @@ impl<'a> Formatter<'a> { /// println!("{:?}", Foo(vec![10, 11])); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] - #[inline] pub fn debug_list<'b>(&'b mut self) -> DebugList<'b, 'a> { builders::debug_list_new(self) } @@ -1425,7 +1422,6 @@ impl<'a> Formatter<'a> { /// println!("{:?}", Foo(vec![10, 11])); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] - #[inline] pub fn debug_set<'b>(&'b mut self) -> DebugSet<'b, 'a> { builders::debug_set_new(self) } @@ -1450,7 +1446,6 @@ impl<'a> Formatter<'a> { /// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] - #[inline] pub fn debug_map<'b>(&'b mut self) -> DebugMap<'b, 'a> { builders::debug_map_new(self) } From 6fd7d8586c606e3ca03511bd915946a8e75c2db7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 11 Aug 2017 12:35:54 +0200 Subject: [PATCH 84/88] Fix some merge fallout. --- src/librustc/hir/def_id.rs | 7 ------- src/librustc/middle/dead.rs | 2 -- src/librustc/ty/context.rs | 1 - src/librustc_borrowck/borrowck/gather_loans/mod.rs | 3 ++- src/librustc_lint/unused.rs | 4 ++-- src/librustc_privacy/lib.rs | 2 -- 6 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index bb3b248674ab..7f76e1bf770b 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -201,11 +201,4 @@ impl DefId { pub fn is_local(&self) -> bool { self.krate == LOCAL_CRATE } - - pub fn invalid() -> DefId { - DefId { - krate: INVALID_CRATE, - index: CRATE_DEF_INDEX, - } - } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index ed04186eb286..8a2b115e58d3 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -119,8 +119,6 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, def: Def, pats: &[codemap::Spanned]) { - - let variant = match self.tables.node_id_to_type(lhs.hir_id).sty { ty::TyAdt(adt, _) => adt.variant_of_def(def), _ => span_bug!(lhs.span, "non-ADT in struct pattern") diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d93750ec04e0..2ef65a26b4ba 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -285,7 +285,6 @@ pub struct LocalTableInContextMut<'a, V: 'a> { } impl<'a, V> LocalTableInContextMut<'a, V> { - pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> { validate_hir_id_for_typeck_tables(self.local_id_root, id, true); self.data.get_mut(&id.local_id) diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 7a89d1f09d39..35af83c8ae23 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -449,7 +449,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } None } - LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => { + LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { + let local_id = self.tcx().hir.def_index_to_node_id(var_id); self.tcx().used_mut_nodes.borrow_mut().insert(local_id); None } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 65973d99c547..9b90360109ee 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -155,12 +155,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let maybe_def = match expr.node { hir::ExprCall(ref callee, _) => { match callee.node { - hir::ExprPath(ref qpath) => Some(cx.tables.qpath_def(qpath, callee.id)), + hir::ExprPath(ref qpath) => Some(cx.tables.qpath_def(qpath, callee.hir_id)), _ => None } }, hir::ExprMethodCall(..) => { - cx.tables.type_dependent_defs.get(&expr.id).cloned() + cx.tables.type_dependent_defs().get(expr.hir_id).cloned() }, _ => { None } }; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 373d7911cf93..76a8850291f8 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1655,10 +1655,8 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert_eq!(krate, LOCAL_CRATE); let krate = tcx.hir.krate(); - let empty_tables = ty::TypeckTables::empty(None); - // Check privacy of names not checked in previous compilation stages. let mut visitor = NamePrivacyVisitor { tcx: tcx, From f2df18579b139216f15a2ea17e27bb980f02a0ab Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 14 Aug 2017 12:04:52 +0200 Subject: [PATCH 85/88] Mark closures return via impl-trait as reachable. --- src/librustc/middle/reachable.rs | 3 +++ src/librustc_privacy/lib.rs | 1 + src/test/run-pass/impl-trait/auxiliary/xcrate.rs | 11 +++++++++++ src/test/run-pass/impl-trait/xcrate.rs | 1 + 4 files changed, 16 insertions(+) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index df828c8d8e71..4a608c69d14c 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -296,6 +296,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ImplItemKind::Type(_) => {} } } + hir_map::NodeExpr(&hir::Expr { node: hir::ExprClosure(.., body, _), .. }) => { + self.visit_nested_body(body); + } // Nothing to recurse on for these hir_map::NodeForeignItem(_) | hir_map::NodeVariant(_) | diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 9fa5fea20d91..81cf22e3b377 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -448,6 +448,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()), ty::TyProjection(ref proj) => Some(proj.item_def_id), ty::TyFnDef(def_id, ..) | + ty::TyClosure(def_id, ..) | ty::TyAnon(def_id, _) => Some(def_id), _ => None }; diff --git a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs index be353f6d563a..e9074f8c2309 100644 --- a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs +++ b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs @@ -13,3 +13,14 @@ pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 { move |b| move |c| move |d| a + b + c + d } + +fn some_internal_fn() -> u32 { + 1 +} + +// See #40839 +pub fn return_closure_accessing_internal_fn() -> impl Fn() -> u32 { + || { + some_internal_fn() + 1 + } +} diff --git a/src/test/run-pass/impl-trait/xcrate.rs b/src/test/run-pass/impl-trait/xcrate.rs index fe3ed7b3465f..6d00c46fa350 100644 --- a/src/test/run-pass/impl-trait/xcrate.rs +++ b/src/test/run-pass/impl-trait/xcrate.rs @@ -14,4 +14,5 @@ extern crate xcrate; fn main() { assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10); + xcrate::return_closure_accessing_internal_fn()(); } From 60377e48f0416daa9120fd057ce55a0024cc458f Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 12 Aug 2017 23:48:24 +0800 Subject: [PATCH 86/88] save-analysis: Remove path span extraction methods from SpanUtils Use the `span` field in PathSegment and TyParam instead. Fix #43796. Close #41478. --- src/librustc_save_analysis/dump_visitor.rs | 44 ++-------- src/librustc_save_analysis/span_utils.rs | 85 ------------------- src/test/run-make/issues-41478-43796/Makefile | 8 ++ src/test/run-make/issues-41478-43796/a.rs | 19 +++++ 4 files changed, 33 insertions(+), 123 deletions(-) create mode 100644 src/test/run-make/issues-41478-43796/Makefile create mode 100644 src/test/run-make/issues-41478-43796/a.rs diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 4740f9a0d5a5..a8b34e8682b9 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -27,7 +27,6 @@ use rustc::hir::def::Def as HirDef; use rustc::hir::def_id::DefId; use rustc::hir::map::Node; -use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fx::FxHashSet; @@ -62,7 +61,6 @@ macro_rules! down_cast_data { pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> { save_ctxt: SaveContext<'l, 'tcx>, - sess: &'l Session, tcx: TyCtxt<'l, 'tcx, 'tcx>, dumper: &'ll mut JsonDumper, @@ -84,7 +82,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { -> DumpVisitor<'l, 'tcx, 'll, O> { let span_utils = SpanUtils::new(&save_ctxt.tcx.sess); DumpVisitor { - sess: &save_ctxt.tcx.sess, tcx: save_ctxt.tcx, save_ctxt: save_ctxt, dumper: dumper, @@ -147,39 +144,15 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { // For each prefix, we return the span for the last segment in the prefix and // a str representation of the entire prefix. fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> { - let spans = self.span.spans_for_path_segments(path); let segments = &path.segments[if path.is_global() { 1 } else { 0 }..]; - // Paths to enums seem to not match their spans - the span includes all the - // variants too. But they seem to always be at the end, so I hope we can cope with - // always using the first ones. So, only error out if we don't have enough spans. - // What could go wrong...? - if spans.len() < segments.len() { - if generated_code(path.span) { - return vec![]; - } - error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:", - path_to_string(path), - spans.len(), - segments.len()); - for s in &spans { - let loc = self.sess.codemap().lookup_char_pos(s.lo); - error!(" '{}' in {}, line {}", - self.span.snippet(*s), - loc.file.name, - loc.line); - } - error!(" master span: {:?}: `{}`", path.span, self.span.snippet(path.span)); - return vec![]; - } - - let mut result: Vec<(Span, String)> = vec![]; + let mut result = Vec::with_capacity(segments.len()); let mut segs = vec![]; - for (i, (seg, span)) in segments.iter().zip(&spans).enumerate() { + for (i, seg) in segments.iter().enumerate() { segs.push(seg.clone()); let sub_path = ast::Path { - span: *span, // span for the last segment + span: seg.span, // span for the last segment segments: segs, }; let qualname = if i == 0 && path.is_global() { @@ -187,7 +160,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } else { path_to_string(&sub_path) }; - result.push((*span, qualname)); + result.push((seg.span, qualname)); segs = sub_path.segments; } @@ -436,13 +409,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { full_span: Span, prefix: &str, id: NodeId) { - // We can't only use visit_generics since we don't have spans for param - // bindings, so we reparse the full_span to get those sub spans. - // However full span is the entire enum/fn/struct block, so we only want - // the first few to match the number of generics we're looking for. - let param_sub_spans = self.span.spans_for_ty_params(full_span, - (generics.ty_params.len() as isize)); - for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) { + for param in &generics.ty_params { + let param_ss = param.span; let name = escape(self.span.snippet(param_ss)); // Append $id to name to make sure each one is unique let qualname = format!("{}::{}${}", diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index e771da2ed4ce..631907b28f8b 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -16,7 +16,6 @@ use std::cell::Cell; use std::env; use std::path::Path; -use syntax::ast; use syntax::parse::lexer::{self, StringReader}; use syntax::parse::token::{self, Token}; use syntax::symbol::keywords; @@ -207,75 +206,6 @@ impl<'a> SpanUtils<'a> { result } - // Reparse span and return an owned vector of sub spans of the first limit - // identifier tokens in the given nesting level. - // example with Foo, Bar> - // Nesting = 0: all idents outside of angle brackets: [Foo] - // Nesting = 1: idents within one level of angle brackets: [Bar, Bar] - pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec { - let mut result: Vec = vec![]; - - let mut toks = self.retokenise_span(span); - // We keep track of how many brackets we're nested in - let mut angle_count: isize = 0; - let mut bracket_count: isize = 0; - let mut found_ufcs_sep = false; - loop { - let ts = toks.real_token(); - if ts.tok == token::Eof { - if angle_count != 0 || bracket_count != 0 { - if generated_code(span) { - return vec![]; - } - let loc = self.sess.codemap().lookup_char_pos(span.lo); - span_bug!(span, - "Mis-counted brackets when breaking path? \ - Parsing '{}' in {}, line {}", - self.snippet(span), - loc.file.name, - loc.line); - } - return result - } - if (result.len() as isize) == limit { - return result; - } - bracket_count += match ts.tok { - token::OpenDelim(token::Bracket) => 1, - token::CloseDelim(token::Bracket) => -1, - _ => 0, - }; - if bracket_count > 0 { - continue; - } - angle_count += match ts.tok { - token::Lt => 1, - token::Gt => -1, - token::BinOp(token::Shl) => 2, - token::BinOp(token::Shr) => -2, - _ => 0, - }; - - // Ignore the `>::` in `::AssocTy`. - - // The root cause of this hack is that the AST representation of - // qpaths is horrible. It treats ::C as a path with two - // segments, B and C and notes that there is also a self type A at - // position 0. Because we don't have spans for individual idents, - // only the whole path, we have to iterate over the tokens in the - // path, trying to pull out the non-nested idents (e.g., avoiding 'a - // in `>::C`). So we end up with a span for `B>::C` from - // the start of the first ident to the end of the path. - if !found_ufcs_sep && angle_count == -1 { - found_ufcs_sep = true; - angle_count += 1; - } - if ts.tok.is_ident() && angle_count == nesting { - result.push(ts.sp); - } - } - } - pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option { let mut toks = self.retokenise_span(span); let mut prev = toks.real_token(); @@ -330,21 +260,6 @@ impl<'a> SpanUtils<'a> { } } - - // Returns a list of the spans of idents in a path. - // E.g., For foo::bar::baz, we return [foo, bar, baz] (well, their spans) - pub fn spans_for_path_segments(&self, path: &ast::Path) -> Vec { - self.spans_with_brackets(path.span, 0, -1) - } - - // Return an owned vector of the subspans of the param identifier - // tokens found in span. - pub fn spans_for_ty_params(&self, span: Span, number: isize) -> Vec { - // Type params are nested within one level of brackets: - // i.e. we want Vec from Foo> - self.spans_with_brackets(span, 1, number) - } - // // Return the name for a macro definition (identifier after first `!`) // pub fn span_for_macro_def_name(&self, span: Span) -> Option { // let mut toks = self.retokenise_span(span); diff --git a/src/test/run-make/issues-41478-43796/Makefile b/src/test/run-make/issues-41478-43796/Makefile new file mode 100644 index 000000000000..f9735253ab68 --- /dev/null +++ b/src/test/run-make/issues-41478-43796/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +all: + # Work in /tmp, because we need to create the `save-analysis-temp` folder. + cp a.rs $(TMPDIR)/ + cd $(TMPDIR) && $(RUSTC) -Zsave-analysis $(TMPDIR)/a.rs 2> $(TMPDIR)/stderr.txt || ( cat $(TMPDIR)/stderr.txt && exit 1 ) + [ ! -s $(TMPDIR)/stderr.txt ] || ( cat $(TMPDIR)/stderr.txt && exit 1 ) + [ -f $(TMPDIR)/save-analysis/liba.json ] || ( ls -la $(TMPDIR) && exit 1 ) diff --git a/src/test/run-make/issues-41478-43796/a.rs b/src/test/run-make/issues-41478-43796/a.rs new file mode 100644 index 000000000000..9d95f8b25852 --- /dev/null +++ b/src/test/run-make/issues-41478-43796/a.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_type = "lib"] +pub struct V(S); +pub trait An { + type U; +} +pub trait F { +} +impl F for V<::U> { +} From a3a06b16776bb84d442a44187d9729e51ce0fece Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 14 Aug 2017 13:23:56 +0300 Subject: [PATCH 87/88] remove the "defaulted unit" type bit during writeback The defaulted unit bit is only relevant for the surrounding inference context, and can cause trouble, including spurious lints and ICEs, outside of it. Fixes #43853. --- src/librustc/infer/resolve.rs | 10 +++++++++- src/librustc/ty/context.rs | 2 +- src/librustc/ty/flags.rs | 5 ++++- src/librustc/ty/mod.rs | 2 +- src/test/run-pass/issue-43853.rs | 24 ++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/issue-43853.rs diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 2e8b843d07b3..6a1f8f1d0692 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -111,8 +111,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() { + if !t.needs_infer() && !ty::keep_local(&t) { t // micro-optimize -- if there is nothing in this type that this fold affects... + // ^ we need to have the `keep_local` check to un-default + // defaulted tuples. } else { let t = self.infcx.shallow_resolve(t); match t.sty { @@ -131,6 +133,12 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> ty::TyInfer(_) => { bug!("Unexpected type in full type resolver: {:?}", t); } + ty::TyTuple(tys, true) => { + // Un-default defaulted tuples - we are going to a + // different infcx, and the default will just cause + // pollution. + self.tcx().intern_tup(tys, false) + } _ => { t.super_fold_with(self) } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6b9cbabf20e9..003af204f1ed 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1195,7 +1195,7 @@ macro_rules! direct_interners { } } -fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { +pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { x.has_type_flags(ty::TypeFlags::KEEP_IN_LOCAL_TCX) } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index ce2bb23660ce..31ed61a919e7 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -151,7 +151,10 @@ impl FlagComputation { self.add_ty(m.ty); } - &ty::TyTuple(ref ts, _) => { + &ty::TyTuple(ref ts, is_default) => { + if is_default { + self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX); + } self.add_tys(&ts[..]); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 28a73f4a4d38..b91eb3ec68ff 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -76,7 +76,7 @@ pub use self::sty::TypeVariants::*; pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; -pub use self::context::{TyCtxt, GlobalArenas, tls}; +pub use self::context::{TyCtxt, GlobalArenas, tls, keep_local}; pub use self::context::{Lift, TypeckTables}; pub use self::instance::{Instance, InstanceDef}; diff --git a/src/test/run-pass/issue-43853.rs b/src/test/run-pass/issue-43853.rs new file mode 100644 index 000000000000..f55d584ea24f --- /dev/null +++ b/src/test/run-pass/issue-43853.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. + +use std::panic; + +fn test() { + wait(|| panic!()); +} + +fn wait T>(f: F) -> F::Output { + From::from(f()) +} + +fn main() { + let result = panic::catch_unwind(move || test()); + assert!(result.is_err()); +} From 3b92b97bfb98456cf2c1c0b87237a6eac8857e42 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 14 Aug 2017 14:56:35 +0200 Subject: [PATCH 88/88] Fix unused variable warnings in builds disabled debug-assertions. --- src/librustc/ty/context.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2ef65a26b4ba..6e8a7ca35a84 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -226,8 +226,7 @@ pub struct LocalTableInContext<'a, V: 'a> { fn validate_hir_id_for_typeck_tables(local_id_root: Option, hir_id: hir::HirId, mut_access: bool) { - #[cfg(debug_assertions)] - { + if cfg!(debug_assertions) { if let Some(local_id_root) = local_id_root { if hir_id.owner != local_id_root.index { ty::tls::with(|tcx| {