From 72ac8ce9aa50d4456239755076a5dd869232006e Mon Sep 17 00:00:00 2001 From: CrLF0710 Date: Sun, 7 Jul 2019 12:16:13 +0800 Subject: [PATCH 01/43] Stablize Euclidean Modulo (feature euclidean_division) --- src/libcore/num/mod.rs | 48 ++++++++++++++-------------------------- src/libcore/tests/lib.rs | 1 - src/libstd/f32.rs | 6 ++--- src/libstd/f64.rs | 6 ++--- 4 files changed, 20 insertions(+), 41 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 72552c5a0b0f0..67e30e7ffcb24 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -717,13 +717,12 @@ returning `None` if `rhs == 0` or the division results in overflow. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!((", stringify!($SelfT), "::min_value() + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euclid(-1), None); assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -774,14 +773,13 @@ if `rhs == 0` or the division results in overflow. Basic usage: ``` -#![feature(euclidean_division)] use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1210,11 +1208,10 @@ This function will panic if `rhs` is 0. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); assert_eq!((-128i8).wrapping_div_euclid(-1), -128); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1269,11 +1266,10 @@ This function will panic if `rhs` is 0. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1566,7 +1562,6 @@ This function will panic if `rhs` is 0. Basic usage: ``` -#![feature(euclidean_division)] use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); @@ -1574,7 +1569,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringi "::MIN, true)); ```"), #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { @@ -1636,13 +1631,12 @@ This function will panic if `rhs` is 0. Basic usage: ``` -#![feature(euclidean_division)] use std::", stringify!($SelfT), "; assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1873,7 +1867,6 @@ This function will panic if `rhs` is 0. Basic usage: ``` -#![feature(euclidean_division)] let a: ", stringify!($SelfT), " = 7; // or any other integer type let b = 4; @@ -1882,7 +1875,7 @@ assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1913,7 +1906,6 @@ This function will panic if `rhs` is 0. Basic usage: ``` -#![feature(euclidean_division)] let a: ", stringify!($SelfT), " = 7; // or any other integer type let b = 4; @@ -1922,7 +1914,7 @@ assert_eq!((-a).rem_euclid(b), 1); assert_eq!(a.rem_euclid(-b), 3); assert_eq!((-a).rem_euclid(-b), 1); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2753,11 +2745,10 @@ if `rhs == 0`. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2805,11 +2796,10 @@ if `rhs == 0`. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3127,10 +3117,9 @@ is exactly equal to `self.wrapping_div(rhs)`. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3179,10 +3168,9 @@ is exactly equal to `self.wrapping_rem(rhs)`. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3448,11 +3436,10 @@ This function will panic if `rhs` is 0. Basic usage ``` -#![feature(euclidean_division)] assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); ```"), #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { @@ -3508,11 +3495,10 @@ This function will panic if `rhs` is 0. Basic usage ``` -#![feature(euclidean_division)] assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); ```"), #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { @@ -3696,10 +3682,9 @@ is exactly equal to `self / rhs`. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3722,10 +3707,9 @@ is exactly equal to `self % rhs`. Basic usage: ``` -#![feature(euclidean_division)] assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type ```"), - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bf072a9243b51..955ae155310a1 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -4,7 +4,6 @@ #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(dec2flt)] -#![feature(euclidean_division)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(flt2dec)] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7254c62161161..f649170c40372 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -256,7 +256,6 @@ impl f32 { /// # Examples /// /// ``` - /// #![feature(euclidean_division)] /// let a: f32 = 7.0; /// let b = 4.0; /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 @@ -265,7 +264,7 @@ impl f32 { /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 /// ``` #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f32) -> f32 { let q = (self / rhs).trunc(); if self % rhs < 0.0 { @@ -288,7 +287,6 @@ impl f32 { /// # Examples /// /// ``` - /// #![feature(euclidean_division)] /// let a: f32 = 7.0; /// let b = 4.0; /// assert_eq!(a.rem_euclid(b), 3.0); @@ -299,7 +297,7 @@ impl f32 { /// assert!((-std::f32::EPSILON).rem_euclid(3.0) != 0.0); /// ``` #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f32) -> f32 { let r = self % rhs; if r < 0.0 { diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f8bb36ad0a89e..f61630997dcdb 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -232,7 +232,6 @@ impl f64 { /// # Examples /// /// ``` - /// #![feature(euclidean_division)] /// let a: f64 = 7.0; /// let b = 4.0; /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 @@ -241,7 +240,7 @@ impl f64 { /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 /// ``` #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn div_euclid(self, rhs: f64) -> f64 { let q = (self / rhs).trunc(); if self % rhs < 0.0 { @@ -264,7 +263,6 @@ impl f64 { /// # Examples /// /// ``` - /// #![feature(euclidean_division)] /// let a: f64 = 7.0; /// let b = 4.0; /// assert_eq!(a.rem_euclid(b), 3.0); @@ -275,7 +273,7 @@ impl f64 { /// assert!((-std::f64::EPSILON).rem_euclid(3.0) != 0.0); /// ``` #[inline] - #[unstable(feature = "euclidean_division", issue = "49048")] + #[stable(feature = "euclidean_division", since = "1.38.0")] pub fn rem_euclid(self, rhs: f64) -> f64 { let r = self % rhs; if r < 0.0 { From 5397dfce77f3b3d903580843af3da37615a44e74 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 8 Jul 2019 18:12:06 +0200 Subject: [PATCH 02/43] =?UTF-8?q?Remove=20obsolete=20=E2=80=9Cshould=20not?= =?UTF-8?q?=20have=20to=20exist=E2=80=9D=20reasons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/liballoc/slice.rs | 4 +--- src/liballoc/str.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index bc4ae16798478..9a23cdc1768f3 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -595,9 +595,7 @@ pub trait SliceConcat: Sized { fn join(slice: &[Self], sep: &Separator) -> Self::Output; } -#[unstable(feature = "slice_concat_ext", - reason = "trait should not have to exist", - issue = "27747")] +#[unstable(feature = "slice_concat_ext", issue = "27747")] impl> SliceConcat for V { type Output = Vec; diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 37a1046d0942d..b6512487ddd56 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -71,9 +71,7 @@ pub use core::str::SplitAsciiWhitespace; #[stable(feature = "str_escape", since = "1.34.0")] pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode}; -#[unstable(feature = "slice_concat_ext", - reason = "trait should not have to exist", - issue = "27747")] +#[unstable(feature = "slice_concat_ext", issue = "27747")] impl> SliceConcat for S { type Output = String; From 01d93bf59523c4e5c00cf8933c551adc73953cd1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 8 Jul 2019 17:47:49 +0200 Subject: [PATCH 03/43] Split the SliceConcat trait into Concat and Join --- src/liballoc/slice.rs | 74 +++++++++++++++++++++++++++++++++---------- src/liballoc/str.rs | 17 +++++++--- 2 files changed, 69 insertions(+), 22 deletions(-) diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 9a23cdc1768f3..d7a9f83ad242e 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -494,10 +494,10 @@ impl [T] { /// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn concat(&self) -> T::Output - where T: SliceConcat + pub fn concat(&self) -> >::Output + where Self: Concat { - SliceConcat::concat(self) + Concat::concat(self) } /// Flattens a slice of `T` into a single value `Self::Output`, placing a @@ -510,10 +510,10 @@ impl [T] { /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); /// ``` #[stable(feature = "rename_connect_to_join", since = "1.3.0")] - pub fn join(&self, sep: &Separator) -> T::Output - where T: SliceConcat + pub fn join(&self, sep: &Separator) -> >::Output + where Self: Join { - SliceConcat::join(self, sep) + Join::join(self, sep) } /// Flattens a slice of `T` into a single value `Self::Output`, placing a @@ -528,10 +528,10 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")] - pub fn connect(&self, sep: &Separator) -> T::Output - where T: SliceConcat + pub fn connect(&self, sep: &Separator) -> >::Output + where Self: Join { - SliceConcat::join(self, sep) + Join::join(self, sep) } } @@ -578,28 +578,63 @@ impl [u8] { // Extension traits for slices over specific kinds of data //////////////////////////////////////////////////////////////////////////////// -/// Helper trait for [`[T]::concat`](../../std/primitive.slice.html#method.concat) -/// and [`[T]::join`](../../std/primitive.slice.html#method.join) +/// Helper trait for [`[T]::concat`](../../std/primitive.slice.html#method.concat). +/// +/// Note: the `Item` type parameter is not used in this trait, +/// but it allows impls to be more generic. +/// Without it, we get this error: +/// +/// ```error +/// error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predica +/// --> src/liballoc/slice.rs:608:6 +/// | +/// 608 | impl> Concat for [V] { +/// | ^ unconstrained type parameter +/// ``` +/// +/// This is because there could exist `V` types with multiple `Borrow<[_]>` impls, +/// such that multiple `T` types would apply: +/// +/// ``` +/// # #[allow(dead_code)] +/// pub struct Foo(Vec, Vec); +/// +/// impl std::borrow::Borrow<[u32]> for Foo { +/// fn borrow(&self) -> &[u32] { &self.0 } +/// } +/// +/// impl std::borrow::Borrow<[String]> for Foo { +/// fn borrow(&self) -> &[String] { &self.1 } +/// } +/// ``` #[unstable(feature = "slice_concat_trait", issue = "27747")] -pub trait SliceConcat: Sized { +pub trait Concat { #[unstable(feature = "slice_concat_trait", issue = "27747")] /// The resulting type after concatenation type Output; /// Implementation of [`[T]::concat`](../../std/primitive.slice.html#method.concat) #[unstable(feature = "slice_concat_trait", issue = "27747")] - fn concat(slice: &[Self]) -> Self::Output; + fn concat(slice: &Self) -> Self::Output; +} + +/// Helper trait for [`[T]::join`](../../std/primitive.slice.html#method.join) +#[unstable(feature = "slice_concat_trait", issue = "27747")] +pub trait Join { + #[unstable(feature = "slice_concat_trait", issue = "27747")] + /// The resulting type after concatenation + type Output; /// Implementation of [`[T]::join`](../../std/primitive.slice.html#method.join) #[unstable(feature = "slice_concat_trait", issue = "27747")] - fn join(slice: &[Self], sep: &Separator) -> Self::Output; + fn join(slice: &Self, sep: &Separator) -> Self::Output; } #[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> SliceConcat for V { +impl> Concat for [V] { type Output = Vec; - fn concat(slice: &[Self]) -> Vec { + fn concat(slice: &Self) -> Vec { let size = slice.iter().map(|slice| slice.borrow().len()).sum(); let mut result = Vec::with_capacity(size); for v in slice { @@ -607,8 +642,13 @@ impl> SliceConcat for V { } result } +} + +#[unstable(feature = "slice_concat_ext", issue = "27747")] +impl> Join for [V] { + type Output = Vec; - fn join(slice: &[Self], sep: &T) -> Vec { + fn join(slice: &Self, sep: &T) -> Vec { let mut iter = slice.iter(); let first = match iter.next() { Some(first) => first, diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index b6512487ddd56..726ac1907fa86 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -37,7 +37,7 @@ use core::unicode::conversions; use crate::borrow::ToOwned; use crate::boxed::Box; -use crate::slice::{SliceConcat, SliceIndex}; +use crate::slice::{Concat, Join, SliceIndex}; use crate::string::String; use crate::vec::Vec; @@ -71,15 +71,22 @@ pub use core::str::SplitAsciiWhitespace; #[stable(feature = "str_escape", since = "1.34.0")] pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode}; +/// Note: `str` in `Concat` is not meaningful here. +/// This type parameter of the trait only exists to enable another impl. #[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> SliceConcat for S { +impl> Concat for [S] { type Output = String; - fn concat(slice: &[Self]) -> String { - Self::join(slice, "") + fn concat(slice: &Self) -> String { + Join::join(slice, "") } +} + +#[unstable(feature = "slice_concat_ext", issue = "27747")] +impl> Join for [S] { + type Output = String; - fn join(slice: &[Self], sep: &str) -> String { + fn join(slice: &Self, sep: &str) -> String { unsafe { String::from_utf8_unchecked( join_generic_copy(slice, sep.as_bytes()) ) } From 283f6762caebb723a17ce82e1fc120928697cfb9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 8 Jul 2019 17:50:27 +0200 Subject: [PATCH 04/43] Take separator by value in `[T]::join` --- src/liballoc/slice.rs | 10 +++++----- src/liballoc/str.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index d7a9f83ad242e..1b18dbeda9c11 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -510,7 +510,7 @@ impl [T] { /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); /// ``` #[stable(feature = "rename_connect_to_join", since = "1.3.0")] - pub fn join(&self, sep: &Separator) -> >::Output + pub fn join(&self, sep: Separator) -> >::Output where Self: Join { Join::join(self, sep) @@ -528,7 +528,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")] - pub fn connect(&self, sep: &Separator) -> >::Output + pub fn connect(&self, sep: Separator) -> >::Output where Self: Join { Join::join(self, sep) @@ -620,14 +620,14 @@ pub trait Concat { /// Helper trait for [`[T]::join`](../../std/primitive.slice.html#method.join) #[unstable(feature = "slice_concat_trait", issue = "27747")] -pub trait Join { +pub trait Join { #[unstable(feature = "slice_concat_trait", issue = "27747")] /// The resulting type after concatenation type Output; /// Implementation of [`[T]::join`](../../std/primitive.slice.html#method.join) #[unstable(feature = "slice_concat_trait", issue = "27747")] - fn join(slice: &Self, sep: &Separator) -> Self::Output; + fn join(slice: &Self, sep: Separator) -> Self::Output; } #[unstable(feature = "slice_concat_ext", issue = "27747")] @@ -645,7 +645,7 @@ impl> Concat for [V] { } #[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> Join for [V] { +impl> Join<&'_ T> for [V] { type Output = Vec; fn join(slice: &Self, sep: &T) -> Vec { diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 726ac1907fa86..f57cf96a64196 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -83,7 +83,7 @@ impl> Concat for [S] { } #[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> Join for [S] { +impl> Join<&'_ str> for [S] { type Output = String; fn join(slice: &Self, sep: &str) -> String { From b62a77b4905150b14c8b0fd6e685f528e4f90ea7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 8 Jul 2019 18:08:54 +0200 Subject: [PATCH 05/43] Add joining slices of slices with a slice separator, not just a single item --- src/liballoc/slice.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 1b18dbeda9c11..d475c628ff193 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -508,6 +508,7 @@ impl [T] { /// ``` /// assert_eq!(["hello", "world"].join(" "), "hello world"); /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]); + /// assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]); /// ``` #[stable(feature = "rename_connect_to_join", since = "1.3.0")] pub fn join(&self, sep: Separator) -> >::Output @@ -654,7 +655,7 @@ impl> Join<&'_ T> for [V] { Some(first) => first, None => return vec![], }; - let size = slice.iter().map(|slice| slice.borrow().len()).sum::() + slice.len() - 1; + let size = slice.iter().map(|v| v.borrow().len()).sum::() + slice.len() - 1; let mut result = Vec::with_capacity(size); result.extend_from_slice(first.borrow()); @@ -666,6 +667,29 @@ impl> Join<&'_ T> for [V] { } } +#[unstable(feature = "slice_concat_ext", issue = "27747")] +impl> Join<&'_ [T]> for [V] { + type Output = Vec; + + fn join(slice: &Self, sep: &[T]) -> Vec { + let mut iter = slice.iter(); + let first = match iter.next() { + Some(first) => first, + None => return vec![], + }; + let size = slice.iter().map(|v| v.borrow().len()).sum::() + + sep.len() * (slice.len() - 1); + let mut result = Vec::with_capacity(size); + result.extend_from_slice(first.borrow()); + + for v in iter { + result.extend_from_slice(sep); + result.extend_from_slice(v.borrow()) + } + result + } +} + //////////////////////////////////////////////////////////////////////////////// // Standard trait implementations for slices //////////////////////////////////////////////////////////////////////////////// From d0635ee5f74badbf72355b7e29d7f0723e8551da Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 9 Jul 2019 18:19:01 +0200 Subject: [PATCH 06/43] Update src/liballoc/slice.rs Co-Authored-By: Mazdak Farrokhzad --- src/liballoc/slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index d475c628ff193..848df2f9dcf90 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -646,7 +646,7 @@ impl> Concat for [V] { } #[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> Join<&'_ T> for [V] { +impl> Join<&T> for [V] { type Output = Vec; fn join(slice: &Self, sep: &T) -> Vec { From bbc9366c1a2d4d071b54cc1af23706a36741b444 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 9 Jul 2019 18:19:10 +0200 Subject: [PATCH 07/43] Update src/liballoc/slice.rs Co-Authored-By: Mazdak Farrokhzad --- src/liballoc/slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 848df2f9dcf90..881d499c0745b 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -668,7 +668,7 @@ impl> Join<&T> for [V] { } #[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> Join<&'_ [T]> for [V] { +impl> Join<&[T]> for [V] { type Output = Vec; fn join(slice: &Self, sep: &[T]) -> Vec { From 5f7768a976edc296c62479b936993b4dc9af065b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 9 Jul 2019 18:19:18 +0200 Subject: [PATCH 08/43] Update src/liballoc/str.rs Co-Authored-By: Mazdak Farrokhzad --- src/liballoc/str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index f57cf96a64196..9a1342c30d502 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -83,7 +83,7 @@ impl> Concat for [S] { } #[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> Join<&'_ str> for [S] { +impl> Join<&str> for [S] { type Output = String; fn join(slice: &Self, sep: &str) -> String { From 156173f83bdd0eb80546053d42304645e8cfbb6c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 16 Jul 2019 11:09:29 +0900 Subject: [PATCH 09/43] Add tests for overlapping explicitly dropped locals in generators --- src/test/run-pass/generator/size-moved-locals.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/run-pass/generator/size-moved-locals.rs b/src/test/run-pass/generator/size-moved-locals.rs index 37e2e0cfdcccf..5b056059b5d1d 100644 --- a/src/test/run-pass/generator/size-moved-locals.rs +++ b/src/test/run-pass/generator/size-moved-locals.rs @@ -55,8 +55,20 @@ fn overlap_move_points() -> impl Generator { } } +fn overlap_x_and_y() -> impl Generator{ + static || { + let x = [0u8; 1024]; + yield; + drop(x); + let y = [0u8;1024]; + yield; + drop(y); + } +} + fn main() { assert_eq!(1028, std::mem::size_of_val(&move_before_yield())); assert_eq!(1032, std::mem::size_of_val(&move_before_yield_with_noop())); assert_eq!(2056, std::mem::size_of_val(&overlap_move_points())); + assert_eq!(2052, std::mem::size_of_val(&overlap_x_and_y())); } From 21b502b275ca7d9a7f43c4e1cf09b0b547ecc645 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 13:19:36 +0200 Subject: [PATCH 10/43] warn that raw pointers must be aligned when used, and that writes cause drop --- src/libstd/primitive_docs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 65fd8c83e1ce5..cab58799d68d4 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -362,8 +362,11 @@ mod prim_unit { } /// /// *[See also the `std::ptr` module](ptr/index.html).* /// -/// Working with raw pointers in Rust is uncommon, -/// typically limited to a few patterns. +/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. +/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is used to +/// load/store data from/to memory, they must be non-null and aligned. +/// Storing through a raw pointer (`*ptr = data`) calls `drop` on the old value, so +/// [`write`] must be used if memory is not already initialized. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. @@ -442,6 +445,7 @@ mod prim_unit { } /// [`offset`]: ../std/primitive.pointer.html#method.offset /// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw /// [`drop`]: ../std/mem/fn.drop.html +/// [`write`]: ../std/ptr/fn.write.html #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer { } From 2e6b13a649ce4a8f5a608d10133dd2b4b30c35c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 13:20:08 +0200 Subject: [PATCH 11/43] references must be aligned; also move up the warning that fn ptrs must be non-NULL --- src/libstd/primitive_docs.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index cab58799d68d4..95b803e3461ec 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -895,9 +895,9 @@ mod prim_usize { } /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` /// operators on a value, or by using a `ref` or `ref mut` pattern. /// -/// For those familiar with pointers, a reference is just a pointer that is assumed to not be null. -/// In fact, `Option<&T>` has the same memory representation as a nullable pointer, and can be -/// passed across FFI boundaries as such. +/// For those familiar with pointers, a reference is just a pointer that is assumed to be +/// aligned and not null. In fact, `Option<&T>` has the same memory representation as a +/// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// /// In most cases, references can be used much like the original value. Field access, method /// calling, and indexing work the same (save for mutability rules, of course). In addition, the @@ -1040,6 +1040,11 @@ mod prim_ref { } /// [`FnMut`]: ops/trait.FnMut.html /// [`FnOnce`]: ops/trait.FnOnce.html /// +/// Function pointers are pointers that point to *code*, not data. They can be called +/// just like functions. Like references, function pointers are assumed to not be null, +/// so if you want to pass a function pointer over FFI and be able to accommodate null pointers, +/// make your type `Option` with your required signature. +/// /// Plain function pointers are obtained by casting either plain functions, or closures that don't /// capture an environment: /// @@ -1095,10 +1100,6 @@ 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 accommodate null pointers, make your type -/// `Option` with your required signature. -/// /// Function pointers implement the following traits: /// /// * [`Clone`] From f502bf78cba8974cdfbd20f3b524d86b982e5e2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 12:08:19 +0200 Subject: [PATCH 12/43] sync with nomicon: raw ptr must be non-dangling and aligned every time it is dereferenced --- src/libstd/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 95b803e3461ec..0f66e8cd47ea3 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -363,8 +363,8 @@ mod prim_unit { } /// *[See also the `std::ptr` module](ptr/index.html).* /// /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is used to -/// load/store data from/to memory, they must be non-null and aligned. +/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is +/// dereferenced (using the `*` operator), it must be non-null and aligned. /// Storing through a raw pointer (`*ptr = data`) calls `drop` on the old value, so /// [`write`] must be used if memory is not already initialized. /// From 40812224cad0d8b89d52fc1ffc3d44e1615794d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 12:13:57 +0200 Subject: [PATCH 13/43] apply feedback --- src/libstd/primitive_docs.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 0f66e8cd47ea3..5fa15f1fbde36 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -363,10 +363,11 @@ mod prim_unit { } /// *[See also the `std::ptr` module](ptr/index.html).* /// /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is +/// Raw pointers can be unaligned or [`null`] when unused. However, when a raw pointer is /// dereferenced (using the `*` operator), it must be non-null and aligned. -/// Storing through a raw pointer (`*ptr = data`) calls `drop` on the old value, so -/// [`write`] must be used if memory is not already initialized. +/// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so +/// [`write`] must be used if memory is not already initialized---otherwise `drop` +/// would be called on the uninitialized memory. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. @@ -896,7 +897,8 @@ mod prim_usize { } /// operators on a value, or by using a `ref` or `ref mut` pattern. /// /// For those familiar with pointers, a reference is just a pointer that is assumed to be -/// aligned and not null. In fact, `Option<&T>` has the same memory representation as a +/// aligned, not null, and pointing to valid (initialized) memory. +/// In fact, `Option<&T>` has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// /// In most cases, references can be used much like the original value. Field access, method From a7b924654070f59297e86ff372ac74c5c701929f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jul 2019 10:33:11 +0200 Subject: [PATCH 14/43] weasle, weasle --- src/libstd/primitive_docs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5fa15f1fbde36..b7196a8670138 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -1043,9 +1043,9 @@ mod prim_ref { } /// [`FnOnce`]: ops/trait.FnOnce.html /// /// Function pointers are pointers that point to *code*, not data. They can be called -/// just like functions. Like references, function pointers are assumed to not be null, -/// so if you want to pass a function pointer over FFI and be able to accommodate null pointers, -/// make your type `Option` with your required signature. +/// just like functions. Like references, function pointers are, among other things, assumed to +/// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null +/// pointers, make your type `Option` with your required signature. /// /// Plain function pointers are obtained by casting either plain functions, or closures that don't /// capture an environment: From 91967816c3851b4b796ce774bde49a9f47681bca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jul 2019 15:32:58 +0200 Subject: [PATCH 15/43] account for non-drop-glue types --- src/libstd/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index b7196a8670138..ead1987d04b56 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -365,9 +365,10 @@ mod prim_unit { } /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. /// Raw pointers can be unaligned or [`null`] when unused. However, when a raw pointer is /// dereferenced (using the `*` operator), it must be non-null and aligned. +/// /// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so -/// [`write`] must be used if memory is not already initialized---otherwise `drop` -/// would be called on the uninitialized memory. +/// [`write`] must be used if the type has drop glue and memory is not already +/// initialized---otherwise `drop` would be called on the uninitialized memory. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. From f78cd4de454c4b55c95137f2db07b4f36b86c3af Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Sun, 16 Jun 2019 17:10:13 +0900 Subject: [PATCH 16/43] Fix building_llvm in sanity check, add swig sanity check. --- src/bootstrap/sanity.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index dc65fb9b79706..4e3930c8da7fc 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -78,8 +78,11 @@ pub fn check(build: &mut Build) { // We need cmake, but only if we're actually building LLVM or sanitizers. let building_llvm = build.hosts.iter() - .filter_map(|host| build.config.target_config.get(host)) - .any(|config| config.llvm_config.is_none()); + .map(|host| build.config.target_config + .get(host) + .map(|config| config.llvm_config.is_none()) + .unwrap_or(true)) + .any(|build_llvm_ourselves| build_llvm_ourselves); if building_llvm || build.config.sanitizers { cmd_finder.must_have("cmake"); } @@ -106,6 +109,14 @@ pub fn check(build: &mut Build) { build.config.ninja = true; } } + + if build.config.lldb_enabled { + cmd_finder.must_have("swig"); + let out = output(Command::new("swig").arg("-version")); + if !out.contains("SWIG Version 3") && !out.contains("SWIG Version 4") { + panic!("Ensure that Swig 3.x.x or 4.x.x is installed."); + } + } } build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p)) From 5b3b6b8d00df27c46d6254c737b40e79bebcced2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 22 Jul 2019 18:29:49 -0700 Subject: [PATCH 17/43] Make the parser TokenStream more resilient after mismatched delimiter recovery --- src/libsyntax/parse/parser.rs | 3 +++ src/test/ui/issues/issue-62881.rs | 6 ++++++ src/test/ui/issues/issue-62881.stderr | 29 +++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/test/ui/issues/issue-62881.rs create mode 100644 src/test/ui/issues/issue-62881.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1d4d02c732582..197a9078b1888 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7670,6 +7670,9 @@ impl<'a> Parser<'a> { let ret = f(self); let last_token = if self.token_cursor.stack.len() == prev { &mut self.token_cursor.frame.last_token + } else if self.token_cursor.stack.is_empty() {//&& !self.unclosed_delims.is_empty() { + // This can happen with mismatched delimiters (#62881) + return Ok((ret?, TokenStream::new(vec![]))); } else { &mut self.token_cursor.stack[prev].last_token }; diff --git a/src/test/ui/issues/issue-62881.rs b/src/test/ui/issues/issue-62881.rs new file mode 100644 index 0000000000000..1782c2e375df5 --- /dev/null +++ b/src/test/ui/issues/issue-62881.rs @@ -0,0 +1,6 @@ +fn main() {} + +fn f() -> isize { fn f() -> isize {} pub f< +//~^ ERROR missing `fn` or `struct` for function or struct definition +//~| ERROR mismatched types +//~ ERROR this file contains an un-closed delimiter diff --git a/src/test/ui/issues/issue-62881.stderr b/src/test/ui/issues/issue-62881.stderr new file mode 100644 index 0000000000000..85c3575fd9288 --- /dev/null +++ b/src/test/ui/issues/issue-62881.stderr @@ -0,0 +1,29 @@ +error: this file contains an un-closed delimiter + --> $DIR/issue-62881.rs:6:53 + | +LL | fn f() -> isize { fn f() -> isize {} pub f< + | - un-closed delimiter +... +LL | + | ^ + +error: missing `fn` or `struct` for function or struct definition + --> $DIR/issue-62881.rs:3:41 + | +LL | fn f() -> isize { fn f() -> isize {} pub f< + | ^ + +error[E0308]: mismatched types + --> $DIR/issue-62881.rs:3:29 + | +LL | fn f() -> isize { fn f() -> isize {} pub f< + | - ^^^^^ expected isize, found () + | | + | this function's body doesn't return + | + = note: expected type `isize` + found type `()` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From ba78db310b2ddf9b5f8e6c87a58e8ea8df374e16 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 14 May 2019 21:50:39 +0200 Subject: [PATCH 18/43] libsyntax: factor out file path resolving This allows the same logic used by `include_X!` macros to be used by `#[doc(include)]`. --- src/libsyntax/ext/source_util.rs | 33 ++++++-------------------------- src/libsyntax/lib.rs | 1 + src/libsyntax/util/path.rs | 28 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 src/libsyntax/util/path.rs diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index c2ba8b983f5a8..aad390f3bf601 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -6,13 +6,13 @@ use crate::print::pprust; use crate::ptr::P; use crate::symbol::Symbol; use crate::tokenstream; +use crate::util::path; use smallvec::SmallVec; -use syntax_pos::{self, Pos, Span, FileName}; +use syntax_pos::{self, Pos, Span}; use std::fs; use std::io::ErrorKind; -use std::path::PathBuf; use rustc_data_structures::sync::Lrc; // These macros all relate to the file system; they either return @@ -78,9 +78,9 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea None => return DummyResult::any(sp), }; // The file will be added to the code map by the parser - let path = res_rel_file(cx, sp, file); + let file = path::resolve(file, sp, cx.source_map()); let directory_ownership = DirectoryOwnership::Owned { relative: None }; - let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, directory_ownership, None, sp); + let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp); struct ExpandResult<'a> { p: parse::parser::Parser<'a>, @@ -115,7 +115,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To Some(f) => f, None => return DummyResult::expr(sp) }; - let file = res_rel_file(cx, sp, file); + let file = path::resolve(file, sp, cx.source_map()); match fs::read_to_string(&file) { Ok(src) => { let interned_src = Symbol::intern(&src); @@ -143,7 +143,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream:: Some(f) => f, None => return DummyResult::expr(sp) }; - let file = res_rel_file(cx, sp, file); + let file = path::resolve(file, sp, cx.source_map()); match fs::read(&file) { Ok(bytes) => { // Add the contents to the source map if it contains UTF-8. @@ -164,24 +164,3 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream:: } } } - -// 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: String) -> PathBuf { - let arg = PathBuf::from(arg); - // 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 path = match cx.source_map().span_to_unmapped_path(callsite) { - FileName::Real(path) => path, - FileName::DocTest(path, _) => path, - other => panic!("cannot resolve relative path in non-file source `{}`", other), - }; - path.pop(); - path.push(arg); - path - } else { - arg - } -} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 3dea1977c4dac..1b2873b1de7bc 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -135,6 +135,7 @@ pub mod util { #[cfg(test)] pub mod parser_testing; pub mod map_in_place; + pub mod path; } pub mod json; diff --git a/src/libsyntax/util/path.rs b/src/libsyntax/util/path.rs new file mode 100644 index 0000000000000..a3511bac8e7d9 --- /dev/null +++ b/src/libsyntax/util/path.rs @@ -0,0 +1,28 @@ +use crate::source_map::SourceMap; +use std::path::PathBuf; +use syntax_pos::{Span, FileName}; + +/// Resolve a path mentioned inside Rust code. +/// +/// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths. +/// +/// Returns an absolute path to the file that `path` refers to. +pub fn resolve(path: impl Into, span: Span, map: &SourceMap) -> PathBuf { + let path = path.into(); + + // Relative paths are resolved relative to the file in which they are found + // after macro expansion (that is, they are unhygienic). + if !path.is_absolute() { + let callsite = span.source_callsite(); + let mut result = match map.span_to_unmapped_path(callsite) { + FileName::Real(path) => path, + FileName::DocTest(path, _) => path, + other => panic!("cannot resolve relative path in non-file source `{}`", other), + }; + result.pop(); + result.push(path); + result + } else { + path + } +} From 138e08ccf6f6c6caf55a135bd0edcba8e6855df5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 18 May 2019 15:56:53 +0200 Subject: [PATCH 19/43] Make #[doc(include)] paths behave like other paths This makes them relative to the containing file instead of the crate root --- src/libstd/os/raw/mod.rs | 48 ++++++++++++++++++++++++------------- src/libsyntax/ext/expand.rs | 7 ++---- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index c0b0b6d40d891..fd50657800d50 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -8,7 +8,8 @@ #![stable(feature = "raw_os", since = "1.1.0")] -#[doc(include = "os/raw/char.md")] +#[cfg_attr(stage0, doc(include = "os/raw/char.md"))] +#[cfg_attr(not(stage0), doc(include = "char.md"))] #[cfg(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", @@ -31,7 +32,8 @@ target_arch = "powerpc")), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[doc(include = "os/raw/char.md")] +#[cfg_attr(stage0, doc(include = "os/raw/char.md"))] +#[cfg_attr(not(stage0), doc(include = "char.md"))] #[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", @@ -54,37 +56,51 @@ target_arch = "powerpc")), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; -#[doc(include = "os/raw/schar.md")] +#[cfg_attr(stage0, doc(include = "os/raw/schar.md"))] +#[cfg_attr(not(stage0), doc(include = "schar.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; -#[doc(include = "os/raw/uchar.md")] +#[cfg_attr(stage0, doc(include = "os/raw/uchar.md"))] +#[cfg_attr(not(stage0), doc(include = "uchar.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; -#[doc(include = "os/raw/short.md")] +#[cfg_attr(stage0, doc(include = "os/raw/short.md"))] +#[cfg_attr(not(stage0), doc(include = "short.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16; -#[doc(include = "os/raw/ushort.md")] +#[cfg_attr(stage0, doc(include = "os/raw/ushort.md"))] +#[cfg_attr(not(stage0), doc(include = "ushort.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16; -#[doc(include = "os/raw/int.md")] +#[cfg_attr(stage0, doc(include = "os/raw/int.md"))] +#[cfg_attr(not(stage0), doc(include = "int.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32; -#[doc(include = "os/raw/uint.md")] +#[cfg_attr(stage0, doc(include = "os/raw/uint.md"))] +#[cfg_attr(not(stage0), doc(include = "uint.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32; -#[doc(include = "os/raw/long.md")] +#[cfg_attr(stage0, doc(include = "os/raw/long.md"))] +#[cfg_attr(not(stage0), doc(include = "long.md"))] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32; -#[doc(include = "os/raw/ulong.md")] +#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))] +#[cfg_attr(not(stage0), doc(include = "ulong.md"))] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32; -#[doc(include = "os/raw/long.md")] +#[cfg_attr(stage0, doc(include = "os/raw/long.md"))] +#[cfg_attr(not(stage0), doc(include = "long.md"))] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64; -#[doc(include = "os/raw/ulong.md")] +#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))] +#[cfg_attr(not(stage0), doc(include = "ulong.md"))] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64; -#[doc(include = "os/raw/longlong.md")] +#[cfg_attr(stage0, doc(include = "os/raw/longlong.md"))] +#[cfg_attr(not(stage0), doc(include = "longlong.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64; -#[doc(include = "os/raw/ulonglong.md")] +#[cfg_attr(stage0, doc(include = "os/raw/ulonglong.md"))] +#[cfg_attr(not(stage0), doc(include = "ulonglong.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64; -#[doc(include = "os/raw/float.md")] +#[cfg_attr(stage0, doc(include = "os/raw/float.md"))] +#[cfg_attr(not(stage0), doc(include = "float.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32; -#[doc(include = "os/raw/double.md")] +#[cfg_attr(stage0, doc(include = "os/raw/double.md"))] +#[cfg_attr(not(stage0), doc(include = "double.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64; #[stable(feature = "raw_os", since = "1.1.0")] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ae72f1fd108ed..6cfcfdfbf7d85 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -17,6 +17,7 @@ use crate::symbol::{sym, Symbol}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::visit::{self, Visitor}; use crate::util::map_in_place::MapInPlace; +use crate::util::path; use errors::{Applicability, FatalError}; use smallvec::{smallvec, SmallVec}; @@ -1253,7 +1254,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { return noop_visit_attribute(at, self); } - let filename = self.cx.root_path.join(file.to_string()); + let filename = path::resolve(&*file.as_str(), it.span(), self.cx.source_map()); match fs::read_to_string(&filename) { Ok(src) => { let src_interned = Symbol::intern(&src); @@ -1302,10 +1303,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { ); err.span_label(lit.span, "couldn't read file"); - if e.kind() == ErrorKind::NotFound { - err.help("external doc paths are relative to the crate root"); - } - err.emit(); } } From 1cc7c211f5ff566f0ea2270197a15d1ab8c429bf Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 19 May 2019 13:33:16 +0200 Subject: [PATCH 20/43] Adjust docs to new #[doc(include)] behaviour --- src/doc/rustdoc/src/unstable-features.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 1d9510c9aacab..6e32468b64dee 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -183,9 +183,8 @@ Book][unstable-masked] and [its tracking issue][issue-masked]. As designed in [RFC 1990], Rustdoc can read an external file to use as a type's documentation. This is useful if certain documentation is so long that it would break the flow of reading the source. -Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` (where `sometype.md` is -a file adjacent to the `lib.rs` for the crate) will ask Rustdoc to instead read that file and use it -as if it were written inline. +Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` will ask Rustdoc to +instead read that file and use it as if it were written inline. [RFC 1990]: https://github.com/rust-lang/rfcs/pull/1990 From 8ccf52c1c6cffde2905d7ad0ebfa36a9e8a0c319 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 22 Jun 2019 20:37:25 +0200 Subject: [PATCH 21/43] stage0 -> bootstrap --- src/libstd/os/raw/mod.rs | 64 ++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index fd50657800d50..340b2a5d5519e 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -8,8 +8,8 @@ #![stable(feature = "raw_os", since = "1.1.0")] -#[cfg_attr(stage0, doc(include = "os/raw/char.md"))] -#[cfg_attr(not(stage0), doc(include = "char.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/char.md"))] +#[cfg_attr(not(bootstrap), doc(include = "char.md"))] #[cfg(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", @@ -32,8 +32,8 @@ target_arch = "powerpc")), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[cfg_attr(stage0, doc(include = "os/raw/char.md"))] -#[cfg_attr(not(stage0), doc(include = "char.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/char.md"))] +#[cfg_attr(not(bootstrap), doc(include = "char.md"))] #[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", @@ -56,51 +56,51 @@ target_arch = "powerpc")), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; -#[cfg_attr(stage0, doc(include = "os/raw/schar.md"))] -#[cfg_attr(not(stage0), doc(include = "schar.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/schar.md"))] +#[cfg_attr(not(bootstrap), doc(include = "schar.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; -#[cfg_attr(stage0, doc(include = "os/raw/uchar.md"))] -#[cfg_attr(not(stage0), doc(include = "uchar.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/uchar.md"))] +#[cfg_attr(not(bootstrap), doc(include = "uchar.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; -#[cfg_attr(stage0, doc(include = "os/raw/short.md"))] -#[cfg_attr(not(stage0), doc(include = "short.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/short.md"))] +#[cfg_attr(not(bootstrap), doc(include = "short.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16; -#[cfg_attr(stage0, doc(include = "os/raw/ushort.md"))] -#[cfg_attr(not(stage0), doc(include = "ushort.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/ushort.md"))] +#[cfg_attr(not(bootstrap), doc(include = "ushort.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16; -#[cfg_attr(stage0, doc(include = "os/raw/int.md"))] -#[cfg_attr(not(stage0), doc(include = "int.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/int.md"))] +#[cfg_attr(not(bootstrap), doc(include = "int.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32; -#[cfg_attr(stage0, doc(include = "os/raw/uint.md"))] -#[cfg_attr(not(stage0), doc(include = "uint.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/uint.md"))] +#[cfg_attr(not(bootstrap), doc(include = "uint.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32; -#[cfg_attr(stage0, doc(include = "os/raw/long.md"))] -#[cfg_attr(not(stage0), doc(include = "long.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/long.md"))] +#[cfg_attr(not(bootstrap), doc(include = "long.md"))] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32; -#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))] -#[cfg_attr(not(stage0), doc(include = "ulong.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/ulong.md"))] +#[cfg_attr(not(bootstrap), doc(include = "ulong.md"))] #[cfg(any(target_pointer_width = "32", windows))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32; -#[cfg_attr(stage0, doc(include = "os/raw/long.md"))] -#[cfg_attr(not(stage0), doc(include = "long.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/long.md"))] +#[cfg_attr(not(bootstrap), doc(include = "long.md"))] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64; -#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))] -#[cfg_attr(not(stage0), doc(include = "ulong.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/ulong.md"))] +#[cfg_attr(not(bootstrap), doc(include = "ulong.md"))] #[cfg(all(target_pointer_width = "64", not(windows)))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64; -#[cfg_attr(stage0, doc(include = "os/raw/longlong.md"))] -#[cfg_attr(not(stage0), doc(include = "longlong.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/longlong.md"))] +#[cfg_attr(not(bootstrap), doc(include = "longlong.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64; -#[cfg_attr(stage0, doc(include = "os/raw/ulonglong.md"))] -#[cfg_attr(not(stage0), doc(include = "ulonglong.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/ulonglong.md"))] +#[cfg_attr(not(bootstrap), doc(include = "ulonglong.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64; -#[cfg_attr(stage0, doc(include = "os/raw/float.md"))] -#[cfg_attr(not(stage0), doc(include = "float.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/float.md"))] +#[cfg_attr(not(bootstrap), doc(include = "float.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32; -#[cfg_attr(stage0, doc(include = "os/raw/double.md"))] -#[cfg_attr(not(stage0), doc(include = "double.md"))] +#[cfg_attr(bootstrap, doc(include = "os/raw/double.md"))] +#[cfg_attr(not(bootstrap), doc(include = "double.md"))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64; #[stable(feature = "raw_os", since = "1.1.0")] From edb21873cced7a179571aa3a9c25eb1cfc05c2db Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 22 Jun 2019 21:51:51 +0200 Subject: [PATCH 22/43] Make path::resolve a method on ExtCtxt --- src/libsyntax/ext/base.rs | 27 ++++++++++++++++++++++++++- src/libsyntax/ext/expand.rs | 3 +-- src/libsyntax/ext/source_util.rs | 7 +++---- src/libsyntax/lib.rs | 1 - src/libsyntax/util/path.rs | 28 ---------------------------- 5 files changed, 30 insertions(+), 36 deletions(-) delete mode 100644 src/libsyntax/util/path.rs diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 926c9e88efe15..11b7a984aaa00 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,6 +1,6 @@ use crate::ast::{self, Attribute, Name, PatKind}; use crate::attr::{HasAttrs, Stability, Deprecation}; -use crate::source_map::{SourceMap, Spanned, respan}; +use crate::source_map::{SourceMap, Spanned, FileName, respan}; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency}; @@ -889,6 +889,31 @@ impl<'a> ExtCtxt<'a> { pub fn check_unused_macros(&self) { self.resolver.check_unused_macros(); } + + /// Resolve a path mentioned inside Rust code. + /// + /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths. + /// + /// Returns an absolute path to the file that `path` refers to. + pub fn resolve_path(&self, path: impl Into, span: Span) -> PathBuf { + let path = path.into(); + + // Relative paths are resolved relative to the file in which they are found + // after macro expansion (that is, they are unhygienic). + if !path.is_absolute() { + let callsite = span.source_callsite(); + let mut result = match self.source_map().span_to_unmapped_path(callsite) { + FileName::Real(path) => path, + FileName::DocTest(path, _) => path, + other => panic!("cannot resolve relative path in non-file source `{}`", other), + }; + result.pop(); + result.push(path); + result + } else { + path + } + } } /// Extracts a string literal from the macro expanded version of `expr`, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 6cfcfdfbf7d85..ae8b11ff9d50e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -17,7 +17,6 @@ use crate::symbol::{sym, Symbol}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::visit::{self, Visitor}; use crate::util::map_in_place::MapInPlace; -use crate::util::path; use errors::{Applicability, FatalError}; use smallvec::{smallvec, SmallVec}; @@ -1254,7 +1253,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { return noop_visit_attribute(at, self); } - let filename = path::resolve(&*file.as_str(), it.span(), self.cx.source_map()); + let filename = self.cx.resolve_path(&*file.as_str(), it.span()); match fs::read_to_string(&filename) { Ok(src) => { let src_interned = Symbol::intern(&src); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index aad390f3bf601..ae080c05eec91 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -6,7 +6,6 @@ use crate::print::pprust; use crate::ptr::P; use crate::symbol::Symbol; use crate::tokenstream; -use crate::util::path; use smallvec::SmallVec; use syntax_pos::{self, Pos, Span}; @@ -78,7 +77,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea None => return DummyResult::any(sp), }; // The file will be added to the code map by the parser - let file = path::resolve(file, sp, cx.source_map()); + let file = cx.resolve_path(file, sp); let directory_ownership = DirectoryOwnership::Owned { relative: None }; let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp); @@ -115,7 +114,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To Some(f) => f, None => return DummyResult::expr(sp) }; - let file = path::resolve(file, sp, cx.source_map()); + let file = cx.resolve_path(file, sp); match fs::read_to_string(&file) { Ok(src) => { let interned_src = Symbol::intern(&src); @@ -143,7 +142,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream:: Some(f) => f, None => return DummyResult::expr(sp) }; - let file = path::resolve(file, sp, cx.source_map()); + let file = cx.resolve_path(file, sp); match fs::read(&file) { Ok(bytes) => { // Add the contents to the source map if it contains UTF-8. diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 1b2873b1de7bc..3dea1977c4dac 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -135,7 +135,6 @@ pub mod util { #[cfg(test)] pub mod parser_testing; pub mod map_in_place; - pub mod path; } pub mod json; diff --git a/src/libsyntax/util/path.rs b/src/libsyntax/util/path.rs deleted file mode 100644 index a3511bac8e7d9..0000000000000 --- a/src/libsyntax/util/path.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::source_map::SourceMap; -use std::path::PathBuf; -use syntax_pos::{Span, FileName}; - -/// Resolve a path mentioned inside Rust code. -/// -/// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths. -/// -/// Returns an absolute path to the file that `path` refers to. -pub fn resolve(path: impl Into, span: Span, map: &SourceMap) -> PathBuf { - let path = path.into(); - - // Relative paths are resolved relative to the file in which they are found - // after macro expansion (that is, they are unhygienic). - if !path.is_absolute() { - let callsite = span.source_callsite(); - let mut result = match map.span_to_unmapped_path(callsite) { - FileName::Real(path) => path, - FileName::DocTest(path, _) => path, - other => panic!("cannot resolve relative path in non-file source `{}`", other), - }; - result.pop(); - result.push(path); - result - } else { - path - } -} From 7c42259d03b196839754ef2c55d6e3acb3c9f895 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 17 Jul 2019 22:46:37 +0200 Subject: [PATCH 23/43] Update stdarch submodule --- src/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdarch b/src/stdarch index b881a2d124cb0..4791ba85e7645 160000 --- a/src/stdarch +++ b/src/stdarch @@ -1 +1 @@ -Subproject commit b881a2d124cb0eea09d137300eb4a35829b517fb +Subproject commit 4791ba85e7645c02146dd416288480943670d1ca From dd5045ed630b7577296087f09f559bb9c08f68e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 17:48:01 +0200 Subject: [PATCH 24/43] Apply suggestions from code review Co-Authored-By: gnzlbg --- src/libstd/primitive_docs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index ead1987d04b56..b79cfa3eead23 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -363,12 +363,12 @@ mod prim_unit { } /// *[See also the `std::ptr` module](ptr/index.html).* /// /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or [`null`] when unused. However, when a raw pointer is +/// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is /// dereferenced (using the `*` operator), it must be non-null and aligned. /// /// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so /// [`write`] must be used if the type has drop glue and memory is not already -/// initialized---otherwise `drop` would be called on the uninitialized memory. +/// initialized - otherwise `drop` would be called on the uninitialized memory. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. @@ -898,7 +898,10 @@ mod prim_usize { } /// operators on a value, or by using a `ref` or `ref mut` pattern. /// /// For those familiar with pointers, a reference is just a pointer that is assumed to be -/// aligned, not null, and pointing to valid (initialized) memory. +/// aligned, not null, and pointing to memory containing a valid value of `T` - for example, +/// `&bool` can only point to an allocation containing the integer values `1` (`true`) or `0` +/// (`false`), but the behavior of creating a `&bool` that points to an allocation containing +/// the value `3` is undefined. /// In fact, `Option<&T>` has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// From 65cf10d90276e40bd8cc27a79d6c6f0d13e0cc7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 17:51:52 +0200 Subject: [PATCH 25/43] word things more like we usually do --- src/libstd/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index b79cfa3eead23..d9a3da66a6786 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -900,8 +900,8 @@ mod prim_usize { } /// For those familiar with pointers, a reference is just a pointer that is assumed to be /// aligned, not null, and pointing to memory containing a valid value of `T` - for example, /// `&bool` can only point to an allocation containing the integer values `1` (`true`) or `0` -/// (`false`), but the behavior of creating a `&bool` that points to an allocation containing -/// the value `3` is undefined. +/// (`false`), but creating a `&bool` that points to an allocation containing +/// the value `3` causes undefined behaviour. /// In fact, `Option<&T>` has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// From 218ab4cd7fdf145a0870c582a23ad5fd85cd80e5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 23 Jul 2019 17:57:54 +0200 Subject: [PATCH 26/43] Update test --- src/test/ui/extern/external-doc-error.rs | 1 - src/test/ui/extern/external-doc-error.stderr | 12 +++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/test/ui/extern/external-doc-error.rs b/src/test/ui/extern/external-doc-error.rs index e17dda65568e9..4e89f7464da49 100644 --- a/src/test/ui/extern/external-doc-error.rs +++ b/src/test/ui/extern/external-doc-error.rs @@ -4,7 +4,6 @@ #[doc(include = "not-a-file.md")] pub struct SomeStruct; //~^ ERROR couldn't read - //~| HELP external doc paths are relative to the crate root #[doc(include = "auxiliary/invalid-utf8.txt")] pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file diff --git a/src/test/ui/extern/external-doc-error.stderr b/src/test/ui/extern/external-doc-error.stderr index a3be3277de545..b180cd66c5269 100644 --- a/src/test/ui/extern/external-doc-error.stderr +++ b/src/test/ui/extern/external-doc-error.stderr @@ -3,35 +3,33 @@ error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2) | LL | #[doc(include = "not-a-file.md")] | ^^^^^^^^^^^^^^^ couldn't read file - | - = help: external doc paths are relative to the crate root error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file - --> $DIR/external-doc-error.rs:9:17 + --> $DIR/external-doc-error.rs:8:17 | LL | #[doc(include = "auxiliary/invalid-utf8.txt")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8 error: expected path to external documentation - --> $DIR/external-doc-error.rs:12:7 + --> $DIR/external-doc-error.rs:11:7 | LL | #[doc(include)] | ^^^^^^^ help: provide a file path with `=`: `include = ""` error: expected path to external documentation - --> $DIR/external-doc-error.rs:17:7 + --> $DIR/external-doc-error.rs:16:7 | LL | #[doc(include("../README.md"))] | ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"` error: expected path to external documentation - --> $DIR/external-doc-error.rs:22:7 + --> $DIR/external-doc-error.rs:21:7 | LL | #[doc(include = 123)] | ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = ""` error: expected path to external documentation - --> $DIR/external-doc-error.rs:27:7 + --> $DIR/external-doc-error.rs:26:7 | LL | #[doc(include(123))] | ^^^^^^^^^^^^ help: provide a file path with `=`: `include = ""` From f56c8f6ea426ac24d221b982ff9ee43b77fc9400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 23 Jul 2019 11:19:13 -0700 Subject: [PATCH 27/43] Fix another case --- src/libsyntax/parse/parser.rs | 15 ++++++-- src/test/ui/issues/issue-62895.rs | 11 ++++++ src/test/ui/issues/issue-62895.stderr | 49 +++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issues/issue-62895.rs create mode 100644 src/test/ui/issues/issue-62895.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 197a9078b1888..e494cb472a825 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7670,8 +7670,9 @@ impl<'a> Parser<'a> { let ret = f(self); let last_token = if self.token_cursor.stack.len() == prev { &mut self.token_cursor.frame.last_token - } else if self.token_cursor.stack.is_empty() {//&& !self.unclosed_delims.is_empty() { - // This can happen with mismatched delimiters (#62881) + } else if self.token_cursor.stack.get(prev).is_none() { + // This can happen due to a bad interaction of two unrelated recovery mechanisms with + // mismatched delimiters *and* recovery lookahead on `pub ident(` likely typo (#62881) return Ok((ret?, TokenStream::new(vec![]))); } else { &mut self.token_cursor.stack[prev].last_token @@ -7680,7 +7681,15 @@ impl<'a> Parser<'a> { // Pull out the tokens that we've collected from the call to `f` above. let mut collected_tokens = match *last_token { LastToken::Collecting(ref mut v) => mem::take(v), - LastToken::Was(_) => panic!("our vector went away?"), + LastToken::Was(ref was) => { + let msg = format!("our vector went away? - found Was({:?})", was); + debug!("collect_tokens: {}", msg); + self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg); + // This can happen due to a bad interaction of two unrelated recovery mechanisms + // with mismatched delimiters *and* recovery lookahead on `pub ident(` likely typo + // (#62895, different but similar to the case above) + return Ok((ret?, TokenStream::new(vec![]))); + } }; // If we're not at EOF our current token wasn't actually consumed by diff --git a/src/test/ui/issues/issue-62895.rs b/src/test/ui/issues/issue-62895.rs new file mode 100644 index 0000000000000..53f17405d79f4 --- /dev/null +++ b/src/test/ui/issues/issue-62895.rs @@ -0,0 +1,11 @@ +fn main() {} + +fn v() -> isize { //~ ERROR mismatched types +mod _ { //~ ERROR expected identifier +pub fn g() -> isizee { //~ ERROR cannot find type `isizee` in this scope +mod _ { //~ ERROR expected identifier +pub g() -> is //~ ERROR missing `fn` for function definition +(), w20); +} +(), w20); //~ ERROR expected item, found `;` +} diff --git a/src/test/ui/issues/issue-62895.stderr b/src/test/ui/issues/issue-62895.stderr new file mode 100644 index 0000000000000..7def7b562ca59 --- /dev/null +++ b/src/test/ui/issues/issue-62895.stderr @@ -0,0 +1,49 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-62895.rs:4:5 + | +LL | mod _ { + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-62895.rs:6:5 + | +LL | mod _ { + | ^ expected identifier, found reserved identifier + +error: missing `fn` for function definition + --> $DIR/issue-62895.rs:7:4 + | +LL | pub g() -> is + | ^^^^ +help: add `fn` here to parse `g` as a public function + | +LL | pub fn g() -> is + | ^^ + +error: expected item, found `;` + --> $DIR/issue-62895.rs:10:9 + | +LL | (), w20); + | ^ help: remove this semicolon + +error[E0412]: cannot find type `isizee` in this scope + --> $DIR/issue-62895.rs:5:15 + | +LL | pub fn g() -> isizee { + | ^^^^^^ help: a builtin type with a similar name exists: `isize` + +error[E0308]: mismatched types + --> $DIR/issue-62895.rs:3:11 + | +LL | fn v() -> isize { + | - ^^^^^ expected isize, found () + | | + | this function's body doesn't return + | + = note: expected type `isize` + found type `()` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0308, E0412. +For more information about an error, try `rustc --explain E0308`. From fe2b5bbe6d151ae4713b3bddb4b386f94757435c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 23 Jul 2019 12:51:34 -0700 Subject: [PATCH 28/43] review comments --- src/libsyntax/parse/parser.rs | 7 ++++--- src/test/ui/{issues => parser}/issue-62881.rs | 0 src/test/ui/{issues => parser}/issue-62881.stderr | 0 src/test/ui/{issues => parser}/issue-62895.rs | 0 src/test/ui/{issues => parser}/issue-62895.stderr | 0 5 files changed, 4 insertions(+), 3 deletions(-) rename src/test/ui/{issues => parser}/issue-62881.rs (100%) rename src/test/ui/{issues => parser}/issue-62881.stderr (100%) rename src/test/ui/{issues => parser}/issue-62895.rs (100%) rename src/test/ui/{issues => parser}/issue-62895.stderr (100%) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e494cb472a825..5c26c2bf9b500 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7672,7 +7672,8 @@ impl<'a> Parser<'a> { &mut self.token_cursor.frame.last_token } else if self.token_cursor.stack.get(prev).is_none() { // This can happen due to a bad interaction of two unrelated recovery mechanisms with - // mismatched delimiters *and* recovery lookahead on `pub ident(` likely typo (#62881) + // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(` + // (#62881). return Ok((ret?, TokenStream::new(vec![]))); } else { &mut self.token_cursor.stack[prev].last_token @@ -7686,8 +7687,8 @@ impl<'a> Parser<'a> { debug!("collect_tokens: {}", msg); self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg); // This can happen due to a bad interaction of two unrelated recovery mechanisms - // with mismatched delimiters *and* recovery lookahead on `pub ident(` likely typo - // (#62895, different but similar to the case above) + // with mismatched delimiters *and* recovery lookahead on the likely typo + // `pub ident(` (#62895, different but similar to the case above). return Ok((ret?, TokenStream::new(vec![]))); } }; diff --git a/src/test/ui/issues/issue-62881.rs b/src/test/ui/parser/issue-62881.rs similarity index 100% rename from src/test/ui/issues/issue-62881.rs rename to src/test/ui/parser/issue-62881.rs diff --git a/src/test/ui/issues/issue-62881.stderr b/src/test/ui/parser/issue-62881.stderr similarity index 100% rename from src/test/ui/issues/issue-62881.stderr rename to src/test/ui/parser/issue-62881.stderr diff --git a/src/test/ui/issues/issue-62895.rs b/src/test/ui/parser/issue-62895.rs similarity index 100% rename from src/test/ui/issues/issue-62895.rs rename to src/test/ui/parser/issue-62895.rs diff --git a/src/test/ui/issues/issue-62895.stderr b/src/test/ui/parser/issue-62895.stderr similarity index 100% rename from src/test/ui/issues/issue-62895.stderr rename to src/test/ui/parser/issue-62895.stderr From bd8813e52c5120c40ec3cca096ff4a98fdf56be8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 24 Jul 2019 01:42:39 +0200 Subject: [PATCH 29/43] Add method disambiguation help for trait implementation Closes #51046 Closes #40471 --- src/librustc_typeck/check/method/suggest.rs | 50 ++++++++++++------- .../method-ambig-two-traits-from-impls.rs | 16 ++++++ .../method-ambig-two-traits-from-impls.stderr | 22 ++++++++ .../method-ambig-two-traits-from-impls2.rs | 16 ++++++ ...method-ambig-two-traits-from-impls2.stderr | 22 ++++++++ 5 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/methods/method-ambig-two-traits-from-impls.rs create mode 100644 src/test/ui/methods/method-ambig-two-traits-from-impls.stderr create mode 100644 src/test/ui/methods/method-ambig-two-traits-from-impls2.rs create mode 100644 src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 5febc694def0c..cd4c8a28dab28 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -10,7 +10,6 @@ use rustc::hir::{self, ExprKind, Node, QPath}; use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::hir::map as hir_map; -use rustc::hir::print; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::traits::Obligation; use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; @@ -78,6 +77,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + let print_disambiguation_help = | + err: &mut DiagnosticBuilder<'_>, + trait_name: String, + | { + err.help(&format!( + "to disambiguate the method call, write `{}::{}({}{})` instead", + trait_name, + item_name, + if rcvr_ty.is_region_ptr() && args.is_some() { + if rcvr_ty.is_mutable_pointer() { + "&mut " + } else { + "&" + } + } else { + "" + }, + args.map(|arg| arg + .iter() + .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) + .unwrap_or_else(|_| "...".to_owned())) + .collect::>() + .join(", ") + ).unwrap_or_else(|| "...".to_owned()) + )); + }; + let report_candidates = | span: Span, err: &mut DiagnosticBuilder<'_>, @@ -139,6 +165,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.note(¬e_str); } + if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { + print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id)); + } } CandidateSource::TraitSource(trait_did) => { let item = match self.associated_item( @@ -163,24 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the candidate is defined in the trait `{}`", self.tcx.def_path_str(trait_did)); } - err.help(&format!("to disambiguate the method call, write `{}::{}({}{})` \ - instead", - self.tcx.def_path_str(trait_did), - item_name, - if rcvr_ty.is_region_ptr() && args.is_some() { - if rcvr_ty.is_mutable_pointer() { - "&mut " - } else { - "&" - } - } else { - "" - }, - args.map(|arg| arg.iter() - .map(|arg| print::to_string(print::NO_ANN, - |s| s.print_expr(arg))) - .collect::>() - .join(", ")).unwrap_or_else(|| "...".to_owned()))); + print_disambiguation_help(err, self.tcx.def_path_str(trait_did)); } } } diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.rs b/src/test/ui/methods/method-ambig-two-traits-from-impls.rs new file mode 100644 index 0000000000000..22bf840660536 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.rs @@ -0,0 +1,16 @@ +trait A { fn foo(self); } +trait B { fn foo(self); } + +struct AB {} + +impl A for AB { + fn foo(self) {} +} + +impl B for AB { + fn foo(self) {} +} + +fn main() { + AB {}.foo(); //~ ERROR E0034 +} diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr new file mode 100644 index 0000000000000..0b3724e030fa4 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr @@ -0,0 +1,22 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-ambig-two-traits-from-impls.rs:15:11 + | +LL | AB {}.foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls.rs:7:5 + | +LL | fn foo(self) {} + | ^^^^^^^^^^^^ + = help: to disambiguate the method call, write `A::foo(AB {})` instead +note: candidate #2 is defined in an impl of the trait `B` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls.rs:11:5 + | +LL | fn foo(self) {} + | ^^^^^^^^^^^^ + = help: to disambiguate the method call, write `B::foo(AB {})` instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs b/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs new file mode 100644 index 0000000000000..0a96c1223da36 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs @@ -0,0 +1,16 @@ +trait A { fn foo(); } +trait B { fn foo(); } + +struct AB {} + +impl A for AB { + fn foo() {} +} + +impl B for AB { + fn foo() {} +} + +fn main() { + AB::foo(); //~ ERROR E0034 +} diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr new file mode 100644 index 0000000000000..81c99b33c813e --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -0,0 +1,22 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-ambig-two-traits-from-impls2.rs:15:5 + | +LL | AB::foo(); + | ^^^^^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls2.rs:7:5 + | +LL | fn foo() {} + | ^^^^^^^^ + = help: to disambiguate the method call, write `A::foo(...)` instead +note: candidate #2 is defined in an impl of the trait `B` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls2.rs:11:5 + | +LL | fn foo() {} + | ^^^^^^^^ + = help: to disambiguate the method call, write `B::foo(...)` instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. From be510dbc35960c9d90f42811787eea2acef8ffe5 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 24 Jul 2019 02:25:01 +0200 Subject: [PATCH 30/43] Adjust tests for method disambiguation help --- .../associated-const/associated-const-ambiguity-report.stderr | 2 ++ src/test/ui/error-codes/E0034.stderr | 2 ++ src/test/ui/inference/inference_unstable_featured.stderr | 2 ++ src/test/ui/issues/issue-3702-2.stderr | 2 ++ src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr | 2 ++ .../methods/method-ambig-two-traits-with-default-method.stderr | 2 ++ ...ethod-deref-to-same-trait-object-with-separate-params.stderr | 2 ++ src/test/ui/traits/trait-alias-ambiguous.stderr | 2 ++ 8 files changed, 16 insertions(+) diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr index 5f2b9c47e8c2a..bb217bd182db6 100644 --- a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr @@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32` | LL | const ID: i32 = 1; | ^^^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `Foo::ID(...)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32` --> $DIR/associated-const-ambiguity-report.rs:14:5 | LL | const ID: i32 = 3; | ^^^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `Bar::ID(...)` instead error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index 816a48f102dce..a58d16bfafb59 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `Trait1` for the type `Tes | LL | fn foo() {} | ^^^^^^^^ + = help: to disambiguate the method call, write `Trait1::foo(...)` instead note: candidate #2 is defined in an impl of the trait `Trait2` for the type `Test` --> $DIR/E0034.rs:16:5 | LL | fn foo() {} | ^^^^^^^^ + = help: to disambiguate the method call, write `Trait2::foo(...)` instead error: aborting due to previous error diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr index 08cdb8cc6883f..b06a6298a571c 100644 --- a/src/test/ui/inference/inference_unstable_featured.stderr +++ b/src/test/ui/inference/inference_unstable_featured.stderr @@ -5,7 +5,9 @@ LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ multiple `ipu_flatten` found | = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char` + = help: to disambiguate the method call, write `inference_unstable_iterator::IpuIterator::ipu_flatten('x')` instead = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char` + = help: to disambiguate the method call, write `inference_unstable_itertools::IpuItertools::ipu_flatten('x')` instead error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3702-2.stderr b/src/test/ui/issues/issue-3702-2.stderr index 347a19b687fbb..4d0ff750c254c 100644 --- a/src/test/ui/issues/issue-3702-2.stderr +++ b/src/test/ui/issues/issue-3702-2.stderr @@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type | LL | fn to_int(&self) -> isize { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `ToPrimitive::to_int(&self)` instead note: candidate #2 is defined in an impl of the trait `Add` for the type `isize` --> $DIR/issue-3702-2.rs:14:5 | LL | fn to_int(&self) -> isize { *self } | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `Add::to_int(&self)` instead error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr index 2b87ddfdf98e5..9f46a722a508e 100644 --- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -9,7 +9,9 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` | LL | impl Me2 for usize { fn me(&self) -> usize { *self } } | ^^^^^^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `Me2::me(1_usize)` instead = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize` + = help: to disambiguate the method call, write `ambig_impl_2_lib::Me::me(1_usize)` instead error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr index 5d508d5702258..dc8aef2503739 100644 --- a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr @@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize` | LL | trait Foo { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `Foo::method(1_usize)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize` --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13 | LL | trait Bar { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `Bar::method(1_usize)` instead error: aborting due to previous error diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index d6fac7025a479..283ef8fcba7a4 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -27,11 +27,13 @@ note: candidate #1 is defined in an impl of the trait `internal::X` for the type | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `internal::X::foo(x)` instead note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ + = help: to disambiguate the method call, write `nuisance_foo::NuisanceFoo::foo(x)` instead note: candidate #3 is defined in the trait `FinalFoo` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5 | diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr index b7443269b882d..cde7dd0824924 100644 --- a/src/test/ui/traits/trait-alias-ambiguous.stderr +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -9,11 +9,13 @@ note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `inner::A::foo(t)` instead note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:11:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ + = help: to disambiguate the method call, write `inner::B::foo(t)` instead error: aborting due to previous error From a93fdfedf36dcb909d90cbf963b087c5873bec1d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 16 Jul 2019 21:06:17 +0300 Subject: [PATCH 31/43] Merge `rustc_allocator` into `libsyntax_ext` --- Cargo.lock | 18 ------- src/librustc/lib.rs | 1 - src/librustc/middle/allocator.rs | 16 ------- src/librustc/session/mod.rs | 2 +- src/librustc_allocator/Cargo.toml | 19 -------- src/librustc_codegen_llvm/allocator.rs | 3 +- src/librustc_codegen_llvm/lib.rs | 3 +- src/librustc_codegen_ssa/Cargo.toml | 1 - .../back/symbol_export.rs | 4 +- src/librustc_codegen_ssa/traits/backend.rs | 2 +- src/librustc_driver/Cargo.toml | 2 - src/librustc_interface/Cargo.toml | 1 - src/librustc_interface/passes.rs | 2 +- src/librustc_metadata/creader.rs | 2 +- .../lib.rs => libsyntax/ext/allocator.rs} | 47 +++++++++++-------- src/libsyntax/lib.rs | 1 + .../global_allocator.rs} | 8 ++-- src/libsyntax_ext/lib.rs | 1 + 18 files changed, 41 insertions(+), 92 deletions(-) delete mode 100644 src/librustc/middle/allocator.rs delete mode 100644 src/librustc_allocator/Cargo.toml rename src/{librustc_allocator/lib.rs => libsyntax/ext/allocator.rs} (68%) rename src/{librustc_allocator/expand.rs => libsyntax_ext/global_allocator.rs} (98%) diff --git a/Cargo.lock b/Cargo.lock index bdc746c0bb0e0..8993254627863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2751,20 +2751,6 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc_allocator" -version = "0.0.0" -dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_target 0.0.0", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - [[package]] name = "rustc_apfloat" version = "0.0.0" @@ -2822,7 +2808,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", @@ -2883,7 +2868,6 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_allocator 0.0.0", "rustc_ast_borrowck 0.0.0", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", @@ -2904,7 +2888,6 @@ dependencies = [ "serialize 0.0.0", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", - "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] @@ -2948,7 +2931,6 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_allocator 0.0.0", "rustc_ast_borrowck 0.0.0", "rustc_codegen_ssa 0.0.0", "rustc_codegen_utils 0.0.0", diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 63e0107a4d882..45c6aa63c5581 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -112,7 +112,6 @@ pub mod infer; pub mod lint; pub mod middle { - pub mod allocator; pub mod borrowck; pub mod expr_use_visitor; pub mod cstore; diff --git a/src/librustc/middle/allocator.rs b/src/librustc/middle/allocator.rs deleted file mode 100644 index bb2e3b4ec1971..0000000000000 --- a/src/librustc/middle/allocator.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[derive(Clone, Copy)] -pub enum AllocatorKind { - Global, - DefaultLib, - DefaultExe, -} - -impl AllocatorKind { - pub fn fn_name(&self, base: &str) -> String { - match *self { - AllocatorKind::Global => format!("__rg_{}", base), - AllocatorKind::DefaultLib => format!("__rdl_{}", base), - AllocatorKind::DefaultExe => format!("__rde_{}", base), - } - } -} diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 664926a152f14..d7620817f0448 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fingerprint::Fingerprint; use crate::lint; use crate::lint::builtin::BuiltinLintDiagnostics; -use crate::middle::allocator::AllocatorKind; use crate::middle::dependency_format; use crate::session::config::{OutputType, PrintRequest, SwitchWithOptPath}; use crate::session::search_paths::{PathKind, SearchPath}; @@ -27,6 +26,7 @@ use errors::emitter::HumanReadableErrorType; use errors::annotate_snippet_emitter_writer::{AnnotateSnippetEmitterWriter}; use syntax::ast::{self, NodeId}; use syntax::edition::Edition; +use syntax::ext::allocator::AllocatorKind; use syntax::feature_gate::{self, AttributeType}; use syntax::json::JsonEmitter; use syntax::source_map; diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml deleted file mode 100644 index a964f323c9e7d..0000000000000 --- a/src/librustc_allocator/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_allocator" -version = "0.0.0" -edition = "2018" - -[lib] -path = "lib.rs" -test = false - -[dependencies] -rustc = { path = "../librustc" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_target = { path = "../librustc_target" } -syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } -log = "0.4" -smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index 02a05fd110200..5d43bf6ae28bf 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -2,9 +2,8 @@ use std::ffi::CString; use crate::attributes; use libc::c_uint; -use rustc::middle::allocator::AllocatorKind; use rustc::ty::TyCtxt; -use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; +use syntax::ext::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use crate::ModuleLlvm; use crate::llvm::{self, False, True}; diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 0f0b9f279175c..8dd241bd81a0a 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -32,7 +32,6 @@ extern crate flate2; #[macro_use] extern crate bitflags; extern crate libc; #[macro_use] extern crate rustc; -extern crate rustc_allocator; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; extern crate rustc_incremental; @@ -52,13 +51,13 @@ use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModul use rustc_codegen_ssa::CompiledModule; use errors::{FatalError, Handler}; use rustc::dep_graph::WorkProduct; +use syntax::ext::allocator::AllocatorKind; use syntax_pos::symbol::InternedString; pub use llvm_util::target_features; use std::any::Any; use std::sync::{mpsc, Arc}; use rustc::dep_graph::DepGraph; -use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::session::Session; use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel}; diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index e7ee06df7e12d..3c51c777f53e1 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -24,7 +24,6 @@ serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } rustc = { path = "../librustc" } -rustc_allocator = { path = "../librustc_allocator" } rustc_apfloat = { path = "../librustc_apfloat" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_data_structures = { path = "../librustc_data_structures"} diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index c5553fa93cf67..2d9220f897cff 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -1,3 +1,4 @@ +use std::collections::hash_map::Entry::*; use std::sync::Arc; use rustc::ty::Instance; @@ -12,9 +13,8 @@ use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::query::Providers; use rustc::ty::subst::SubstsRef; use rustc::util::nodemap::{FxHashMap, DefIdMap}; -use rustc_allocator::ALLOCATOR_METHODS; use rustc_data_structures::indexed_vec::IndexVec; -use std::collections::hash_map::Entry::*; +use syntax::ext::allocator::ALLOCATOR_METHODS; pub type ExportedSymbols = FxHashMap< CrateNum, diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index 9d5aaa7655db8..9fbb44dcc9959 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -3,12 +3,12 @@ use rustc::ty::Ty; use super::write::WriteBackendMethods; use super::CodegenObject; -use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::EncodedMetadata; use rustc::session::{Session, config}; use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use std::sync::Arc; +use syntax::ext::allocator::AllocatorKind; use syntax_pos::symbol::InternedString; pub trait BackendTypes { diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index d4c30dc6c4507..aafc78cf94eff 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -16,7 +16,6 @@ log = "0.4" env_logger = { version = "0.5", default-features = false } rayon = { version = "0.2.0", package = "rustc-rayon" } rustc = { path = "../librustc" } -rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } rustc_ast_borrowck = { path = "../librustc_ast_borrowck" } rustc_data_structures = { path = "../librustc_data_structures" } @@ -37,5 +36,4 @@ rustc_interface = { path = "../librustc_interface" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } -syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index a0efec5ee7a7f..44fe3ff2c9df8 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -18,7 +18,6 @@ syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } serialize = { path = "../libserialize" } rustc = { path = "../librustc" } -rustc_allocator = { path = "../librustc_allocator" } rustc_ast_borrowck = { path = "../librustc_ast_borrowck" } rustc_incremental = { path = "../librustc_incremental" } rustc_traits = { path = "../librustc_traits" } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 6bf56bf851553..d4a922ddd49e3 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -497,7 +497,7 @@ fn configure_and_expand_inner<'a>( if has_global_allocator { // Expand global allocators, which are treated as an in-tree proc macro time(sess, "creating allocators", || { - allocator::expand::modify( + syntax_ext::global_allocator::modify( &sess.parse_sess, &mut resolver, &mut krate, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 126cfec157ff3..31f70155b4e37 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -8,7 +8,6 @@ use rustc_data_structures::sync::{Lrc, RwLock, Lock}; use rustc::hir::def_id::CrateNum; use rustc_data_structures::svh::Svh; -use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::DepKind; use rustc::mir::interpret::AllocDecodingState; use rustc::session::{Session, CrateDisambiguator}; @@ -26,6 +25,7 @@ use std::{cmp, fs}; use syntax::ast; use syntax::attr; +use syntax::ext::allocator::AllocatorKind; use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use syntax::symbol::{Symbol, sym}; use syntax::visit; diff --git a/src/librustc_allocator/lib.rs b/src/libsyntax/ext/allocator.rs similarity index 68% rename from src/librustc_allocator/lib.rs rename to src/libsyntax/ext/allocator.rs index 8d380c47bc4a3..f2c6bf27cee0c 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/libsyntax/ext/allocator.rs @@ -1,10 +1,33 @@ -#![feature(nll)] -#![feature(rustc_private)] +#[derive(Clone, Copy)] +pub enum AllocatorKind { + Global, + DefaultLib, + DefaultExe, +} -#![deny(rust_2018_idioms)] -#![deny(unused_lifetimes)] +impl AllocatorKind { + pub fn fn_name(&self, base: &str) -> String { + match *self { + AllocatorKind::Global => format!("__rg_{}", base), + AllocatorKind::DefaultLib => format!("__rdl_{}", base), + AllocatorKind::DefaultExe => format!("__rde_{}", base), + } + } +} -pub mod expand; +pub enum AllocatorTy { + Layout, + Ptr, + ResultPtr, + Unit, + Usize, +} + +pub struct AllocatorMethod { + pub name: &'static str, + pub inputs: &'static [AllocatorTy], + pub output: AllocatorTy, +} pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ AllocatorMethod { @@ -28,17 +51,3 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ output: AllocatorTy::ResultPtr, }, ]; - -pub struct AllocatorMethod { - pub name: &'static str, - pub inputs: &'static [AllocatorTy], - pub output: AllocatorTy, -} - -pub enum AllocatorTy { - Layout, - Ptr, - ResultPtr, - Unit, - Usize, -} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 3dea1977c4dac..e3bc72335aba0 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -165,6 +165,7 @@ pub mod print { pub mod ext { pub use syntax_pos::hygiene; + pub mod allocator; pub mod base; pub mod build; pub mod derive; diff --git a/src/librustc_allocator/expand.rs b/src/libsyntax_ext/global_allocator.rs similarity index 98% rename from src/librustc_allocator/expand.rs rename to src/libsyntax_ext/global_allocator.rs index af63fffc0f9b4..e8f94bff14470 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,5 +1,4 @@ use log::debug; -use rustc::middle::allocator::AllocatorKind; use smallvec::{smallvec, SmallVec}; use syntax::{ ast::{ @@ -11,6 +10,7 @@ use syntax::{ respan, ExpnInfo, ExpnKind, }, ext::{ + allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}, base::{ExtCtxt, MacroKind, Resolver}, build::AstBuilder, expand::ExpansionConfig, @@ -23,14 +23,12 @@ use syntax::{ }; use syntax_pos::Span; -use crate::{AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; - pub fn modify( sess: &ParseSess, resolver: &mut dyn Resolver, krate: &mut Crate, crate_name: String, - handler: &rustc_errors::Handler, + handler: &errors::Handler, ) { ExpandAllocatorDirectives { handler, @@ -44,7 +42,7 @@ pub fn modify( struct ExpandAllocatorDirectives<'a> { found: bool, - handler: &'a rustc_errors::Handler, + handler: &'a errors::Handler, sess: &'a ParseSess, resolver: &'a mut dyn Resolver, crate_name: Option, diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 7de90278ed732..cd7ac5fe2c66c 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -37,6 +37,7 @@ mod test_case; mod trace_macros; pub mod deriving; +pub mod global_allocator; pub mod proc_macro_decls; pub mod proc_macro_impl; From 433024147ae1e9795fe7e94cb1810a17fd37fa51 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 19 Jul 2019 00:24:58 +0300 Subject: [PATCH 32/43] syntax_ext: Turn `#[global_allocator]` into a regular attribute macro --- src/libcore/macros.rs | 7 + src/librustc/middle/dead.rs | 5 - src/librustc_interface/passes.rs | 15 +- src/librustc_metadata/creader.rs | 29 +-- src/librustc_metadata/lib.rs | 5 +- src/librustc_passes/ast_validation.rs | 10 +- src/libsyntax/ext/allocator.rs | 22 ++ src/libsyntax/feature_gate.rs | 1 - src/libsyntax_ext/global_allocator.rs | 223 ++++++------------ src/libsyntax_ext/lib.rs | 8 +- .../run-pass/allocator/custom-in-block.rs | 21 ++ .../run-pass/allocator/custom-in-submodule.rs | 25 ++ src/test/ui/allocator-submodule.rs | 28 --- src/test/ui/allocator-submodule.stderr | 8 - src/test/ui/allocator/allocator-args.rs | 13 + src/test/ui/allocator/allocator-args.stderr | 8 + src/test/ui/allocator/two-allocators.rs | 2 +- src/test/ui/allocator/two-allocators.stderr | 8 +- src/tools/tidy/src/features.rs | 2 +- 19 files changed, 205 insertions(+), 235 deletions(-) create mode 100644 src/test/run-pass/allocator/custom-in-block.rs create mode 100644 src/test/run-pass/allocator/custom-in-submodule.rs delete mode 100644 src/test/ui/allocator-submodule.rs delete mode 100644 src/test/ui/allocator-submodule.stderr create mode 100644 src/test/ui/allocator/allocator-args.rs create mode 100644 src/test/ui/allocator/allocator-args.stderr diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 296bb43f9fad4..17781798946ed 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -1281,6 +1281,13 @@ mod builtin { #[rustc_macro_transparency = "semitransparent"] pub macro test_case($item:item) { /* compiler built-in */ } + /// Attribute macro applied to a static to register it as a global allocator. + #[stable(feature = "global_allocator", since = "1.28.0")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + #[rustc_macro_transparency = "semitransparent"] + pub macro global_allocator($item:item) { /* compiler built-in */ } + /// Derive macro generating an impl of the trait `Clone`. #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 4c27318c3e19b..88de77829a6e0 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -320,11 +320,6 @@ fn has_allow_dead_code_or_lang_attr( return true; } - // Don't lint about global allocators - if attr::contains_name(attrs, sym::global_allocator) { - return true; - } - let def_id = tcx.hir().local_def_id(id); let cg_attrs = tcx.codegen_fn_attrs(def_id); diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index d4a922ddd49e3..b460a908f1b12 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -468,7 +468,7 @@ fn configure_and_expand_inner<'a>( util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate); } - let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { + let has_proc_macro_decls = time(sess, "AST validation", || { ast_validation::check_crate(sess, &krate) }); @@ -494,19 +494,6 @@ fn configure_and_expand_inner<'a>( }); } - if has_global_allocator { - // Expand global allocators, which are treated as an in-tree proc macro - time(sess, "creating allocators", || { - syntax_ext::global_allocator::modify( - &sess.parse_sess, - &mut resolver, - &mut krate, - crate_name.to_string(), - sess.diagnostic(), - ) - }); - } - // Done with macro expansion! if sess.opts.debugging_opts.input_stats { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 31f70155b4e37..3404ec5e173bd 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -25,10 +25,9 @@ use std::{cmp, fs}; use syntax::ast; use syntax::attr; -use syntax::ext::allocator::AllocatorKind; +use syntax::ext::allocator::{global_allocator_spans, AllocatorKind}; use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; use syntax::symbol::{Symbol, sym}; -use syntax::visit; use syntax::{span_err, span_fatal}; use syntax_pos::{Span, DUMMY_SP}; use log::{debug, info, log_enabled}; @@ -888,7 +887,14 @@ impl<'a> CrateLoader<'a> { } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { - let has_global_allocator = has_global_allocator(krate); + let has_global_allocator = match &*global_allocator_spans(krate) { + [span1, span2, ..] => { + self.sess.struct_span_err(*span2, "cannot define multiple global allocators") + .span_note(*span1, "the previous global allocator is defined here").emit(); + true + } + spans => !spans.is_empty() + }; self.sess.has_global_allocator.set(has_global_allocator); // Check to see if we actually need an allocator. This desire comes @@ -975,25 +981,8 @@ impl<'a> CrateLoader<'a> { that implements the GlobalAlloc trait."); } self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib)); - - fn has_global_allocator(krate: &ast::Crate) -> bool { - struct Finder(bool); - let mut f = Finder(false); - visit::walk_crate(&mut f, krate); - return f.0; - - impl<'ast> visit::Visitor<'ast> for Finder { - fn visit_item(&mut self, i: &'ast ast::Item) { - if attr::contains_name(&i.attrs, sym::global_allocator) { - self.0 = true; - } - visit::walk_item(self, i) - } - } - } } - fn inject_dependency_if(&self, krate: CrateNum, what: &str, diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 826349362db25..30bb37e4680d1 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -1,6 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] +#![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] #![feature(libc)] @@ -8,9 +9,9 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustc_diagnostic_macros)] -#![feature(crate_visibility_modifier)] -#![feature(specialization)] #![feature(rustc_private)] +#![feature(slice_patterns)] +#![feature(specialization)] #![recursion_limit="256"] diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 560635962995c..b550029d9786d 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -51,7 +51,6 @@ impl OuterImplTrait { struct AstValidator<'a> { session: &'a Session, has_proc_macro_decls: bool, - has_global_allocator: bool, /// Used to ban nested `impl Trait`, e.g., `impl Into`. /// Nested `impl Trait` _is_ allowed in associated type position, @@ -539,10 +538,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } - if attr::contains_name(&item.attrs, sym::global_allocator) { - self.has_global_allocator = true; - } - match item.node { ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => { self.invalid_visibility(&item.vis, None); @@ -848,11 +843,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } -pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { +pub fn check_crate(session: &Session, krate: &Crate) -> bool { let mut validator = AstValidator { session, has_proc_macro_decls: false, - has_global_allocator: false, outer_impl_trait: None, is_impl_trait_banned: false, is_assoc_ty_bound_banned: false, @@ -861,5 +855,5 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) { }; visit::walk_crate(&mut validator, krate); - (validator.has_proc_macro_decls, validator.has_global_allocator) + validator.has_proc_macro_decls } diff --git a/src/libsyntax/ext/allocator.rs b/src/libsyntax/ext/allocator.rs index f2c6bf27cee0c..99aeb5414c5d8 100644 --- a/src/libsyntax/ext/allocator.rs +++ b/src/libsyntax/ext/allocator.rs @@ -1,3 +1,7 @@ +use crate::{ast, attr, visit}; +use crate::symbol::{sym, Symbol}; +use syntax_pos::Span; + #[derive(Clone, Copy)] pub enum AllocatorKind { Global, @@ -51,3 +55,21 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ output: AllocatorTy::ResultPtr, }, ]; + +pub fn global_allocator_spans(krate: &ast::Crate) -> Vec { + struct Finder { name: Symbol, spans: Vec } + impl<'ast> visit::Visitor<'ast> for Finder { + fn visit_item(&mut self, item: &'ast ast::Item) { + if item.ident.name == self.name && + attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { + self.spans.push(item.span); + } + visit::walk_item(self, item) + } + } + + let name = Symbol::intern(&AllocatorKind::Global.fn_name("alloc")); + let mut f = Finder { name, spans: Vec::new() }; + visit::walk_crate(&mut f, krate); + f.spans +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 43f0eaae7c97e..214160f10790d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1117,7 +1117,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[rustc_const_unstable]` attribute \ is an internal feature", cfg_fn!(rustc_const_unstable))), - (sym::global_allocator, Normal, template!(Word), Ungated), (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, sym::allocator_internals, "the `#[default_lib_allocator]` \ diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index e8f94bff14470..785636abb121f 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,162 +1,95 @@ -use log::debug; -use smallvec::{smallvec, SmallVec}; -use syntax::{ - ast::{ - self, Arg, Attribute, Crate, Expr, FnHeader, Generics, Ident, Item, ItemKind, - Mac, Mod, Mutability, Ty, TyKind, Unsafety, VisibilityKind, - }, - attr, - source_map::{ - respan, ExpnInfo, ExpnKind, - }, - ext::{ - allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}, - base::{ExtCtxt, MacroKind, Resolver}, - build::AstBuilder, - expand::ExpansionConfig, - hygiene::ExpnId, - }, - mut_visit::{self, MutVisitor}, - parse::ParseSess, - ptr::P, - symbol::{kw, sym} -}; +use errors::Applicability; +use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item}; +use syntax::ast::{ItemKind, Mutability, Ty, TyKind, Unsafety, VisibilityKind}; +use syntax::source_map::respan; +use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; +use syntax::ext::base::{Annotatable, ExtCtxt}; +use syntax::ext::build::AstBuilder; +use syntax::ext::hygiene::SyntaxContext; +use syntax::ptr::P; +use syntax::symbol::{kw, sym}; use syntax_pos::Span; -pub fn modify( - sess: &ParseSess, - resolver: &mut dyn Resolver, - krate: &mut Crate, - crate_name: String, - handler: &errors::Handler, -) { - ExpandAllocatorDirectives { - handler, - sess, - resolver, - found: false, - crate_name: Some(crate_name), - in_submod: -1, // -1 to account for the "root" module - }.visit_crate(krate); -} - -struct ExpandAllocatorDirectives<'a> { - found: bool, - handler: &'a errors::Handler, - sess: &'a ParseSess, - resolver: &'a mut dyn Resolver, - crate_name: Option, - - // For now, we disallow `global_allocator` in submodules because hygiene is hard. Keep track of - // whether we are in a submodule or not. If `in_submod > 0` we are in a submodule. - in_submod: isize, -} - -impl MutVisitor for ExpandAllocatorDirectives<'_> { - fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - debug!("in submodule {}", self.in_submod); - - if !attr::contains_name(&item.attrs, sym::global_allocator) { - return mut_visit::noop_flat_map_item(item, self); - } - - match item.node { - ItemKind::Static(..) => {} - _ => { - self.handler - .span_err(item.span, "allocators must be statics"); - return smallvec![item]; - } - } - - if self.in_submod > 0 { - self.handler - .span_err(item.span, "`global_allocator` cannot be used in submodules"); - return smallvec![item]; - } +pub fn expand( + ecx: &mut ExtCtxt<'_>, + span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec { + if !meta_item.is_word() { + let msg = format!("malformed `{}` attribute input", meta_item.path); + ecx.parse_sess.span_diagnostic.struct_span_err(span, &msg) + .span_suggestion( + span, + "must be of the form", + format!("`#[{}]`", meta_item.path), + Applicability::MachineApplicable + ).emit(); + } - if self.found { - self.handler - .span_err(item.span, "cannot define more than one `#[global_allocator]`"); - return smallvec![item]; + let not_static = |item: Annotatable| { + ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics"); + vec![item] + }; + let item = match item { + Annotatable::Item(item) => match item.node { + ItemKind::Static(..) => item, + _ => return not_static(Annotatable::Item(item)), } - self.found = true; - - // Create a new expansion for the generated allocator code. - let span = item.span.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::global_allocator), item.span, self.sess.edition, - [sym::rustc_attrs][..].into(), - )); - - // Create an expansion config - let ecfg = ExpansionConfig::default(self.crate_name.take().unwrap()); - - // Generate a bunch of new items using the AllocFnFactory - let mut f = AllocFnFactory { - span, - kind: AllocatorKind::Global, - global: item.ident, - core: Ident::with_empty_ctxt(sym::core), - cx: ExtCtxt::new(self.sess, ecfg, self.resolver), - }; - - // We will generate a new submodule. To `use` the static from that module, we need to get - // the `super::...` path. - let super_path = f.cx.path(f.span, vec![Ident::with_empty_ctxt(kw::Super), f.global]); - - // Generate the items in the submodule - let mut items = vec![ - // import `core` to use allocators - f.cx.item_extern_crate(f.span, f.core), - // `use` the `global_allocator` in `super` - f.cx.item_use_simple( - f.span, - respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), - super_path, - ), - ]; - - // Add the allocator methods to the submodule - items.extend( - ALLOCATOR_METHODS - .iter() - .map(|method| f.allocator_fn(method)), - ); - - // Generate the submodule itself - let name = f.kind.fn_name("allocator_abi"); - let allocator_abi = Ident::from_str(&name).gensym(); - let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); - let module = f.cx.monotonic_expander().flat_map_item(module).pop().unwrap(); - - // Return the item and new submodule - smallvec![item, module] - } + _ => return not_static(item), + }; + + // Generate a bunch of new items using the AllocFnFactory + let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.mark)); + let f = AllocFnFactory { + span, + kind: AllocatorKind::Global, + global: item.ident, + core: Ident::with_empty_ctxt(sym::core), + cx: ecx, + }; + + // We will generate a new submodule. To `use` the static from that module, we need to get + // the `super::...` path. + let super_path = f.cx.path(f.span, vec![Ident::with_empty_ctxt(kw::Super), f.global]); + + // Generate the items in the submodule + let mut items = vec![ + // import `core` to use allocators + f.cx.item_extern_crate(f.span, f.core), + // `use` the `global_allocator` in `super` + f.cx.item_use_simple( + f.span, + respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), + super_path, + ), + ]; + + // Add the allocator methods to the submodule + items.extend( + ALLOCATOR_METHODS + .iter() + .map(|method| f.allocator_fn(method)), + ); - // If we enter a submodule, take note. - fn visit_mod(&mut self, m: &mut Mod) { - debug!("enter submodule"); - self.in_submod += 1; - mut_visit::noop_visit_mod(m, self); - self.in_submod -= 1; - debug!("exit submodule"); - } + // Generate the submodule itself + let name = f.kind.fn_name("allocator_abi"); + let allocator_abi = Ident::from_str(&name).gensym(); + let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); - // `visit_mac` is disabled by default. Enable it here. - fn visit_mac(&mut self, mac: &mut Mac) { - mut_visit::noop_visit_mac(mac, self) - } + // Return the item and new submodule + vec![Annotatable::Item(item), Annotatable::Item(module)] } -struct AllocFnFactory<'a> { +struct AllocFnFactory<'a, 'b> { span: Span, kind: AllocatorKind, global: Ident, core: Ident, - cx: ExtCtxt<'a>, + cx: &'b ExtCtxt<'a>, } -impl AllocFnFactory<'_> { +impl AllocFnFactory<'_, '_> { fn allocator_fn(&self, method: &AllocatorMethod) -> P { let mut abi_args = Vec::new(); let mut i = 0; diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index cd7ac5fe2c66c..400bfe796bb07 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -29,6 +29,7 @@ mod concat_idents; mod env; mod format; mod format_foreign; +mod global_allocator; mod global_asm; mod log_syntax; mod proc_macro_server; @@ -37,7 +38,6 @@ mod test_case; mod trace_macros; pub mod deriving; -pub mod global_allocator; pub mod proc_macro_decls; pub mod proc_macro_impl; @@ -152,6 +152,12 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_bench)), edition ) }); + register(sym::global_allocator, SyntaxExtension { + allow_internal_unstable: Some([sym::rustc_attrs][..].into()), + ..SyntaxExtension::default( + SyntaxExtensionKind::LegacyAttr(Box::new(global_allocator::expand)), edition + ) + }); let allow_internal_unstable = Some([sym::fmt_internals][..].into()); register(sym::format_args, SyntaxExtension { diff --git a/src/test/run-pass/allocator/custom-in-block.rs b/src/test/run-pass/allocator/custom-in-block.rs new file mode 100644 index 0000000000000..506154ec601ae --- /dev/null +++ b/src/test/run-pass/allocator/custom-in-block.rs @@ -0,0 +1,21 @@ +// run-pass +// no-prefer-dynamic +// aux-build:custom.rs +// aux-build:helper.rs + +extern crate custom; +extern crate helper; + +use custom::A; +use std::sync::atomic::{AtomicUsize, Ordering}; + +fn main() { + #[global_allocator] + pub static GLOBAL: A = A(AtomicUsize::new(0)); + + let s = Box::new(0); + helper::work_with(&s); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1); + drop(s); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2); +} diff --git a/src/test/run-pass/allocator/custom-in-submodule.rs b/src/test/run-pass/allocator/custom-in-submodule.rs new file mode 100644 index 0000000000000..f9c4ad7668b63 --- /dev/null +++ b/src/test/run-pass/allocator/custom-in-submodule.rs @@ -0,0 +1,25 @@ +// run-pass +// no-prefer-dynamic +// aux-build:custom.rs +// aux-build:helper.rs + +extern crate custom; +extern crate helper; + +use custom::A; +use std::sync::atomic::{AtomicUsize, Ordering}; + +mod submodule { + use super::*; + + #[global_allocator] + pub static GLOBAL: A = A(AtomicUsize::new(0)); +} + +fn main() { + let s = Box::new(0); + helper::work_with(&s); + assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), 1); + drop(s); + assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), 2); +} diff --git a/src/test/ui/allocator-submodule.rs b/src/test/ui/allocator-submodule.rs deleted file mode 100644 index 7a8d86b8da18c..0000000000000 --- a/src/test/ui/allocator-submodule.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Tests that it is possible to create a global allocator in a submodule, rather than in the crate -// root. - -extern crate alloc; - -use std::{ - alloc::{GlobalAlloc, Layout}, - ptr, -}; - -struct MyAlloc; - -unsafe impl GlobalAlloc for MyAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - ptr::null_mut() - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {} -} - -mod submod { - use super::MyAlloc; - - #[global_allocator] - static MY_HEAP: MyAlloc = MyAlloc; //~ ERROR global_allocator -} - -fn main() {} diff --git a/src/test/ui/allocator-submodule.stderr b/src/test/ui/allocator-submodule.stderr deleted file mode 100644 index 91c7c0f6b8e24..0000000000000 --- a/src/test/ui/allocator-submodule.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `global_allocator` cannot be used in submodules - --> $DIR/allocator-submodule.rs:25:5 - | -LL | static MY_HEAP: MyAlloc = MyAlloc; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/allocator/allocator-args.rs b/src/test/ui/allocator/allocator-args.rs new file mode 100644 index 0000000000000..1033f947c5f5b --- /dev/null +++ b/src/test/ui/allocator/allocator-args.rs @@ -0,0 +1,13 @@ +use std::alloc::{GlobalAlloc, Layout}; + +struct A; + +unsafe impl GlobalAlloc for A { + unsafe fn alloc(&self, _: Layout) -> *mut u8 { panic!() } + unsafe fn dealloc(&self, _: *mut u8, _: Layout) { panic!() } +} + +#[global_allocator(malloc)] //~ ERROR malformed `global_allocator` attribute input +static S: A = A; + +fn main() {} diff --git a/src/test/ui/allocator/allocator-args.stderr b/src/test/ui/allocator/allocator-args.stderr new file mode 100644 index 0000000000000..d8ae7130e5d3d --- /dev/null +++ b/src/test/ui/allocator/allocator-args.stderr @@ -0,0 +1,8 @@ +error: malformed `global_allocator` attribute input + --> $DIR/allocator-args.rs:10:1 + | +LL | #[global_allocator(malloc)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: ``#[global_allocator]`` + +error: aborting due to previous error + diff --git a/src/test/ui/allocator/two-allocators.rs b/src/test/ui/allocator/two-allocators.rs index 0f81fc41823ba..aa1291e77aecb 100644 --- a/src/test/ui/allocator/two-allocators.rs +++ b/src/test/ui/allocator/two-allocators.rs @@ -4,6 +4,6 @@ use std::alloc::System; static A: System = System; #[global_allocator] static B: System = System; -//~^ ERROR: cannot define more than one `#[global_allocator]` +//~^ ERROR: cannot define multiple global allocators fn main() {} diff --git a/src/test/ui/allocator/two-allocators.stderr b/src/test/ui/allocator/two-allocators.stderr index 6b0c2b2a25d38..ed0aa13eb8078 100644 --- a/src/test/ui/allocator/two-allocators.stderr +++ b/src/test/ui/allocator/two-allocators.stderr @@ -1,8 +1,14 @@ -error: cannot define more than one `#[global_allocator]` +error: cannot define multiple global allocators --> $DIR/two-allocators.rs:6:1 | LL | static B: System = System; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the previous global allocator is defined here + --> $DIR/two-allocators.rs:4:1 + | +LL | static A: System = System; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 1841beb1fd116..ade61abb7485e 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -344,7 +344,7 @@ fn get_and_check_lib_features(base_src_path: &Path, Ok((name, f)) => { let mut check_features = |f: &Feature, list: &Features, display: &str| { if let Some(ref s) = list.get(name) { - if f.tracking_issue != s.tracking_issue { + if f.tracking_issue != s.tracking_issue && f.level != Status::Stable { tidy_error!(bad, "{}:{}: mismatches the `issue` in {}", file.display(), From 76b1ffaf6c70abd3fa4da2e694dc709116258098 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 19 Jul 2019 02:10:36 +0300 Subject: [PATCH 33/43] syntax_ext: Reuse built-in attribute template checking for macro attributes --- src/librustc_lint/builtin.rs | 4 +- src/libsyntax/attr/builtin.rs | 96 +++++++++++++++++++ src/libsyntax/feature_gate.rs | 90 +---------------- src/libsyntax_ext/global_allocator.rs | 19 +--- src/libsyntax_ext/test.rs | 11 ++- src/libsyntax_ext/test_case.rs | 7 +- src/test/ui/allocator/allocator-args.stderr | 2 +- .../issue-43106-gating-of-bench.stderr | 8 +- .../issue-43106-gating-of-test.stderr | 8 +- 9 files changed, 132 insertions(+), 113 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 4105e030477f1..b63d14ca949ee 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -36,10 +36,10 @@ use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; use syntax::ptr::P; use syntax::ast::Expr; -use syntax::attr::{self, HasAttrs}; +use syntax::attr::{self, HasAttrs, AttributeTemplate}; use syntax::source_map::Spanned; use syntax::edition::Edition; -use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType}; +use syntax::feature_gate::{AttributeGate, AttributeType}; use syntax::feature_gate::{Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::{Symbol, kw, sym}; diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index b41f1047fcba3..713094416524b 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -1,6 +1,9 @@ //! Parsing and validation of builtin attributes use crate::ast::{self, Attribute, MetaItem, NestedMetaItem}; +use crate::early_buffered_lints::BufferedEarlyLintId; +use crate::ext::base::ExtCtxt; +use crate::ext::build::AstBuilder; use crate::feature_gate::{Features, GatedCfg}; use crate::parse::ParseSess; @@ -19,6 +22,27 @@ enum AttrError { UnsupportedLiteral(&'static str, /* is_bytestr */ bool), } +/// A template that the attribute input must match. +/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. +#[derive(Clone, Copy)] +pub struct AttributeTemplate { + crate word: bool, + crate list: Option<&'static str>, + crate name_value_str: Option<&'static str>, +} + +impl AttributeTemplate { + /// Checks that the given meta-item is compatible with this template. + fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { + match meta_item_kind { + ast::MetaItemKind::Word => self.word, + ast::MetaItemKind::List(..) => self.list.is_some(), + ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(), + ast::MetaItemKind::NameValue(..) => false, + } + } +} + fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { let diag = &sess.span_diagnostic; match error { @@ -901,3 +925,75 @@ pub fn find_transparency( let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque }; (transparency.map_or(fallback, |t| t.0), error) } + +pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { + // All the built-in macro attributes are "words" at the moment. + let template = AttributeTemplate { word: true, list: None, name_value_str: None }; + let attr = ecx.attribute(meta_item.span, meta_item.clone()); + check_builtin_attribute(ecx.parse_sess, &attr, name, template); +} + +crate fn check_builtin_attribute( + sess: &ParseSess, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate +) { + // Some special attributes like `cfg` must be checked + // before the generic check, so we skip them here. + let should_skip = |name| name == sym::cfg; + // Some of previously accepted forms were used in practice, + // report them as warnings for now. + let should_warn = |name| name == sym::doc || name == sym::ignore || + name == sym::inline || name == sym::link; + + match attr.parse_meta(sess) { + Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { + let error_msg = format!("malformed `{}` attribute input", name); + let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; + let mut first = true; + if template.word { + first = false; + let code = format!("#[{}]", name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.list { + if !first { + msg.push_str(" or "); + } + first = false; + let code = format!("#[{}({})]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.name_value_str { + if !first { + msg.push_str(" or "); + } + let code = format!("#[{} = \"{}\"]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if should_warn(name) { + sess.buffer_lint( + BufferedEarlyLintId::IllFormedAttributeInput, + meta.span, + ast::CRATE_NODE_ID, + &msg, + ); + } else { + sess.span_diagnostic.struct_span_err(meta.span, &error_msg) + .span_suggestions( + meta.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ).emit(); + } + } + Err(mut err) => err.emit(), + } +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 214160f10790d..72184b0bd6400 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -19,8 +19,7 @@ use crate::ast::{ self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd, }; -use crate::attr; -use crate::early_buffered_lints::BufferedEarlyLintId; +use crate::attr::{self, check_builtin_attribute, AttributeTemplate}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; @@ -906,27 +905,6 @@ pub enum AttributeGate { Ungated, } -/// A template that the attribute input must match. -/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. -#[derive(Clone, Copy)] -pub struct AttributeTemplate { - word: bool, - list: Option<&'static str>, - name_value_str: Option<&'static str>, -} - -impl AttributeTemplate { - /// Checks that the given meta-item is compatible with this template. - fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { - match meta_item_kind { - ast::MetaItemKind::Word => self.word, - ast::MetaItemKind::List(..) => self.list.is_some(), - ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(), - ast::MetaItemKind::NameValue(..) => false, - } - } -} - /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -1901,70 +1879,6 @@ impl<'a> PostExpansionVisitor<'a> { Abi::System => {} } } - - fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: Symbol, - template: AttributeTemplate) { - // Some special attributes like `cfg` must be checked - // before the generic check, so we skip them here. - let should_skip = |name| name == sym::cfg; - // Some of previously accepted forms were used in practice, - // report them as warnings for now. - let should_warn = |name| name == sym::doc || name == sym::ignore || - name == sym::inline || name == sym::link; - - match attr.parse_meta(self.context.parse_sess) { - Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { - let error_msg = format!("malformed `{}` attribute input", name); - let mut msg = "attribute must be of the form ".to_owned(); - let mut suggestions = vec![]; - let mut first = true; - if template.word { - first = false; - let code = format!("#[{}]", name); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#[{}({})]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#[{} = \"{}\"]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if should_warn(name) { - self.context.parse_sess.buffer_lint( - BufferedEarlyLintId::IllFormedAttributeInput, - meta.span, - ast::CRATE_NODE_ID, - &msg, - ); - } else { - self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg) - .span_suggestions( - meta.span, - if suggestions.len() == 1 { - "must be of the form" - } else { - "the following are the possible correct uses" - }, - suggestions.into_iter(), - Applicability::HasPlaceholders, - ).emit(); - } - } - Err(mut err) => err.emit(), - } - } } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { @@ -2005,7 +1919,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some(&(name, _, template, _)) if name != sym::rustc_dummy => - self.check_builtin_attribute(attr, name, template), + check_builtin_attribute(self.context.parse_sess, attr, name, template), _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { if token == token::Eq { // All key-value attributes are restricted to meta-item syntax. diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index 785636abb121f..196db3d7baa5b 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,31 +1,22 @@ -use errors::Applicability; -use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item}; use syntax::ast::{ItemKind, Mutability, Ty, TyKind, Unsafety, VisibilityKind}; -use syntax::source_map::respan; +use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item}; +use syntax::attr::check_builtin_macro_attribute; use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; +use syntax::source_map::respan; use syntax::symbol::{kw, sym}; use syntax_pos::Span; pub fn expand( ecx: &mut ExtCtxt<'_>, - span: Span, + _span: Span, meta_item: &ast::MetaItem, item: Annotatable, ) -> Vec { - if !meta_item.is_word() { - let msg = format!("malformed `{}` attribute input", meta_item.path); - ecx.parse_sess.span_diagnostic.struct_span_err(span, &msg) - .span_suggestion( - span, - "must be of the form", - format!("`#[{}]`", meta_item.path), - Applicability::MachineApplicable - ).emit(); - } + check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator); let not_static = |item: Annotatable| { ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics"); diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index f8755a1d1d791..d381c42f9ce84 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -1,31 +1,34 @@ /// The expansion from a test function to the appropriate test struct for libtest /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. +use syntax::ast; +use syntax::attr::{self, check_builtin_macro_attribute}; use syntax::ext::base::*; use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::SyntaxContext; -use syntax::attr; -use syntax::ast; use syntax::print::pprust; use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; + use std::iter; pub fn expand_test( cx: &mut ExtCtxt<'_>, attr_sp: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, item: Annotatable, ) -> Vec { + check_builtin_macro_attribute(cx, meta_item, sym::test); expand_test_or_bench(cx, attr_sp, item, false) } pub fn expand_bench( cx: &mut ExtCtxt<'_>, attr_sp: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, item: Annotatable, ) -> Vec { + check_builtin_macro_attribute(cx, meta_item, sym::bench); expand_test_or_bench(cx, attr_sp, item, true) } diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs index 355f2428e0806..ea4a8d541ab99 100644 --- a/src/libsyntax_ext/test_case.rs +++ b/src/libsyntax_ext/test_case.rs @@ -9,10 +9,11 @@ // We mark item with an inert attribute "rustc_test_marker" which the test generation // logic will pick up on. +use syntax::ast; +use syntax::attr::check_builtin_macro_attribute; use syntax::ext::base::*; use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::SyntaxContext; -use syntax::ast; use syntax::source_map::respan; use syntax::symbol::sym; use syntax_pos::Span; @@ -20,9 +21,11 @@ use syntax_pos::Span; pub fn expand( ecx: &mut ExtCtxt<'_>, attr_sp: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, anno_item: Annotatable ) -> Vec { + check_builtin_macro_attribute(ecx, meta_item, sym::test_case); + if !ecx.ecfg.should_test { return vec![]; } let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id)); diff --git a/src/test/ui/allocator/allocator-args.stderr b/src/test/ui/allocator/allocator-args.stderr index d8ae7130e5d3d..dfff2a7e7094d 100644 --- a/src/test/ui/allocator/allocator-args.stderr +++ b/src/test/ui/allocator/allocator-args.stderr @@ -2,7 +2,7 @@ error: malformed `global_allocator` attribute input --> $DIR/allocator-args.rs:10:1 | LL | #[global_allocator(malloc)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: ``#[global_allocator]`` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[global_allocator]` error: aborting due to previous error diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr index 503ef020d9604..e82cb93c6359e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr @@ -1,7 +1,13 @@ +error: malformed `bench` attribute input + --> $DIR/issue-43106-gating-of-bench.rs:15:1 + | +LL | #![bench = "4100"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[bench]` + error[E0601]: `main` function not found in crate `issue_43106_gating_of_bench` | = note: consider adding a `main` function to `$DIR/issue-43106-gating-of-bench.rs` -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr index 2ab35be43c576..9866fa3730ef2 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr @@ -1,7 +1,13 @@ +error: malformed `test` attribute input + --> $DIR/issue-43106-gating-of-test.rs:10:1 + | +LL | #![test = "4200"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[test]` + error[E0601]: `main` function not found in crate `issue_43106_gating_of_test` | = note: consider adding a `main` function to `$DIR/issue-43106-gating-of-test.rs` -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0601`. From bf8fc8adfc76f31a8fb6a4cb0dee02f262bd766a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 19 Jul 2019 02:51:07 +0300 Subject: [PATCH 34/43] syntax_ext: Improve and simplify code generated by `#[global_allocator]` Instead of ``` mod allocator_abi { /* methods */ } ``` we now generate ``` const _: () = { /* methods */ } ``` and use `std_path` for paths referring to standard library entities. This way we no longer need to generate `use` and `extern crate` imports, and `#[global_allocator]` starts working inside unnamed blocks. --- src/libsyntax_ext/global_allocator.rs | 85 ++++++------------- .../run-pass/allocator/custom-in-block.rs | 5 +- .../run-pass/allocator/custom-in-submodule.rs | 5 +- 3 files changed, 34 insertions(+), 61 deletions(-) diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index 196db3d7baa5b..71c9e6cd23d44 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,13 +1,12 @@ -use syntax::ast::{ItemKind, Mutability, Ty, TyKind, Unsafety, VisibilityKind}; -use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item}; +use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety}; +use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident}; use syntax::attr::check_builtin_macro_attribute; use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; -use syntax::source_map::respan; -use syntax::symbol::{kw, sym}; +use syntax::symbol::{kw, sym, Symbol}; use syntax_pos::Span; pub fn expand( @@ -36,52 +35,31 @@ pub fn expand( span, kind: AllocatorKind::Global, global: item.ident, - core: Ident::with_empty_ctxt(sym::core), cx: ecx, }; - // We will generate a new submodule. To `use` the static from that module, we need to get - // the `super::...` path. - let super_path = f.cx.path(f.span, vec![Ident::with_empty_ctxt(kw::Super), f.global]); - - // Generate the items in the submodule - let mut items = vec![ - // import `core` to use allocators - f.cx.item_extern_crate(f.span, f.core), - // `use` the `global_allocator` in `super` - f.cx.item_use_simple( - f.span, - respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), - super_path, - ), - ]; - - // Add the allocator methods to the submodule - items.extend( - ALLOCATOR_METHODS - .iter() - .map(|method| f.allocator_fn(method)), - ); + // Generate item statements for the allocator methods. + let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect(); - // Generate the submodule itself - let name = f.kind.fn_name("allocator_abi"); - let allocator_abi = Ident::from_str(&name).gensym(); - let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); + // Generate anonymous constant serving as container for the allocator methods. + let const_ty = ecx.ty(span, TyKind::Tup(Vec::new())); + let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_item = + ecx.item_const(span, Ident::with_empty_ctxt(kw::Underscore), const_ty, const_body); - // Return the item and new submodule - vec![Annotatable::Item(item), Annotatable::Item(module)] + // Return the original item and the new methods. + vec![Annotatable::Item(item), Annotatable::Item(const_item)] } struct AllocFnFactory<'a, 'b> { span: Span, kind: AllocatorKind, global: Ident, - core: Ident, cx: &'b ExtCtxt<'a>, } impl AllocFnFactory<'_, '_> { - fn allocator_fn(&self, method: &AllocatorMethod) -> P { + fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { let mut abi_args = Vec::new(); let mut i = 0; let ref mut mk = || { @@ -105,25 +83,22 @@ impl AllocFnFactory<'_, '_> { Generics::default(), self.cx.block_expr(output_expr), ); - self.cx.item( + let item = self.cx.item( self.span, Ident::from_str(&self.kind.fn_name(method.name)), self.attrs(), kind, - ) + ); + self.cx.stmt_item(self.span, item) } fn call_allocator(&self, method: &str, mut args: Vec>) -> P { - let method = self.cx.path( - self.span, - vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("GlobalAlloc"), - Ident::from_str(method), - ], - ); - let method = self.cx.expr_path(method); + let method = self.cx.std_path(&[ + Symbol::intern("alloc"), + Symbol::intern("GlobalAlloc"), + Symbol::intern(method), + ]); + let method = self.cx.expr_path(self.cx.path(self.span, method)); let allocator = self.cx.path_ident(self.span, self.global); let allocator = self.cx.expr_path(allocator); let allocator = self.cx.expr_addr_of(self.span, allocator); @@ -153,16 +128,12 @@ impl AllocFnFactory<'_, '_> { args.push(self.cx.arg(self.span, size, ty_usize.clone())); args.push(self.cx.arg(self.span, align, ty_usize)); - let layout_new = self.cx.path( - self.span, - vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("Layout"), - Ident::from_str("from_size_align_unchecked"), - ], - ); - let layout_new = self.cx.expr_path(layout_new); + let layout_new = self.cx.std_path(&[ + Symbol::intern("alloc"), + Symbol::intern("Layout"), + Symbol::intern("from_size_align_unchecked"), + ]); + let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new)); let size = self.cx.expr_ident(self.span, size); let align = self.cx.expr_ident(self.span, align); let layout = self.cx.expr_call(self.span, layout_new, vec![size, align]); diff --git a/src/test/run-pass/allocator/custom-in-block.rs b/src/test/run-pass/allocator/custom-in-block.rs index 506154ec601ae..12813a1fc8bd4 100644 --- a/src/test/run-pass/allocator/custom-in-block.rs +++ b/src/test/run-pass/allocator/custom-in-block.rs @@ -13,9 +13,10 @@ fn main() { #[global_allocator] pub static GLOBAL: A = A(AtomicUsize::new(0)); + let n = GLOBAL.0.load(Ordering::SeqCst); let s = Box::new(0); helper::work_with(&s); - assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); drop(s); - assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); } diff --git a/src/test/run-pass/allocator/custom-in-submodule.rs b/src/test/run-pass/allocator/custom-in-submodule.rs index f9c4ad7668b63..ea341b1ac14ae 100644 --- a/src/test/run-pass/allocator/custom-in-submodule.rs +++ b/src/test/run-pass/allocator/custom-in-submodule.rs @@ -17,9 +17,10 @@ mod submodule { } fn main() { + let n = submodule::GLOBAL.0.load(Ordering::SeqCst); let s = Box::new(0); helper::work_with(&s); - assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), 1); + assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), n + 1); drop(s); - assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), 2); + assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), n + 2); } From 6e4f16173c331ca3ccae1ffecc5a69f1ad54f30c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 20 Jul 2019 03:14:11 +0300 Subject: [PATCH 35/43] Demote template check error to a lint for `#[test]` and `#[bench]` --- src/libsyntax/attr/builtin.rs | 3 ++- .../ui/feature-gate/issue-43106-gating-of-bench.stderr | 10 +++++++--- .../ui/feature-gate/issue-43106-gating-of-test.stderr | 10 +++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 713094416524b..dbf31ad014832 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -942,7 +942,8 @@ crate fn check_builtin_attribute( // Some of previously accepted forms were used in practice, // report them as warnings for now. let should_warn = |name| name == sym::doc || name == sym::ignore || - name == sym::inline || name == sym::link; + name == sym::inline || name == sym::link || + name == sym::test || name == sym::bench; match attr.parse_meta(sess) { Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr index e82cb93c6359e..37b5e792dc239 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-bench.stderr @@ -1,13 +1,17 @@ -error: malformed `bench` attribute input +warning: attribute must be of the form `#[bench]` --> $DIR/issue-43106-gating-of-bench.rs:15:1 | LL | #![bench = "4100"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[bench]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(ill_formed_attribute_input)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 error[E0601]: `main` function not found in crate `issue_43106_gating_of_bench` | = note: consider adding a `main` function to `$DIR/issue-43106-gating-of-bench.rs` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr index 9866fa3730ef2..dbffabf3e02f9 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-test.stderr @@ -1,13 +1,17 @@ -error: malformed `test` attribute input +warning: attribute must be of the form `#[test]` --> $DIR/issue-43106-gating-of-test.rs:10:1 | LL | #![test = "4200"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[test]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(ill_formed_attribute_input)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 error[E0601]: `main` function not found in crate `issue_43106_gating_of_test` | = note: consider adding a `main` function to `$DIR/issue-43106-gating-of-test.rs` -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0601`. From a0c2c640d54fa1622c2fea4accae1025bf109c47 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 20 Jul 2019 13:44:11 +0300 Subject: [PATCH 36/43] Fix rebase --- src/libsyntax_ext/global_allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index 71c9e6cd23d44..33072487e19f4 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -30,7 +30,7 @@ pub fn expand( }; // Generate a bunch of new items using the AllocFnFactory - let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.mark)); + let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id)); let f = AllocFnFactory { span, kind: AllocatorKind::Global, From f49a96501d4f11cb08c382bd8180a5a5db59213d Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 24 Jul 2019 14:09:26 +0200 Subject: [PATCH 37/43] Add test for #51559 Closes #51559 --- src/test/ui/consts/issue-51559.rs | 7 +++++++ src/test/ui/consts/issue-51559.stderr | 11 +++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/ui/consts/issue-51559.rs create mode 100644 src/test/ui/consts/issue-51559.stderr diff --git a/src/test/ui/consts/issue-51559.rs b/src/test/ui/consts/issue-51559.rs new file mode 100644 index 0000000000000..429947269385b --- /dev/null +++ b/src/test/ui/consts/issue-51559.rs @@ -0,0 +1,7 @@ +#![feature(const_raw_ptr_to_usize_cast)] + +const BAR: *mut () = ((|| 3) as fn() -> i32) as *mut (); +pub const FOO: usize = unsafe { BAR as usize }; +//~^ ERROR it is undefined behavior to use this value + +fn main() {} diff --git a/src/test/ui/consts/issue-51559.stderr b/src/test/ui/consts/issue-51559.stderr new file mode 100644 index 0000000000000..917c54ddaef1e --- /dev/null +++ b/src/test/ui/consts/issue-51559.stderr @@ -0,0 +1,11 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-51559.rs:4:1 + | +LL | pub const FOO: usize = unsafe { BAR as usize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From c0918183a7888ed028e41ca2e2e917a0d377aee8 Mon Sep 17 00:00:00 2001 From: Kevin W Matthews Date: Wed, 24 Jul 2019 08:21:08 -0700 Subject: [PATCH 38/43] Use match ergonomics in Condvar documentation --- src/libstd/sync/condvar.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index ffb9ce1c81a53..aeff57716e86b 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -36,7 +36,7 @@ impl WaitTimeoutResult { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// /// // Let's wait 20 milliseconds before notifying the condvar. /// thread::sleep(Duration::from_millis(20)); @@ -48,7 +48,7 @@ impl WaitTimeoutResult { /// }); /// /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// let mut started = lock.lock().unwrap(); /// loop { /// // Let's put a timeout on the condvar's wait. @@ -94,7 +94,7 @@ impl WaitTimeoutResult { /// /// // Inside of our lock, spawn a new thread, and then wait for it to start. /// thread::spawn(move|| { -/// let &(ref lock, ref cvar) = &*pair2; +/// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -102,7 +102,7 @@ impl WaitTimeoutResult { /// }); /// /// // Wait for the thread to start up. -/// let &(ref lock, ref cvar) = &*pair; +/// let (lock, cvar) = &*pair; /// let mut started = lock.lock().unwrap(); /// while !*started { /// started = cvar.wait(started).unwrap(); @@ -180,7 +180,7 @@ impl Condvar { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -188,7 +188,7 @@ impl Condvar { /// }); /// /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// let mut started = lock.lock().unwrap(); /// // As long as the value inside the `Mutex` is `false`, we wait. /// while !*started { @@ -245,7 +245,7 @@ impl Condvar { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -253,7 +253,7 @@ impl Condvar { /// }); /// /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// // As long as the value inside the `Mutex` is `false`, we wait. /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap(); /// ``` @@ -301,7 +301,7 @@ impl Condvar { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -309,7 +309,7 @@ impl Condvar { /// }); /// /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// let mut started = lock.lock().unwrap(); /// // As long as the value inside the `Mutex` is `false`, we wait. /// loop { @@ -374,7 +374,7 @@ impl Condvar { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -382,7 +382,7 @@ impl Condvar { /// }); /// /// // wait for the thread to start up - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// let mut started = lock.lock().unwrap(); /// // as long as the value inside the `Mutex` is `false`, we wait /// loop { @@ -449,7 +449,7 @@ impl Condvar { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -457,7 +457,7 @@ impl Condvar { /// }); /// /// // wait for the thread to start up - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// let result = cvar.wait_timeout_until( /// lock.lock().unwrap(), /// Duration::from_millis(100), @@ -508,7 +508,7 @@ impl Condvar { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -516,7 +516,7 @@ impl Condvar { /// }); /// /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// let mut started = lock.lock().unwrap(); /// // As long as the value inside the `Mutex` is `false`, we wait. /// while !*started { @@ -548,7 +548,7 @@ impl Condvar { /// let pair2 = pair.clone(); /// /// thread::spawn(move|| { - /// let &(ref lock, ref cvar) = &*pair2; + /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; /// // We notify the condvar that the value has changed. @@ -556,7 +556,7 @@ impl Condvar { /// }); /// /// // Wait for the thread to start up. - /// let &(ref lock, ref cvar) = &*pair; + /// let (lock, cvar) = &*pair; /// let mut started = lock.lock().unwrap(); /// // As long as the value inside the `Mutex` is `false`, we wait. /// while !*started { From 404281125e565a4889910657504112789c75a11e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 25 Jul 2019 07:47:57 +0900 Subject: [PATCH 39/43] Use Foo instead of raw arrays --- src/test/run-pass/generator/size-moved-locals.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/run-pass/generator/size-moved-locals.rs b/src/test/run-pass/generator/size-moved-locals.rs index 5b056059b5d1d..c9f471d7b6c98 100644 --- a/src/test/run-pass/generator/size-moved-locals.rs +++ b/src/test/run-pass/generator/size-moved-locals.rs @@ -57,10 +57,10 @@ fn overlap_move_points() -> impl Generator { fn overlap_x_and_y() -> impl Generator{ static || { - let x = [0u8; 1024]; + let x = Foo([0; FOO_SIZE]); yield; drop(x); - let y = [0u8;1024]; + let y = Foo([0; FOO_SIZE]); yield; drop(y); } @@ -70,5 +70,5 @@ fn main() { assert_eq!(1028, std::mem::size_of_val(&move_before_yield())); assert_eq!(1032, std::mem::size_of_val(&move_before_yield_with_noop())); assert_eq!(2056, std::mem::size_of_val(&overlap_move_points())); - assert_eq!(2052, std::mem::size_of_val(&overlap_x_and_y())); + assert_eq!(1032, std::mem::size_of_val(&overlap_x_and_y())); } From 91fa898975609f09f33e3e03fa8706c31a6b7d9b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 17 Apr 2019 19:38:17 -0700 Subject: [PATCH 40/43] Stabilize the type_name intrinsic in core::any Closes rust-lang/rfcs#1428 --- src/libcore/any.rs | 26 +++++++++++++++++++ src/librustc/traits/query/normalize.rs | 2 +- .../traits/query/normalize_erasing_regions.rs | 2 +- src/librustc/ty/query/config.rs | 2 +- src/librustc/ty/query/mod.rs | 2 +- src/librustc/ty/query/on_disk_cache.rs | 2 +- src/librustc/ty/query/plumbing.rs | 4 +-- src/librustc_mir/transform/mod.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 2 +- src/libserialize/serialize.rs | 6 ++--- .../run-pass/consts/const-fn-type-name.rs | 2 +- src/test/run-pass/issues/issue-21058.rs | 5 ++-- src/test/run-pass/issues/issue-61894.rs | 4 +-- src/test/run-pass/tydesc-name.rs | 10 +++---- 14 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/libcore/any.rs b/src/libcore/any.rs index d043ce34effcd..f7aef66942d9b 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -450,3 +450,29 @@ impl TypeId { } } } + +/// Returns the name of a type as a string slice. +/// +/// # Note +/// +/// This is intended for diagnostic use. The exact contents and format of the +/// string are not specified, other than being a best-effort description of the +/// type. For example, `type_name::>()` could return the +/// `"Option"` or `"std::option::Option"`, but not +/// `"foobar"`. In addition, the output may change between versions of the +/// compiler. +/// +/// The type name should not be considered a unique identifier of a type; +/// multiple types may share the same type name. +/// +/// The current implementation uses the same infrastructure as compiler +/// diagnostics and debuginfo, but this is not guaranteed. +#[stable(feature = "type_name", since = "1.38.0")] +pub fn type_name() -> &'static str { + #[cfg(bootstrap)] + unsafe { + intrinsics::type_name::() + } + #[cfg(not(bootstrap))] + intrinsics::type_name::() +} diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 55e622e46b966..2ffcd0fd4d941 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -34,7 +34,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { { debug!( "normalize::<{}>(value={:?}, param_env={:?})", - unsafe { ::std::intrinsics::type_name::() }, + ::std::any::type_name::(), value, self.param_env, ); diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs index 3218ff062ce5e..d09288461d444 100644 --- a/src/librustc/traits/query/normalize_erasing_regions.rs +++ b/src/librustc/traits/query/normalize_erasing_regions.rs @@ -22,7 +22,7 @@ impl<'tcx> TyCtxt<'tcx> { { debug!( "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", - unsafe { ::std::intrinsics::type_name::() }, + ::std::any::type_name::(), value, param_env, ); diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index b921272856e28..1cc083ea93c6c 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -69,7 +69,7 @@ impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M { if !tcx.sess.verbose() { format!("processing `{}`", tcx.def_path_str(def_id)).into() } else { - let name = unsafe { ::std::intrinsics::type_name::() }; + let name = ::std::any::type_name::(); format!("processing {:?} with query `{}`", def_id, name).into() } } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index e788628bc58e2..f4b99ca368874 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -54,7 +54,7 @@ use rustc_target::spec::PanicStrategy; use std::borrow::Cow; use std::ops::Deref; use std::sync::Arc; -use std::intrinsics::type_name; +use std::any::type_name; use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::symbol::InternedString; use syntax::attr; diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index a25c1e34cf154..24bce7e338bd9 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -1060,7 +1060,7 @@ where Q::Value: Encodable, { let desc = &format!("encode_query_results for {}", - unsafe { ::std::intrinsics::type_name::() }); + ::std::any::type_name::()); time_ext(tcx.sess.time_extended(), Some(tcx.sess), desc, || { let map = Q::query_cache(tcx).borrow(); diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 0c9e31e1ff28e..ce9f67db59232 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -782,9 +782,9 @@ macro_rules! define_queries_inner { #[cfg(not(debug_assertions))] cache_hits: 0, key_size: mem::size_of::(), - key_type: unsafe { type_name::() }, + key_type: type_name::(), value_size: mem::size_of::(), - value_type: unsafe { type_name::() }, + value_type: type_name::(), entry_count: map.results.len(), } } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 9e23d06145330..195a652b0a2e6 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -127,7 +127,7 @@ impl<'tcx> MirSource<'tcx> { /// Generates a default name for the pass based on the name of the /// type `T`. pub fn default_name() -> Cow<'static, str> { - let name = unsafe { ::std::intrinsics::type_name::() }; + let name = ::std::any::type_name::(); if let Some(tail) = name.rfind(":") { Cow::from(&name[tail+1..]) } else { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 531ecd11dcb20..4d8f564123634 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -71,7 +71,7 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { "saturating_add" | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" | - "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" + "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 2def2a455fb64..a5f7b4898ae0e 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -4,8 +4,8 @@ Core encoding and decoding interfaces. */ +use std::any; use std::borrow::Cow; -use std::intrinsics; use std::marker::PhantomData; use std::path; use std::rc::Rc; @@ -849,9 +849,9 @@ pub trait SpecializationError { impl SpecializationError for E { default fn not_found(trait_name: &'static str, method_name: &'static str) -> E { panic!("missing specialization: `<{} as {}<{}>>::{}` not overridden", - unsafe { intrinsics::type_name::() }, + any::type_name::(), trait_name, - unsafe { intrinsics::type_name::() }, + any::type_name::(), method_name); } } diff --git a/src/test/run-pass/consts/const-fn-type-name.rs b/src/test/run-pass/consts/const-fn-type-name.rs index 2ee6415aa68b7..2bb1aeecf376d 100644 --- a/src/test/run-pass/consts/const-fn-type-name.rs +++ b/src/test/run-pass/consts/const-fn-type-name.rs @@ -5,7 +5,7 @@ #![allow(dead_code)] const fn type_name_wrapper(_: &T) -> &'static str { - unsafe { core::intrinsics::type_name::() } + core::intrinsics::type_name::() } struct Struct { diff --git a/src/test/run-pass/issues/issue-21058.rs b/src/test/run-pass/issues/issue-21058.rs index 3efa94ce6835c..6facf0b2dd578 100644 --- a/src/test/run-pass/issues/issue-21058.rs +++ b/src/test/run-pass/issues/issue-21058.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(core_intrinsics)] use std::fmt::Debug; @@ -12,7 +11,7 @@ macro_rules! check { assert_eq!(type_name_of_val($ty_of), $expected); }; ($ty:ty, $expected:expr) => { - assert_eq!(unsafe { std::intrinsics::type_name::<$ty>()}, $expected); + assert_eq!(std::any::type_name::<$ty>(), $expected); }; } @@ -50,7 +49,7 @@ fn bar() { } fn type_name_of_val(_: T) -> &'static str { - unsafe { std::intrinsics::type_name::() } + std::any::type_name::() } #[derive(Debug)] diff --git a/src/test/run-pass/issues/issue-61894.rs b/src/test/run-pass/issues/issue-61894.rs index 9ab969be46a45..4d407125299a7 100644 --- a/src/test/run-pass/issues/issue-61894.rs +++ b/src/test/run-pass/issues/issue-61894.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] -use std::intrinsics::type_name; +use std::any::type_name; struct Bar(M); @@ -8,7 +8,7 @@ impl Bar { fn foo(&self) -> &'static str { fn f() {} fn type_name_of(_: T) -> &'static str { - unsafe { type_name::() } + type_name::() } type_name_of(f) } diff --git a/src/test/run-pass/tydesc-name.rs b/src/test/run-pass/tydesc-name.rs index 91578b71d04ae..d9d947bd4c062 100644 --- a/src/test/run-pass/tydesc-name.rs +++ b/src/test/run-pass/tydesc-name.rs @@ -1,16 +1,12 @@ #![allow(dead_code)] -#![feature(core_intrinsics)] - -use std::intrinsics::type_name; +use std::any::type_name; struct Foo { x: T } pub fn main() { - unsafe { - assert_eq!(type_name::(), "isize"); - assert_eq!(type_name::>(), "tydesc_name::Foo"); - } + assert_eq!(type_name::(), "isize"); + assert_eq!(type_name::>(), "tydesc_name::Foo"); } From 50d9b06f97807b97d560dd532b48eb7bfd2717fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Thu, 25 Jul 2019 17:56:58 +0200 Subject: [PATCH 41/43] Fix inconsistent highlight blocks. --- src/libcore/char/methods.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 99f88591eea3e..aa834db2b9b3e 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -547,10 +547,10 @@ impl char { } } - /// Returns `true` if this `char` satisfies the 'XID_Start' Unicode property, and false + /// Returns `true` if this `char` satisfies the `XID_Start` Unicode property, and false /// otherwise. /// - /// 'XID_Start' is a Unicode Derived Property specified in + /// `XID_Start` is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), /// mostly similar to `ID_Start` but modified for closure under `NFKx`. #[cfg_attr(bootstrap, @@ -563,12 +563,12 @@ impl char { derived_property::XID_Start(self) } - /// Returns `true` if this `char` satisfies the 'XID_Continue' Unicode property, and false + /// Returns `true` if this `char` satisfies the `XID_Continue` Unicode property, and false /// otherwise. /// - /// 'XID_Continue' is a Unicode Derived Property specified in + /// `XID_Continue` is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), - /// mostly similar to 'ID_Continue' but modified for closure under NFKx. + /// mostly similar to `ID_Continue` but modified for closure under NFKx. #[cfg_attr(bootstrap, unstable(feature = "rustc_private", reason = "mainly needed for compiler internals", @@ -666,7 +666,7 @@ impl char { /// Returns `true` if this `char` is alphanumeric. /// /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. + /// `Nd`, `Nl`, `No` and the Derived Core Property `Alphabetic`. /// /// # Examples /// @@ -720,7 +720,7 @@ impl char { /// Returns `true` if this `char` is numeric. /// /// 'Numeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No'. + /// `Nd`, `Nl`, `No`. /// /// # Examples /// From 9d39758d14df45956b1a8d8132e3e40c3558dd4b Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Thu, 25 Jul 2019 18:06:26 +0200 Subject: [PATCH 42/43] Remove `cfg(bootstrap)` code for array implementations In PR #62435 ("Use const generics for array impls [part 1]") the old macro-based implementations were not removed but still used with `cfg(bootstrap)` since the bootstrap compiler had some problems with const generics at the time. This does not seem to be the case anymore, so there is no reason to keep the old code. --- src/libcore/array.rs | 673 +++++++++++++++---------------------------- src/libcore/lib.rs | 2 +- 2 files changed, 241 insertions(+), 434 deletions(-) diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 144543be7c465..6ecc0487fae1b 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -81,487 +81,296 @@ impl From for TryFromSliceError { } } -#[cfg(bootstrap)] -macro_rules! __impl_slice_eq1 { - ($Lhs: ty, $Rhs: ty) => { - __impl_slice_eq1! { $Lhs, $Rhs, Sized } - }; - ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { - #[inline] - fn eq(&self, other: &$Rhs) -> bool { self[..] == other[..] } - #[inline] - fn ne(&self, other: &$Rhs) -> bool { self[..] != other[..] } - } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef<[T]> for [T; N] +where + [T; N]: LengthAtMost32, +{ + #[inline] + fn as_ref(&self) -> &[T] { + &self[..] } } -#[cfg(bootstrap)] -macro_rules! __impl_slice_eq2 { - ($Lhs: ty, $Rhs: ty) => { - __impl_slice_eq2! { $Lhs, $Rhs, Sized } - }; - ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - __impl_slice_eq1!($Lhs, $Rhs, $Bound); - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq { - #[inline] - fn eq(&self, other: &$Lhs) -> bool { self[..] == other[..] } - #[inline] - fn ne(&self, other: &$Lhs) -> bool { self[..] != other[..] } - } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsMut<[T]> for [T; N] +where + [T; N]: LengthAtMost32, +{ + #[inline] + fn as_mut(&mut self) -> &mut [T] { + &mut self[..] } } -// macro for implementing n-element array functions and operations -#[cfg(bootstrap)] -macro_rules! array_impls { - ($($N:expr)+) => { - $( - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRef<[T]> for [T; $N] { - #[inline] - fn as_ref(&self) -> &[T] { - &self[..] - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsMut<[T]> for [T; $N] { - #[inline] - fn as_mut(&mut self) -> &mut [T] { - &mut self[..] - } - } - - #[stable(feature = "array_borrow", since = "1.4.0")] - impl Borrow<[T]> for [T; $N] { - fn borrow(&self) -> &[T] { - self - } - } - - #[stable(feature = "array_borrow", since = "1.4.0")] - impl BorrowMut<[T]> for [T; $N] { - fn borrow_mut(&mut self) -> &mut [T] { - self - } - } - - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<&[T]> for [T; $N] where T: Copy { - type Error = TryFromSliceError; - - fn try_from(slice: &[T]) -> Result<[T; $N], TryFromSliceError> { - <&Self>::try_from(slice).map(|r| *r) - } - } - - #[stable(feature = "try_from", since = "1.34.0")] - impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { - type Error = TryFromSliceError; - - fn try_from(slice: &[T]) -> Result<&[T; $N], TryFromSliceError> { - if slice.len() == $N { - let ptr = slice.as_ptr() as *const [T; $N]; - unsafe { Ok(&*ptr) } - } else { - Err(TryFromSliceError(())) - } - } - } - - #[stable(feature = "try_from", since = "1.34.0")] - impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { - type Error = TryFromSliceError; - - fn try_from(slice: &mut [T]) -> Result<&mut [T; $N], TryFromSliceError> { - if slice.len() == $N { - let ptr = slice.as_mut_ptr() as *mut [T; $N]; - unsafe { Ok(&mut *ptr) } - } else { - Err(TryFromSliceError(())) - } - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for [T; $N] { - fn hash(&self, state: &mut H) { - Hash::hash(&self[..], state) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl fmt::Debug for [T; $N] { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&&self[..], f) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> IntoIterator for &'a [T; $N] { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> IntoIterator for &'a mut [T; $N] { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } - } - - // NOTE: some less important impls are omitted to reduce code bloat - __impl_slice_eq1! { [A; $N], [B; $N] } - __impl_slice_eq2! { [A; $N], [B] } - __impl_slice_eq2! { [A; $N], &'b [B] } - __impl_slice_eq2! { [A; $N], &'b mut [B] } - // __impl_slice_eq2! { [A; $N], &'b [B; $N] } - // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } - - #[stable(feature = "rust1", since = "1.0.0")] - impl Eq for [T; $N] { } - - #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for [T; $N] { - #[inline] - fn partial_cmp(&self, other: &[T; $N]) -> Option { - PartialOrd::partial_cmp(&&self[..], &&other[..]) - } - #[inline] - fn lt(&self, other: &[T; $N]) -> bool { - PartialOrd::lt(&&self[..], &&other[..]) - } - #[inline] - fn le(&self, other: &[T; $N]) -> bool { - PartialOrd::le(&&self[..], &&other[..]) - } - #[inline] - fn ge(&self, other: &[T; $N]) -> bool { - PartialOrd::ge(&&self[..], &&other[..]) - } - #[inline] - fn gt(&self, other: &[T; $N]) -> bool { - PartialOrd::gt(&&self[..], &&other[..]) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for [T; $N] { - #[inline] - fn cmp(&self, other: &[T; $N]) -> Ordering { - Ord::cmp(&&self[..], &&other[..]) - } - } - )+ +#[stable(feature = "array_borrow", since = "1.4.0")] +impl Borrow<[T]> for [T; N] +where + [T; N]: LengthAtMost32, +{ + fn borrow(&self) -> &[T] { + self } } -#[cfg(not(bootstrap))] -mod impls_using_const_generics { - use super::*; - - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRef<[T]> for [T; N] - where - [T; N]: LengthAtMost32, - { - #[inline] - fn as_ref(&self) -> &[T] { - &self[..] - } +#[stable(feature = "array_borrow", since = "1.4.0")] +impl BorrowMut<[T]> for [T; N] +where + [T; N]: LengthAtMost32, +{ + fn borrow_mut(&mut self) -> &mut [T] { + self } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl AsMut<[T]> for [T; N] - where - [T; N]: LengthAtMost32, - { - #[inline] - fn as_mut(&mut self) -> &mut [T] { - &mut self[..] - } +#[stable(feature = "try_from", since = "1.34.0")] +impl TryFrom<&[T]> for [T; N] +where + T: Copy, + [T; N]: LengthAtMost32, +{ + type Error = TryFromSliceError; + + fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> { + <&Self>::try_from(slice).map(|r| *r) } +} - #[stable(feature = "array_borrow", since = "1.4.0")] - impl Borrow<[T]> for [T; N] - where - [T; N]: LengthAtMost32, - { - fn borrow(&self) -> &[T] { - self +#[stable(feature = "try_from", since = "1.34.0")] +impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] +where + [T; N]: LengthAtMost32, +{ + type Error = TryFromSliceError; + + fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> { + if slice.len() == N { + let ptr = slice.as_ptr() as *const [T; N]; + unsafe { Ok(&*ptr) } + } else { + Err(TryFromSliceError(())) } } +} - #[stable(feature = "array_borrow", since = "1.4.0")] - impl BorrowMut<[T]> for [T; N] - where - [T; N]: LengthAtMost32, - { - fn borrow_mut(&mut self) -> &mut [T] { - self +#[stable(feature = "try_from", since = "1.34.0")] +impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] +where + [T; N]: LengthAtMost32, +{ + type Error = TryFromSliceError; + + fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> { + if slice.len() == N { + let ptr = slice.as_mut_ptr() as *mut [T; N]; + unsafe { Ok(&mut *ptr) } + } else { + Err(TryFromSliceError(())) } } +} - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<&[T]> for [T; N] - where - T: Copy, - [T; N]: LengthAtMost32, - { - type Error = TryFromSliceError; +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for [T; N] +where + [T; N]: LengthAtMost32, +{ + fn hash(&self, state: &mut H) { + Hash::hash(&self[..], state) + } +} - fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> { - <&Self>::try_from(slice).map(|r| *r) - } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for [T; N] +where + [T; N]: LengthAtMost32, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&&self[..], f) } +} - #[stable(feature = "try_from", since = "1.34.0")] - impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] - where - [T; N]: LengthAtMost32, - { - type Error = TryFromSliceError; +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, const N: usize> IntoIterator for &'a [T; N] +where + [T; N]: LengthAtMost32, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; - fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> { - if slice.len() == N { - let ptr = slice.as_ptr() as *const [T; N]; - unsafe { Ok(&*ptr) } - } else { - Err(TryFromSliceError(())) - } - } + fn into_iter(self) -> Iter<'a, T> { + self.iter() } +} - #[stable(feature = "try_from", since = "1.34.0")] - impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] - where - [T; N]: LengthAtMost32, - { - type Error = TryFromSliceError; +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] +where + [T; N]: LengthAtMost32, +{ + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; - fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> { - if slice.len() == N { - let ptr = slice.as_mut_ptr() as *mut [T; N]; - unsafe { Ok(&mut *ptr) } - } else { - Err(TryFromSliceError(())) - } - } + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for [T; N] - where - [T; N]: LengthAtMost32, - { - fn hash(&self, state: &mut H) { - Hash::hash(&self[..], state) - } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, A, B, const N: usize> PartialEq<[B; N]> for [A; N] +where + A: PartialEq, + [A; N]: LengthAtMost32, + [B; N]: LengthAtMost32, +{ + #[inline] + fn eq(&self, other: &[B; N]) -> bool { + self[..] == other[..] } - - #[stable(feature = "rust1", since = "1.0.0")] - impl fmt::Debug for [T; N] - where - [T; N]: LengthAtMost32, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&&self[..], f) - } + #[inline] + fn ne(&self, other: &[B; N]) -> bool { + self[..] != other[..] } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T, const N: usize> IntoIterator for &'a [T; N] - where - [T; N]: LengthAtMost32, - { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, A, B, const N: usize> PartialEq<[B]> for [A; N] +where + A: PartialEq, + [A; N]: LengthAtMost32, +{ + #[inline] + fn eq(&self, other: &[B]) -> bool { + self[..] == other[..] } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] - where - [T; N]: LengthAtMost32, - { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } + #[inline] + fn ne(&self, other: &[B]) -> bool { + self[..] != other[..] } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A, B, const N: usize> PartialEq<[B; N]> for [A; N] - where - A: PartialEq, - [A; N]: LengthAtMost32, - [B; N]: LengthAtMost32, - { - #[inline] - fn eq(&self, other: &[B; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[B; N]) -> bool { - self[..] != other[..] - } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for [B] +where + B: PartialEq, + [A; N]: LengthAtMost32, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A, B, const N: usize> PartialEq<[B]> for [A; N] - where - A: PartialEq, - [A; N]: LengthAtMost32, - { - #[inline] - fn eq(&self, other: &[B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[B]) -> bool { - self[..] != other[..] - } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for [B] - where - B: PartialEq, - [A; N]: LengthAtMost32, - { - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N] +where + A: PartialEq, + [A; N]: LengthAtMost32, +{ + #[inline] + fn eq(&self, other: &&'b [B]) -> bool { + self[..] == other[..] } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N] - where - A: PartialEq, - [A; N]: LengthAtMost32, - { - #[inline] - fn eq(&self, other: &&'b [B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &&'b [B]) -> bool { - self[..] != other[..] - } + #[inline] + fn ne(&self, other: &&'b [B]) -> bool { + self[..] != other[..] } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B] - where - B: PartialEq, - [A; N]: LengthAtMost32, - { - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B] +where + B: PartialEq, + [A; N]: LengthAtMost32, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N] - where - A: PartialEq, - [A; N]: LengthAtMost32, - { - #[inline] - fn eq(&self, other: &&'b mut [B]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &&'b mut [B]) -> bool { - self[..] != other[..] - } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N] +where + A: PartialEq, + [A; N]: LengthAtMost32, +{ + #[inline] + fn eq(&self, other: &&'b mut [B]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &&'b mut [B]) -> bool { + self[..] != other[..] } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B] - where - B: PartialEq, - [A; N]: LengthAtMost32, - { - #[inline] - fn eq(&self, other: &[A; N]) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &[A; N]) -> bool { - self[..] != other[..] - } +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B] +where + B: PartialEq, + [A; N]: LengthAtMost32, +{ + #[inline] + fn eq(&self, other: &[A; N]) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &[A; N]) -> bool { + self[..] != other[..] } +} - // NOTE: some less important impls are omitted to reduce code bloat - // __impl_slice_eq2! { [A; $N], &'b [B; $N] } - // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } +// NOTE: some less important impls are omitted to reduce code bloat +// __impl_slice_eq2! { [A; $N], &'b [B; $N] } +// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } - #[stable(feature = "rust1", since = "1.0.0")] - impl Eq for [T; N] where [T; N]: LengthAtMost32 {} +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for [T; N] where [T; N]: LengthAtMost32 {} - #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for [T; N] - where - [T; N]: LengthAtMost32, - { - #[inline] - fn partial_cmp(&self, other: &[T; N]) -> Option { - PartialOrd::partial_cmp(&&self[..], &&other[..]) - } - #[inline] - fn lt(&self, other: &[T; N]) -> bool { - PartialOrd::lt(&&self[..], &&other[..]) - } - #[inline] - fn le(&self, other: &[T; N]) -> bool { - PartialOrd::le(&&self[..], &&other[..]) - } - #[inline] - fn ge(&self, other: &[T; N]) -> bool { - PartialOrd::ge(&&self[..], &&other[..]) - } - #[inline] - fn gt(&self, other: &[T; N]) -> bool { - PartialOrd::gt(&&self[..], &&other[..]) - } +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for [T; N] +where + [T; N]: LengthAtMost32, +{ + #[inline] + fn partial_cmp(&self, other: &[T; N]) -> Option { + PartialOrd::partial_cmp(&&self[..], &&other[..]) + } + #[inline] + fn lt(&self, other: &[T; N]) -> bool { + PartialOrd::lt(&&self[..], &&other[..]) + } + #[inline] + fn le(&self, other: &[T; N]) -> bool { + PartialOrd::le(&&self[..], &&other[..]) } + #[inline] + fn ge(&self, other: &[T; N]) -> bool { + PartialOrd::ge(&&self[..], &&other[..]) + } + #[inline] + fn gt(&self, other: &[T; N]) -> bool { + PartialOrd::gt(&&self[..], &&other[..]) + } +} - #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for [T; N] - where - [T; N]: LengthAtMost32, - { - #[inline] - fn cmp(&self, other: &[T; N]) -> Ordering { - Ord::cmp(&&self[..], &&other[..]) - } +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for [T; N] +where + [T; N]: LengthAtMost32, +{ + #[inline] + fn cmp(&self, other: &[T; N]) -> Ordering { + Ord::cmp(&&self[..], &&other[..]) } } @@ -571,10 +380,8 @@ mod impls_using_const_generics { )] #[unstable(feature = "const_generic_impls_guard", issue = "0", reason = "will never be stable, just a temporary step until const generics are stable")] -#[cfg(not(bootstrap))] pub trait LengthAtMost32 {} -#[cfg(not(bootstrap))] macro_rules! array_impls { ($($N:literal)+) => { $( diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index fe149d634e223..9243dda84a6ef 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -74,7 +74,7 @@ #![feature(concat_idents)] #![feature(const_fn)] #![feature(const_fn_union)] -#![cfg_attr(not(bootstrap), feature(const_generics))] +#![feature(const_generics)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] From 3ab60264b504c1f51b2a9e3dfa20ef0d03bcdaed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 25 Jul 2019 10:11:03 -0700 Subject: [PATCH 43/43] Add note suggesting to borrow a String argument to find --- src/libcore/ops/function.rs | 4 ++++ src/test/ui/suggestions/issue-62843.rs | 5 +++++ src/test/ui/suggestions/issue-62843.stderr | 13 +++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 src/test/ui/suggestions/issue-62843.rs create mode 100644 src/test/ui/suggestions/issue-62843.stderr diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index c69f5fd989696..b9552eaa1a0e5 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -137,6 +137,10 @@ pub trait Fn : FnMut { #[rustc_paren_sugar] #[rustc_on_unimplemented( on(Args="()", note="wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"), + on( + all(Args="(char,)", _Self="std::string::String"), + note="borrowing the `{Self}` might fix the problem" + ), message="expected a `{FnMut}<{Args}>` closure, found `{Self}`", label="expected an `FnMut<{Args}>` closure, found `{Self}`", )] diff --git a/src/test/ui/suggestions/issue-62843.rs b/src/test/ui/suggestions/issue-62843.rs new file mode 100644 index 0000000000000..d96b12fd15ac9 --- /dev/null +++ b/src/test/ui/suggestions/issue-62843.rs @@ -0,0 +1,5 @@ +fn main() { + let line = String::from("abc"); + let pattern = String::from("bc"); + println!("{:?}", line.find(pattern)); //~ ERROR E0277 +} diff --git a/src/test/ui/suggestions/issue-62843.stderr b/src/test/ui/suggestions/issue-62843.stderr new file mode 100644 index 0000000000000..cc27b5b49b67d --- /dev/null +++ b/src/test/ui/suggestions/issue-62843.stderr @@ -0,0 +1,13 @@ +error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `std::string::String` + --> $DIR/issue-62843.rs:4:27 + | +LL | println!("{:?}", line.find(pattern)); + | ^^^^ expected an `FnMut<(char,)>` closure, found `std::string::String` + | + = help: the trait `std::ops::FnMut<(char,)>` is not implemented for `std::string::String` + = note: borrowing the `std::string::String` might fix the problem + = note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.