Auto merge of #62990 - Centril:rollup-k9n0hvs, r=Centril

Rollup of 15 pull requests

Successful merges:

 - #60066 (Stabilize the type_name intrinsic in core::any)
 - #60938 (rustdoc: make #[doc(include)] relative to the containing file)
 - #61884 (Stablize Euclidean Modulo (feature euclidean_division))
 - #61890 (Fix some sanity checks)
 - #62528 (Add joining slices of slices with a slice separator, not just a single item)
 - #62707 (Add tests for overlapping explicitly dropped locals in generators)
 - #62735 (Turn `#[global_allocator]` into a regular attribute macro)
 - #62822 (Improve some pointer-related documentation)
 - #62887 (Make the parser TokenStream more resilient after mismatched delimiter recovery)
 - #62921 (Add method disambiguation help for trait implementation)
 - #62930 (Add test for #51559)
 - #62942 (Use match ergonomics in Condvar documentation)
 - #62977 (Fix inconsistent highlight blocks.)
 - #62978 (Remove `cfg(bootstrap)` code for array implementations)
 - #62981 (Add note suggesting to borrow a String argument to find)

Failed merges:

 - #62964 (clarify and unify some type test names)

r? @ghost
This commit is contained in:
bors 2019-07-25 22:34:23 +00:00
commit 18630677cf
98 changed files with 1338 additions and 1247 deletions

View File

@ -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",

View File

@ -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))

View File

@ -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

View File

