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:
commit
18630677cf
18
Cargo.lock
18
Cargo.lock
|
@ -2751,20 +2751,6 @@ dependencies = [
|
|||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_allocator"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_target 0.0.0",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_apfloat"
|
||||
version = "0.0.0"
|
||||
|
@ -2822,7 +2808,6 @@ dependencies = [
|
|||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_allocator 0.0.0",
|
||||
"rustc_apfloat 0.0.0",
|
||||
"rustc_codegen_utils 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
|
@ -2883,7 +2868,6 @@ dependencies = [
|
|||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_allocator 0.0.0",
|
||||
"rustc_ast_borrowck 0.0.0",
|
||||
"rustc_codegen_utils 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
|
@ -2904,7 +2888,6 @@ dependencies = [
|
|||
"serialize 0.0.0",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntax 0.0.0",
|
||||
"syntax_ext 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
|
@ -2948,7 +2931,6 @@ dependencies = [
|
|||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_allocator 0.0.0",
|
||||
"rustc_ast_borrowck 0.0.0",
|
||||
"rustc_codegen_ssa 0.0.0",
|
||||
"rustc_codegen_utils 0.0.0",
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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()) )
|
||||
}
|
||||
|
|
|
@ -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>()
|
||||
}
|
||||
|
|
|
@ -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)+) => {
|
||||
$(
|
||||
|
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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}`",
|
||||
)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"] }
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -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};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"]
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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(¬e_str);
|
||||
}
|
||||
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
|
||||
print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id));
|
||||
}
|
||||
}
|
||||
CandidateSource::TraitSource(trait_did) => {
|
||||
let item = match self.associated_item(
|
||||
|
@ -163,24 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
"the candidate is defined in the trait `{}`",
|
||||
self.tcx.def_path_str(trait_did));
|
||||
}
|
||||
err.help(&format!("to disambiguate the method call, write `{}::{}({}{})` \
|
||||
instead",
|
||||
self.tcx.def_path_str(trait_did),
|
||||
item_name,
|
||||
if rcvr_ty.is_region_ptr() && args.is_some() {
|
||||
if rcvr_ty.is_mutable_pointer() {
|
||||
"&mut "
|
||||
} else {
|
||||
"&"
|
||||
}
|
||||
} else {
|
||||
""
|
||||
},
|
||||
args.map(|arg| arg.iter()
|
||||
.map(|arg| print::to_string(print::NO_ANN,
|
||||
|s| s.print_expr(arg)))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")).unwrap_or_else(|| "...".to_owned())));
|
||||
print_disambiguation_help(err, self.tcx.def_path_str(trait_did));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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`]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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`,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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> {
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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>");
|
||||
}
|
||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||
|
|
@ -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() {}
|
|
@ -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
|
||||
|
|
@ -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() {}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>"`
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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`.
|
|
@ -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
|
||||
}
|
|
@ -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`.
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
|
|
@ -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
|
|
@ -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`.
|
|
@ -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 `;`
|
||||
}
|
|
@ -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`.
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
let line = String::from("abc");
|
||||
let pattern = String::from("bc");
|
||||
println!("{:?}", line.find(pattern)); //~ ERROR E0277
|
||||
}
|
|
@ -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`.
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Reference in New Issue