@ -494,10 +494,10 @@ impl<T> [T] {
/// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn concat<Separator: ?Sized>(&self) -> T::Output
where T: SliceConcat<Separator>
pub fn concat<Item: ?Sized>(&self) -> <Self as Concat<Item>>::Output
where Self: Concat<Item>
{
SliceConcat::concat(self)
Concat::concat(self)
}
/// Flattens a slice of `T` into a single value `Self::Output`, placing a
@ -508,12 +508,13 @@ impl<T> [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<Separator: ?Sized>(&self, sep: &Separator) -> T::Output
where T: SliceConcat<Separator>
pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
where Self: Join<Separator>
{
SliceConcat::join(self, sep)
Join::join(self, sep)
}
/// Flattens a slice of `T` into a single value `Self::Output`, placing a
@ -528,10 +529,10 @@ impl<T> [T] {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
pub fn connect<Separator: ?Sized>(&self, sep: &Separator) -> T::Output
where T: SliceConcat<Separator>
pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
where Self: Join<Separator>
{
SliceConcat::join(self, sep)
Join::join(self, sep)
}
}
@ -578,30 +579,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<T: Clone, V: Borrow<[T]>> 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<u32>, Vec<String>);
///
/// 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<Separator: ?Sized>: Sized {
pub trait Concat<Item: ?Sized> {
#[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<Separator> {
#[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",
reason = "trait should not have to exist",
issue = "27747")]
impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
#[unstable(feature = "slice_concat_ext", issue = "27747")]
impl<T: Clone, V: Borrow<[T]>> Concat<T> for [V] {
type Output = Vec<T>;
fn concat(slice: &[Self]) -> Vec<T> {
fn concat(slice: &Self) -> Vec<T> {
let size = slice.iter().map(|slice| slice.borrow().len()).sum();
let mut result = Vec::with_capacity(size);
for v in slice {
@ -609,14 +643,19 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
}
result
}
}
fn join(slice: &[Self], sep: &T) -> Vec<T> {
#[unstable(feature = "slice_concat_ext", issue = "27747")]
impl<T: Clone, V: Borrow<[T]>> Join<&T> for [V] {
type Output = Vec<T>;
fn join(slice: &Self, sep: &T) -> Vec<T> {
let mut iter = slice.iter();
let first = match iter.next() {
Some(first) => first,
None => return vec![],
};
let size = slice.iter().map(|slice| slice.borrow().len()).sum::<usize>() + slice.len() - 1;
let size = slice.iter().map(|v| v.borrow().len()).sum::<usize>() + slice.len() - 1;
let mut result = Vec::with_capacity(size);
result.extend_from_slice(first.borrow());
@ -628,6 +667,29 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
}
}
#[unstable(feature = "slice_concat_ext", issue = "27747")]
impl<T: Clone, V: Borrow<[T]>> Join<&[T]> for [V] {
type Output = Vec<T>;
fn join(slice: &Self, sep: &[T]) -> Vec<T> {
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::<usize>() +
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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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,17 +71,22 @@ 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")]
impl<S: Borrow<str>> SliceConcat<str> for S {
/// Note: `str` in `Concat<str>` is not meaningful here.
/// This type parameter of the trait only exists to enable another impl.
#[unstable(feature = "slice_concat_ext", issue = "27747")]
impl<S: Borrow<str>> Concat<str> for [S] {
type Output = String;
fn concat(slice: &[Self]) -> String {
Self::join(slice, "")
fn concat(slice: &Self) -> String {
Join::join(slice, "")
}
}
fn join(slice: &[Self], sep: &str) -> String {
#[unstable(feature = "slice_concat_ext", issue = "27747")]
impl<S: Borrow<str>> Join<&str> for [S] {
type Output = String;
fn join(slice: &Self, sep: &str) -> String {
unsafe {
String::from_utf8_unchecked( join_generic_copy(slice, sep.as_bytes()) )
}

View File

@ -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::<Option<String>>()` could return the
/// `"Option<String>"` or `"std::option::Option<std::string::String>"`, 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<T: ?Sized>() -> &'static str {
#[cfg(bootstrap)]
unsafe {
intrinsics::type_name::<T>()
}
#[cfg(not(bootstrap))]
intrinsics::type_name::<T>()
}

View File

@ -81,487 +81,296 @@ impl From<Infallible> 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<B> {
#[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<T, const N: usize> AsRef<[T]> for [T; N]
where
[T; N]: LengthAtMost32,
{
#[inline]
fn as_ref(&self) -> &[T] {
&self[..]
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, const N: usize> AsMut<[T]> for [T; N]
where
[T; N]: LengthAtMost32,
{
#[inline]
fn as_mut(&mut self) -> &mut [T] {
&mut self[..]
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> Borrow<[T]> for [T; N]
where
[T; N]: LengthAtMost32,
{
fn borrow(&self) -> &[T] {
self
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> 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<T, const N: usize> 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 = "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(()))
}
}
}
#[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 = "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, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
#[inline]
fn eq(&self, other: &$Lhs) -> bool { self[..] == other[..] }
#[inline]
fn ne(&self, other: &$Lhs) -> bool { self[..] != other[..] }
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(()))
}
}
}
// 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<T> AsRef<[T]> for [T; $N] {
#[inline]
fn as_ref(&self) -> &[T] {
&self[..]
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T; $N] {
#[inline]
fn as_mut(&mut self) -> &mut [T] {
&mut self[..]
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T> Borrow<[T]> for [T; $N] {
fn borrow(&self) -> &[T] {
self
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T> BorrowMut<[T]> for [T; $N] {
fn borrow_mut(&mut self) -> &mut [T] {
self
}
}
#[stable(feature = "try_from", since = "1.34.0")]
impl<T> 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<T: Hash> Hash for [T; $N] {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
Hash::hash(&self[..], state)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> 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<T:Eq> Eq for [T; $N] { }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T:PartialOrd> PartialOrd for [T; $N] {
#[inline]
fn partial_cmp(&self, other: &[T; $N]) -> Option<Ordering> {
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<T:Ord> Ord for [T; $N] {
#[inline]
fn cmp(&self, other: &[T; $N]) -> Ordering {
Ord::cmp(&&self[..], &&other[..])
}
}
)+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash, const N: usize> Hash for [T; N]
where
[T; N]: LengthAtMost32,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
Hash::hash(&self[..], state)
}
}
#[cfg(not(bootstrap))]
mod impls_using_const_generics {
use super::*;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, const N: usize> AsRef<[T]> for [T; N]
where
[T; N]: LengthAtMost32,
{
#[inline]
fn as_ref(&self) -> &[T] {
&self[..]
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug, const N: usize> 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 = "rust1", since = "1.0.0")]
impl<T, const N: usize> AsMut<[T]> for [T; N]
where
[T; N]: LengthAtMost32,
{
#[inline]
fn as_mut(&mut self) -> &mut [T] {
&mut self[..]
}
#[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 = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> Borrow<[T]> for [T; N]
where
[T; N]: LengthAtMost32,
{
fn borrow(&self) -> &[T] {
self
}
#[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()
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> 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<'a, 'b, A, B, const N: usize> PartialEq<[B; N]> for [A; N]
where
A: PartialEq<B>,
[A; N]: LengthAtMost32,
[B; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[B; N]) -> bool {
self[..] == other[..]
}
#[stable(feature = "try_from", since = "1.34.0")]
impl<T, const N: usize> 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)
}
#[inline]
fn ne(&self, other: &[B; N]) -> bool {
self[..] != other[..]
}
}
#[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 = "rust1", since = "1.0.0")]
impl<'a, 'b, A, B, const N: usize> PartialEq<[B]> for [A; N]
where
A: PartialEq<B>,
[A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[B]) -> bool {
self[..] == other[..]
}
#[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(()))
}
}
#[inline]
fn ne(&self, other: &[B]) -> bool {
self[..] != other[..]
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash, const N: usize> Hash for [T; N]
where
[T; N]: LengthAtMost32,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
Hash::hash(&self[..], state)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for [B]
where
B: PartialEq<A>,
[A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
self[..] == other[..]
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug, const N: usize> 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: &[A; 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 [B]> for [A; N]
where
A: PartialEq<B>,
[A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &&'b [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 [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<B>,
[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 [B]
where
B: PartialEq<A>,
[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<B>,
[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>,
[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<B>,
[A; N]: LengthAtMost32,
{
#[inline]
fn eq(&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 [B]> for [A; N]
where
A: PartialEq<B>,
[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 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 [B]
where
B: PartialEq<A>,
[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>,
[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 mut [B]> for [A; N]
where
A: PartialEq<B>,
[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[..]
}
#[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>,
[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] }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq, const N: usize> Eq for [T; N] where [T; N]: LengthAtMost32 {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd, const N: usize> PartialOrd for [T; N]
where
[T; N]: LengthAtMost32,
{
#[inline]
fn partial_cmp(&self, other: &[T; N]) -> Option<Ordering> {
PartialOrd::partial_cmp(&&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] }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq, const N: usize> Eq for [T; N] where [T; N]: LengthAtMost32 {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd, const N: usize> PartialOrd for [T; N]
where
[T; N]: LengthAtMost32,
{
#[inline]
fn partial_cmp(&self, other: &[T; N]) -> Option<Ordering> {
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[..])
}
#[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<T: Ord, const N: usize> 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<T: Ord, const N: usize> 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)+) => {
$(

View File

@ -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
///

View File

@ -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)]

View File

@ -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"]

View File

@ -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]

View File

@ -137,6 +137,10 @@ pub trait Fn<Args> : FnMut<Args> {
#[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}`",
)]

View File

@ -5,7 +5,6 @@
#![feature(core_private_diy_float)]
#![feature(debug_map_key_value)]
#![feature(dec2flt)]
#![feature(euclidean_division)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
#![feature(flt2dec)]

View File

@ -104,7 +104,6 @@ pub mod infer;
pub mod lint;
pub mod middle {
pub mod allocator;
pub mod borrowck;
pub mod expr_use_visitor;
pub mod cstore;

View File

@ -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),
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -34,7 +34,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
{
debug!(
"normalize::<{}>(value={:?}, param_env={:?})",
unsafe { ::std::intrinsics::type_name::<T>() },
::std::any::type_name::<T>(),
value,
self.param_env,
);

View File

@ -22,7 +22,7 @@ impl<'tcx> TyCtxt<'tcx> {
{
debug!(
"normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
unsafe { ::std::intrinsics::type_name::<T>() },
::std::any::type_name::<T>(),
value,
param_env,
);

View File

@ -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::<M>() };
let name = ::std::any::type_name::<M>();
format!("processing {:?} with query `{}`", def_id, name).into()
}
}

View File

@ -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;

View File

@ -1060,7 +1060,7 @@ where
Q::Value: Encodable,
{
let desc = &format!("encode_query_results for {}",
unsafe { ::std::intrinsics::type_name::<Q>() });
::std::any::type_name::<Q>());
time_ext(tcx.sess.time_extended(), Some(tcx.sess), desc, || {
let map = Q::query_cache(tcx).borrow();

View File

@ -782,9 +782,9 @@ macro_rules! define_queries_inner {
#[cfg(not(debug_assertions))]
cache_hits: 0,
key_size: mem::size_of::<Q::Key>(),
key_type: unsafe { type_name::<Q::Key>() },
key_type: type_name::<Q::Key>(),
value_size: mem::size_of::<Q::Value>(),
value_type: unsafe { type_name::<Q::Value>() },
value_type: type_name::<Q::Value>(),
entry_count: map.results.len(),
}
}

View File

@ -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"] }

View File

@ -1,298 +0,0 @@
use log::debug;
use rustc::middle::allocator::AllocatorKind;
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::{
base::{ExtCtxt, MacroKind, Resolver},
build::AstBuilder,
expand::ExpansionConfig,
hygiene::ExpnId,
},
mut_visit::{self, MutVisitor},
parse::ParseSess,
ptr::P,
symbol::{kw, sym}
};
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,
) {
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 rustc_errors::Handler,
sess: &'a ParseSess,
resolver: &'a mut dyn Resolver,
crate_name: Option<String>,
// 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<Item>) -> SmallVec<[P<Item>; 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];
}
if self.found {
self.handler
.span_err(item.span, "cannot define more than one `#[global_allocator]`");
return smallvec![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]
}
// 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");
}
// `visit_mac` is disabled by default. Enable it here.
fn visit_mac(&mut self, mac: &mut Mac) {
mut_visit::noop_visit_mac(mac, self)
}
}
struct AllocFnFactory<'a> {
span: Span,
kind: AllocatorKind,
global: Ident,
core: Ident,
cx: ExtCtxt<'a>,
}
impl AllocFnFactory<'_> {
fn allocator_fn(&self, method: &AllocatorMethod) -> P<Item> {
let mut abi_args = Vec::new();
let mut i = 0;
let ref mut mk = || {
let name = Ident::from_str(&format!("arg{}", i));
i += 1;
name
};
let args = method
.inputs
.iter()
.map(|ty| self.arg_ty(ty, &mut abi_args, mk))
.collect();
let result = self.call_allocator(method.name, args);
let (output_ty, output_expr) = self.ret_ty(&method.output, result);
let kind = ItemKind::Fn(
self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)),
FnHeader {
unsafety: Unsafety::Unsafe,
..FnHeader::default()
},
Generics::default(),
self.cx.block_expr(output_expr),
);
self.cx.item(
self.span,
Ident::from_str(&self.kind.fn_name(method.name)),
self.attrs(),
kind,
)
}
fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> {
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 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);
args.insert(0, allocator);
self.cx.expr_call(self.span, method, args)
}
fn attrs(&self) -> Vec<Attribute> {
let special = sym::rustc_std_internal_symbol;
let special = self.cx.meta_word(self.span, special);
vec![self.cx.attribute(self.span, special)]
}
fn arg_ty(
&self,
ty: &AllocatorTy,
args: &mut Vec<Arg>,
ident: &mut dyn FnMut() -> Ident,
) -> P<Expr> {
match *ty {
AllocatorTy::Layout => {
let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize));
let ty_usize = self.cx.ty_path(usize);
let size = ident();
let align = ident();
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 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]);
layout
}
AllocatorTy::Ptr => {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
let arg = self.cx.expr_ident(self.span, ident);
self.cx.expr_cast(self.span, arg, self.ptr_u8())
}
AllocatorTy::Usize => {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.usize()));
self.cx.expr_ident(self.span, ident)
}
AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("can't convert AllocatorTy to an argument")
}
}
}
fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) {
match *ty {
AllocatorTy::ResultPtr => {
// We're creating:
//
// #expr as *mut u8
let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8());
(self.ptr_u8(), expr)
}
AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr),
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("can't convert `AllocatorTy` to an output")
}
}
}
fn usize(&self) -> P<Ty> {
let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize));
self.cx.ty_path(usize)
}
fn ptr_u8(&self) -> P<Ty> {
let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8));
let ty_u8 = self.cx.ty_path(u8);
self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
}
}

View File

@ -1,44 +0,0 @@
#![feature(nll)]
#![feature(rustc_private)]
#![deny(rust_2018_idioms)]
#![deny(unused_lifetimes)]
pub mod expand;
pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
AllocatorMethod {
name: "alloc",
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultPtr,
},
AllocatorMethod {
name: "dealloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
output: AllocatorTy::Unit,
},
AllocatorMethod {
name: "realloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize],
output: AllocatorTy::ResultPtr,
},
AllocatorMethod {
name: "alloc_zeroed",
inputs: &[AllocatorTy::Layout],
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,
}

View File

@ -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};

View File

@ -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};

View File

@ -24,7 +24,6 @@ rustc_serialize = { path = "../libserialize", package = "serialize" }
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"}

View File

@ -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,

View File

@ -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 {

View File

@ -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" }
rustc_serialize = { path = "../libserialize", package = "serialize" }
syntax = { path = "../libsyntax" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }

View File

@ -18,7 +18,6 @@ syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_serialize = { path = "../libserialize", package = "serialize" }
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" }

View File

@ -469,7 +469,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)
});
@ -495,19 +495,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", || {
allocator::expand::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 {

View File

@ -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};

View File

@ -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,9 +25,9 @@ use std::{cmp, fs};
use syntax::ast;
use syntax::attr;
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,

View File

@ -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"]

View File

@ -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<T: ?Sized>() -> Cow<'static, str> {
let name = unsafe { ::std::intrinsics::type_name::<T>() };
let name = ::std::any::type_name::<T>();
if let Some(tail) = name.rfind(":") {
Cow::from(&name[tail+1..])
} else {

View File

@ -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<impl Debug>`.
/// 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
}

View File

@ -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,
}

View File

@ -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::<Vec<_>>()
.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(&note_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::<Vec<_>>()
.join(", ")).unwrap_or_else(|| "...".to_owned())));
print_disambiguation_help(err, self.tcx.def_path_str(trait_did));
}
}
}

View File

@ -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<E> SpecializationError for E {
default fn not_found<S, T: ?Sized>(trait_name: &'static str, method_name: &'static str) -> E {
panic!("missing specialization: `<{} as {}<{}>>::{}` not overridden",
unsafe { intrinsics::type_name::<S>() },
any::type_name::<S>(),
trait_name,
unsafe { intrinsics::type_name::<T>() },
any::type_name::<T>(),
method_name);
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -8,7 +8,8 @@
#![stable(feature = "raw_os", since = "1.1.0")]
#[doc(include = "os/raw/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 = "hexagon",
@ -32,7 +33,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(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 = "hexagon",
@ -56,37 +58,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(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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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;
#[doc(include = "os/raw/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")]

View File

@ -362,8 +362,13 @@ 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`]. 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.
///
/// 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 +447,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 { }
@ -891,9 +897,13 @@ 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, 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 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.
///
/// 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
@ -1036,6 +1046,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, 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<fn()>` with your required signature.
///
/// Plain function pointers are obtained by casting either plain functions, or closures that don't
/// capture an environment:
///
@ -1091,10 +1106,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<fn()>` with your required signature.
///
/// Function pointers implement the following traits:
///
/// * [`Clone`]

View File

@ -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<bool>` 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<bool>` 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<bool>` 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<bool>` 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<bool>` 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<bool>` is `false`, we wait.
/// while !*started {

View File

@ -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,76 @@ 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 ||
name == sym::test || name == sym::bench;
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(),
}
}

View File

@ -0,0 +1,75 @@
use crate::{ast, attr, visit};
use crate::symbol::{sym, Symbol};
use syntax_pos::Span;
#[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),
}
}
}
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 {
name: "alloc",
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultPtr,
},
AllocatorMethod {
name: "dealloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
output: AllocatorTy::Unit,
},
AllocatorMethod {
name: "realloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize],
output: AllocatorTy::ResultPtr,
},
AllocatorMethod {
name: "alloc_zeroed",
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultPtr,
},
];
pub fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
struct Finder { name: Symbol, spans: Vec<Span> }
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
}

View File

@ -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<PathBuf>, 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`,

View File

@ -1253,7 +1253,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 = self.cx.resolve_path(&*file.as_str(), it.span());
match fs::read_to_string(&filename) {
Ok(src) => {
let src_interned = Symbol::intern(&src);
@ -1302,10 +1302,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();
}
}

View File

@ -8,11 +8,10 @@ use crate::symbol::Symbol;
use crate::tokenstream;
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 +77,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 = cx.resolve_path(file, sp);
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 +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 = res_rel_file(cx, sp, file);
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 = res_rel_file(cx, sp, file);
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.
@ -164,24 +163,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
}
}

View File

@ -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)]`.
@ -1117,7 +1095,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]` \
@ -1902,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> {
@ -2006,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.

View File

@ -162,6 +162,7 @@ pub mod print {
pub mod ext {
pub use syntax_pos::hygiene;
pub mod allocator;
pub mod base;
pub mod build;
pub mod derive;

View File

@ -7671,6 +7671,11 @@ 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.get(prev).is_none() {
// This can happen due to a bad interaction of two unrelated recovery mechanisms with
// 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
};
@ -7678,7 +7683,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 the likely typo
// `pub ident(` (#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

View File

@ -0,0 +1,191 @@
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::symbol::{kw, sym, Symbol};
use syntax_pos::Span;
pub fn expand(
ecx: &mut ExtCtxt<'_>,
_span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
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");
vec![item]
};
let item = match item {
Annotatable::Item(item) => match item.node {
ItemKind::Static(..) => item,
_ => return not_static(Annotatable::Item(item)),
}
_ => 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.id));
let f = AllocFnFactory {
span,
kind: AllocatorKind::Global,
global: item.ident,
cx: ecx,
};
// Generate item statements for the allocator methods.
let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
// 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 original item and the new methods.
vec![Annotatable::Item(item), Annotatable::Item(const_item)]
}
struct AllocFnFactory<'a, 'b> {
span: Span,
kind: AllocatorKind,
global: Ident,
cx: &'b ExtCtxt<'a>,
}
impl AllocFnFactory<'_, '_> {
fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt {
let mut abi_args = Vec::new();
let mut i = 0;
let ref mut mk = || {
let name = Ident::from_str(&format!("arg{}", i));
i += 1;
name
};
let args = method
.inputs
.iter()
.map(|ty| self.arg_ty(ty, &mut abi_args, mk))
.collect();
let result = self.call_allocator(method.name, args);
let (output_ty, output_expr) = self.ret_ty(&method.output, result);
let kind = ItemKind::Fn(
self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)),
FnHeader {
unsafety: Unsafety::Unsafe,
..FnHeader::default()
},
Generics::default(),
self.cx.block_expr(output_expr),
);
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<Expr>>) -> P<Expr> {
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);
args.insert(0, allocator);
self.cx.expr_call(self.span, method, args)
}
fn attrs(&self) -> Vec<Attribute> {
let special = sym::rustc_std_internal_symbol;
let special = self.cx.meta_word(self.span, special);
vec![self.cx.attribute(self.span, special)]
}
fn arg_ty(
&self,
ty: &AllocatorTy,
args: &mut Vec<Arg>,
ident: &mut dyn FnMut() -> Ident,
) -> P<Expr> {
match *ty {
AllocatorTy::Layout => {
let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize));
let ty_usize = self.cx.ty_path(usize);
let size = ident();
let align = ident();
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.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]);
layout
}
AllocatorTy::Ptr => {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
let arg = self.cx.expr_ident(self.span, ident);
self.cx.expr_cast(self.span, arg, self.ptr_u8())
}
AllocatorTy::Usize => {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.usize()));
self.cx.expr_ident(self.span, ident)
}
AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("can't convert AllocatorTy to an argument")
}
}
}
fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) {
match *ty {
AllocatorTy::ResultPtr => {
// We're creating:
//
// #expr as *mut u8
let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8());
(self.ptr_u8(), expr)
}
AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr),
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("can't convert `AllocatorTy` to an output")
}
}
}
fn usize(&self) -> P<Ty> {
let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize));
self.cx.ty_path(usize)
}
fn ptr_u8(&self) -> P<Ty> {
let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8));
let ty_u8 = self.cx.ty_path(u8);
self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
}
}

View File

@ -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;
@ -151,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 {

View File

@ -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<Annotatable> {
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<Annotatable> {
check_builtin_macro_attribute(cx, meta_item, sym::bench);
expand_test_or_bench(cx, attr_sp, item, true)
}

View File

@ -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<Annotatable> {
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));

@ -1 +1 @@
Subproject commit b881a2d124cb0eea09d137300eb4a35829b517fb
Subproject commit 4791ba85e7645c02146dd416288480943670d1ca

View File

@ -0,0 +1,22 @@
// 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 n = GLOBAL.0.load(Ordering::SeqCst);
let s = Box::new(0);
helper::work_with(&s);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
drop(s);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
}

View File

@ -0,0 +1,26 @@
// 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 n = submodule::GLOBAL.0.load(Ordering::SeqCst);
let s = Box::new(0);
helper::work_with(&s);
assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), n + 1);
drop(s);
assert_eq!(submodule::GLOBAL.0.load(Ordering::SeqCst), n + 2);
}

View File

@ -5,7 +5,7 @@
#![allow(dead_code)]
const fn type_name_wrapper<T>(_: &T) -> &'static str {
unsafe { core::intrinsics::type_name::<T>() }
core::intrinsics::type_name::<T>()
}
struct Struct<TA, TB, TC> {

View File

@ -56,8 +56,20 @@ fn overlap_move_points() -> impl Generator<Yield = (), Return = ()> {
}
}
fn overlap_x_and_y() -> impl Generator<Yield = (), Return = ()>{
static || {
let x = Foo([0; FOO_SIZE]);
yield;
drop(x);
let y = Foo([0; FOO_SIZE]);
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!(1032, std::mem::size_of_val(&overlap_x_and_y()));
}

View File

@ -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<T: Trait>() {
}
fn type_name_of_val<T>(_: T) -> &'static str {
unsafe { std::intrinsics::type_name::<T>() }
std::any::type_name::<T>()
}
#[derive(Debug)]

View File

@ -1,6 +1,6 @@
#![feature(core_intrinsics)]
use std::intrinsics::type_name;
use std::any::type_name;
struct Bar<M>(M);
@ -8,7 +8,7 @@ impl<M> Bar<M> {
fn foo(&self) -> &'static str {
fn f() {}
fn type_name_of<T>(_: T) -> &'static str {
unsafe { type_name::<T>() }
type_name::<T>()
}
type_name_of(f)
}

View File

@ -1,16 +1,12 @@
#![allow(dead_code)]
#![feature(core_intrinsics)]
use std::intrinsics::type_name;
use std::any::type_name;
struct Foo<T> {
x: T
}
pub fn main() {
unsafe {
assert_eq!(type_name::<isize>(), "isize");
assert_eq!(type_name::<Foo<usize>>(), "tydesc_name::Foo<usize>");
}
assert_eq!(type_name::<isize>(), "isize");
assert_eq!(type_name::<Foo<usize>>(), "tydesc_name::Foo<usize>");
}

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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`.

View File

@ -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

View File

@ -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

View File

@ -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 = "<path>"`
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 = "<path>"`
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 = "<path>"`

View File

@ -1,3 +1,13 @@
warning: attribute must be of the form `#[bench]`
--> $DIR/issue-43106-gating-of-bench.rs:15:1
|
LL | #![bench = "4100"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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 <https://github.com/rust-lang/rust/issues/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`

View File

@ -1,3 +1,13 @@
warning: attribute must be of the form `#[test]`
--> $DIR/issue-43106-gating-of-test.rs:10:1
|
LL | #![test = "4200"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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 <https://github.com/rust-lang/rust/issues/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`

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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`.

View File

@ -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

View File

@ -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<Self, u64>) -> 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
|

View File

@ -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

View File

@ -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`.

View File

@ -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 `;`
}

View File

@ -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`.

View File

@ -0,0 +1,5 @@
fn main() {
let line = String::from("abc");
let pattern = String::from("bc");
println!("{:?}", line.find(pattern)); //~ ERROR E0277
}

View File

@ -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`.

View File

@ -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

View File

@ -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(),