Auto merge of #71445 - Dylan-DPC:rollup-31givp1, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #71256 (Lint must_use on mem::replace) - #71350 (Error code explanation extra check) - #71369 (allow wasm32 compilation of librustc_data_structures/profiling.rs) - #71400 (proc_macro::is_available()) - #71440 (Implement `Copy` for `AllocErr`) Failed merges: r? @ghost
This commit is contained in:
commit
fc145e19d0
41 changed files with 344 additions and 128 deletions
|
|
@ -18,7 +18,7 @@ use crate::ptr::{self, NonNull};
|
|||
/// something wrong when combining the given input arguments with this
|
||||
/// allocator.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct AllocErr;
|
||||
|
||||
// (we need this for downstream impl of trait Error)
|
||||
|
|
|
|||
|
|
@ -709,6 +709,7 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
|
|||
/// So this, for example, can only be done on types implementing `Unpin`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(unused_must_use)]
|
||||
/// use std::mem;
|
||||
/// use std::pin::Pin;
|
||||
///
|
||||
|
|
|
|||
|
|
@ -808,6 +808,7 @@ pub fn take<T: Default>(dest: &mut T) -> T {
|
|||
/// [`Clone`]: ../../std/clone/trait.Clone.html
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use = "if you don't need the old value, you can just assign the new value directly"]
|
||||
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
||||
swap(dest, &mut src);
|
||||
src
|
||||
|
|
|
|||
|
|
@ -290,6 +290,13 @@ impl BridgeState<'_> {
|
|||
}
|
||||
|
||||
impl Bridge<'_> {
|
||||
pub(crate) fn is_available() -> bool {
|
||||
BridgeState::with(|state| match state {
|
||||
BridgeState::Connected(_) | BridgeState::InUse => true,
|
||||
BridgeState::NotConnected => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn enter<R>(self, f: impl FnOnce() -> R) -> R {
|
||||
// Hide the default panic output within `proc_macro` expansions.
|
||||
// NB. the server can't do this because it may use a different libstd.
|
||||
|
|
|
|||
|
|
@ -45,6 +45,24 @@ use std::path::PathBuf;
|
|||
use std::str::FromStr;
|
||||
use std::{error, fmt, iter, mem};
|
||||
|
||||
/// Determines whether proc_macro has been made accessible to the currently
|
||||
/// running program.
|
||||
///
|
||||
/// The proc_macro crate is only intended for use inside the implementation of
|
||||
/// procedural macros. All the functions in this crate panic if invoked from
|
||||
/// outside of a procedural macro, such as from a build script or unit test or
|
||||
/// ordinary Rust binary.
|
||||
///
|
||||
/// With consideration for Rust libraries that are designed to support both
|
||||
/// macro and non-macro use cases, `proc_macro::is_available()` provides a
|
||||
/// non-panicking way to detect whether the infrastructure required to use the
|
||||
/// API of proc_macro is presently available. Returns true if invoked from
|
||||
/// inside of a procedural macro, false if invoked from any other binary.
|
||||
#[unstable(feature = "proc_macro_is_available", issue = "71436")]
|
||||
pub fn is_available() -> bool {
|
||||
bridge::Bridge::is_available()
|
||||
}
|
||||
|
||||
/// The main type provided by this crate, representing an abstract stream of
|
||||
/// tokens, or, more specifically, a sequence of token trees.
|
||||
/// The type provide interfaces for iterating over those token trees and, conversely,
|
||||
|
|
|
|||
|
|
@ -97,12 +97,17 @@ use std::time::{Duration, Instant};
|
|||
use measureme::{EventId, EventIdBuilder, SerializableString, StringId};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
/// MmapSerializatioSink is faster on macOS and Linux
|
||||
/// but FileSerializationSink is faster on Windows
|
||||
#[cfg(not(windows))]
|
||||
type SerializationSink = measureme::MmapSerializationSink;
|
||||
#[cfg(windows)]
|
||||
type SerializationSink = measureme::FileSerializationSink;
|
||||
cfg_if! {
|
||||
if #[cfg(any(windows, target_os = "wasi"))] {
|
||||
/// FileSerializationSink is faster on Windows
|
||||
type SerializationSink = measureme::FileSerializationSink;
|
||||
} else if #[cfg(target_arch = "wasm32")] {
|
||||
type SerializationSink = measureme::ByteVecSink;
|
||||
} else {
|
||||
/// MmapSerializatioSink is faster on macOS and Linux
|
||||
type SerializationSink = measureme::MmapSerializationSink;
|
||||
}
|
||||
}
|
||||
|
||||
type Profiler = measureme::Profiler<SerializationSink>;
|
||||
|
||||
|
|
@ -602,31 +607,37 @@ pub fn duration_to_secs_str(dur: std::time::Duration) -> String {
|
|||
}
|
||||
|
||||
// Memory reporting
|
||||
#[cfg(unix)]
|
||||
fn get_resident() -> Option<usize> {
|
||||
let field = 1;
|
||||
let contents = fs::read("/proc/self/statm").ok()?;
|
||||
let contents = String::from_utf8(contents).ok()?;
|
||||
let s = contents.split_whitespace().nth(field)?;
|
||||
let npages = s.parse::<usize>().ok()?;
|
||||
Some(npages * 4096)
|
||||
}
|
||||
cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
fn get_resident() -> Option<usize> {
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::processthreadsapi::GetCurrentProcess;
|
||||
use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS};
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_resident() -> Option<usize> {
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::processthreadsapi::GetCurrentProcess;
|
||||
use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS};
|
||||
|
||||
let mut pmc = MaybeUninit::<PROCESS_MEMORY_COUNTERS>::uninit();
|
||||
match unsafe {
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD)
|
||||
} {
|
||||
0 => None,
|
||||
_ => {
|
||||
let pmc = unsafe { pmc.assume_init() };
|
||||
Some(pmc.WorkingSetSize as usize)
|
||||
let mut pmc = MaybeUninit::<PROCESS_MEMORY_COUNTERS>::uninit();
|
||||
match unsafe {
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD)
|
||||
} {
|
||||
0 => None,
|
||||
_ => {
|
||||
let pmc = unsafe { pmc.assume_init() };
|
||||
Some(pmc.WorkingSetSize as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if #[cfg(unix)] {
|
||||
fn get_resident() -> Option<usize> {
|
||||
let field = 1;
|
||||
let contents = fs::read("/proc/self/statm").ok()?;
|
||||
let contents = String::from_utf8(contents).ok()?;
|
||||
let s = contents.split_whitespace().nth(field)?;
|
||||
let npages = s.parse::<usize>().ok()?;
|
||||
Some(npages * 4096)
|
||||
}
|
||||
} else {
|
||||
fn get_resident() -> Option<usize> {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ External C functions are allowed to be variadic. However, a variadic function
|
|||
takes a minimum number of arguments. For example, consider C's variadic `printf`
|
||||
function:
|
||||
|
||||
```
|
||||
```compile_fail,E0060
|
||||
use std::os::raw::{c_char, c_int};
|
||||
|
||||
extern "C" {
|
||||
fn printf(_: *const c_char, ...) -> c_int;
|
||||
}
|
||||
|
||||
unsafe { printf(); } // error!
|
||||
```
|
||||
|
||||
Using this declaration, it must be called with at least one argument, so
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ A pattern was declared as an argument in a foreign function declaration.
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0130
|
||||
extern {
|
||||
fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign
|
||||
// function declarations
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ A negative implementation was marked as unsafe.
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0198
|
||||
struct Foo;
|
||||
|
||||
unsafe impl !Clone for Foo { } // error!
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
Inherent associated types were part of [RFC 195] but are not yet implemented.
|
||||
See [the tracking issue][iss8995] for the status of this implementation.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0202
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
type Bar = isize; // error!
|
||||
}
|
||||
```
|
||||
|
||||
[RFC 195]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md
|
||||
[iss8995]: https://github.com/rust-lang/rust/issues/8995
|
||||
|
|
|
|||
|
|
@ -3,15 +3,11 @@ message for when a particular trait isn't implemented on a type placed in a
|
|||
position that needs that trait. For example, when the following code is
|
||||
compiled:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0230
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn foo<T: Index<u8>>(x: T){}
|
||||
|
||||
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
|
||||
trait Index<Idx> { /* ... */ }
|
||||
|
||||
foo(true); // `bool` does not implement `Index<u8>`
|
||||
#[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{B}>`"] // error
|
||||
trait BadAnnotation<A> {}
|
||||
```
|
||||
|
||||
There will be an error about `bool` not implementing `Index<u8>`, followed by a
|
||||
|
|
|
|||
|
|
@ -3,15 +3,11 @@ message for when a particular trait isn't implemented on a type placed in a
|
|||
position that needs that trait. For example, when the following code is
|
||||
compiled:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0231
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn foo<T: Index<u8>>(x: T){}
|
||||
|
||||
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
|
||||
trait Index<Idx> { /* ... */ }
|
||||
|
||||
foo(true); // `bool` does not implement `Index<u8>`
|
||||
#[rustc_on_unimplemented = "error on `{Self}` with params `<{A},{}>`"] // error!
|
||||
trait BadAnnotation<A> {}
|
||||
```
|
||||
|
||||
there will be an error about `bool` not implementing `Index<u8>`, followed by a
|
||||
|
|
|
|||
|
|
@ -3,15 +3,11 @@ message for when a particular trait isn't implemented on a type placed in a
|
|||
position that needs that trait. For example, when the following code is
|
||||
compiled:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0232
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn foo<T: Index<u8>>(x: T){}
|
||||
|
||||
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
|
||||
trait Index<Idx> { /* ... */ }
|
||||
|
||||
foo(true); // `bool` does not implement `Index<u8>`
|
||||
#[rustc_on_unimplemented(lorem="")] // error!
|
||||
trait BadAnnotation {}
|
||||
```
|
||||
|
||||
there will be an error about `bool` not implementing `Index<u8>`, followed by a
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ You tried to supply a type which doesn't implement some trait in a location
|
|||
which expected that trait. This error typically occurs when working with
|
||||
`Fn`-based types. Erroneous code example:
|
||||
|
||||
```compile-fail
|
||||
```compile_fail
|
||||
fn foo<F: Fn(usize)>(x: F) { }
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -3,27 +3,27 @@ attempted to `pub use` a type or value that was not itself public.
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail
|
||||
mod foo {
|
||||
const X: u32 = 1;
|
||||
```compile_fail,E0364
|
||||
mod a {
|
||||
fn foo() {}
|
||||
|
||||
mod a {
|
||||
pub use super::foo; // error!
|
||||
}
|
||||
}
|
||||
|
||||
pub use foo::X;
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
The solution to this problem is to ensure that the items that you are
|
||||
re-exporting are themselves marked with `pub`:
|
||||
|
||||
```
|
||||
mod foo {
|
||||
pub const X: u32 = 1;
|
||||
mod a {
|
||||
pub fn foo() {} // ok!
|
||||
|
||||
mod a {
|
||||
pub use super::foo;
|
||||
}
|
||||
}
|
||||
|
||||
pub use foo::X;
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
See the [Use Declarations][use-declarations] section of the reference for
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ or a newtype wrapper around a pointer.
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```compile-fail,E0378
|
||||
```compile_fail,E0378
|
||||
#![feature(dispatch_from_dyn)]
|
||||
use std::ops::DispatchFromDyn;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0590
|
||||
while break {}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,5 +3,17 @@ instantiated from outside of the defining crate as it has been marked
|
|||
as `non_exhaustive` and as such more fields/variants may be added in
|
||||
future that could cause adverse side effects for this code.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```ignore (it only works cross-crate)
|
||||
#[non_exhaustive]
|
||||
pub struct NormalStruct {
|
||||
pub first_field: u16,
|
||||
pub second_field: u16,
|
||||
}
|
||||
|
||||
let ns = NormalStruct { first_field: 640, second_field: 480 }; // error!
|
||||
```
|
||||
|
||||
It is recommended that you look for a `new` function or equivalent in the
|
||||
crate's documentation.
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@ A closure or generator was constructed that references its own type.
|
|||
|
||||
Erroneous example:
|
||||
|
||||
```compile-fail,E0644
|
||||
```compile_fail,E0644
|
||||
fn fix<F>(f: &F)
|
||||
where F: Fn(&F)
|
||||
{
|
||||
f(&f);
|
||||
f(&f);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fix(&|y| {
|
||||
// Here, when `x` is called, the parameter `y` is equal to `x`.
|
||||
});
|
||||
fix(&|y| {
|
||||
// Here, when `x` is called, the parameter `y` is equal to `x`.
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ An unstable feature was used.
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E658
|
||||
```compile_fail,E0658
|
||||
#[repr(u128)] // error: use of unstable library feature 'repr128'
|
||||
enum Foo {
|
||||
Bar(u64),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
Cannot convert inline assembly operand to a single LLVM value.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0669
|
||||
#![feature(llvm_asm)]
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
llvm_asm!("" :: "r"("")); // error!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This error usually happens when trying to pass in a value to an input inline
|
||||
assembly operand that is actually a pair of values. In particular, this can
|
||||
happen when trying to pass in a slice, for instance a `&str`. In Rust, these
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ generator can be constructed.
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```edition2018,compile-fail,E0698
|
||||
```edition2018,compile_fail,E0698
|
||||
async fn bar<T>() -> () {}
|
||||
|
||||
async fn foo() {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ appear within the `impl Trait` itself.
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```compile-fail,E0700
|
||||
```compile_fail,E0700
|
||||
use std::cell::Cell;
|
||||
|
||||
trait Trait<'a> { }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,edition2018
|
||||
```compile_fail,edition2018,E0708
|
||||
#![feature(async_closure)]
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,19 @@
|
|||
A `#[marker]` trait contained an associated item.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0714
|
||||
#![feature(marker_trait_attr)]
|
||||
#![feature(associated_type_defaults)]
|
||||
|
||||
#[marker]
|
||||
trait MarkerConst {
|
||||
const N: usize; // error!
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
The items of marker traits cannot be overridden, so there's no need to have them
|
||||
when they cannot be changed per-type anyway. If you wanted them for ergonomic
|
||||
reasons, consider making an extension trait instead.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,24 @@
|
|||
An `impl` for a `#[marker]` trait tried to override an associated item.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0715
|
||||
#![feature(marker_trait_attr)]
|
||||
|
||||
#[marker]
|
||||
trait Marker {
|
||||
const N: usize = 0;
|
||||
fn do_something() {}
|
||||
}
|
||||
|
||||
struct OverrideConst;
|
||||
impl Marker for OverrideConst { // error!
|
||||
const N: usize = 1;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
Because marker traits are allowed to have multiple implementations for the same
|
||||
type, it's not allowed to override anything in those implementations, as it
|
||||
would be ambiguous which override should actually be used.
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@ A `yield` clause was used in an `async` context.
|
|||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail
|
||||
```compile_fail,E0727,edition2018
|
||||
#![feature(generators)]
|
||||
|
||||
let generator = || {
|
||||
async {
|
||||
yield;
|
||||
}
|
||||
};
|
||||
fn main() {
|
||||
let generator = || {
|
||||
async {
|
||||
yield;
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Here, the `yield` keyword is used in an `async` block,
|
||||
|
|
@ -17,10 +19,12 @@ which is not yet supported.
|
|||
|
||||
To fix this error, you have to move `yield` out of the `async` block:
|
||||
|
||||
```
|
||||
```edition2018
|
||||
#![feature(generators)]
|
||||
|
||||
let generator = || {
|
||||
yield;
|
||||
};
|
||||
fn main() {
|
||||
let generator = || {
|
||||
yield;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,5 +1,18 @@
|
|||
An `enum` with a discriminant must specify a `#[repr(inttype)]`.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0732
|
||||
#![feature(arbitrary_enum_discriminant)]
|
||||
|
||||
enum Enum { // error!
|
||||
Unit = 1,
|
||||
Tuple() = 2,
|
||||
Struct{} = 3,
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
A `#[repr(inttype)]` must be provided on an `enum` if it has a non-unit
|
||||
variant with a discriminant, or where there are both unit variants with
|
||||
discriminants and non-unit variants. This restriction ensures that there
|
||||
|
|
@ -23,7 +36,9 @@ fn discriminant(v : &Enum) -> u8 {
|
|||
unsafe { *(v as *const Enum as *const u8) }
|
||||
}
|
||||
|
||||
assert_eq!(3, discriminant(&Enum::Unit));
|
||||
assert_eq!(2, discriminant(&Enum::Tuple(5)));
|
||||
assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
|
||||
fn main() {
|
||||
assert_eq!(3, discriminant(&Enum::Unit));
|
||||
assert_eq!(2, discriminant(&Enum::Tuple(5)));
|
||||
assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1 +1,16 @@
|
|||
A `union` cannot have fields with destructors.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0740
|
||||
union Test {
|
||||
a: A, // error!
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct A(i32);
|
||||
|
||||
impl Drop for A {
|
||||
fn drop(&mut self) { println!("A"); }
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,16 +3,13 @@ Control-flow expressions are not allowed inside a const context.
|
|||
At the moment, `if` and `match`, as well as the looping constructs `for`,
|
||||
`while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`.
|
||||
|
||||
```compile_fail,E0658
|
||||
```compile_fail,E0744
|
||||
const _: i32 = {
|
||||
let mut x = 0;
|
||||
loop {
|
||||
x += 1;
|
||||
if x == 4 {
|
||||
break;
|
||||
}
|
||||
|
||||
for i in 0..4 { // error!
|
||||
x += i;
|
||||
}
|
||||
x
|
||||
};
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -547,8 +547,7 @@ impl<'a> Parser<'a> {
|
|||
// Rewind to before attempting to parse the type with generics, to recover
|
||||
// from situations like `x as usize < y` in which we first tried to parse
|
||||
// `usize < y` as a type with generic arguments.
|
||||
let parser_snapshot_after_type = self.clone();
|
||||
mem::replace(self, parser_snapshot_before_type);
|
||||
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
|
||||
|
||||
match self.parse_path(PathStyle::Expr) {
|
||||
Ok(path) => {
|
||||
|
|
@ -560,7 +559,7 @@ impl<'a> Parser<'a> {
|
|||
// example because `parse_ty_no_plus` returns `Err` on keywords,
|
||||
// but `parse_path` returns `Ok` on them due to error recovery.
|
||||
// Return original error and parser state.
|
||||
mem::replace(self, parser_snapshot_after_type);
|
||||
*self = parser_snapshot_after_type;
|
||||
return Err(type_err);
|
||||
}
|
||||
};
|
||||
|
|
@ -601,7 +600,7 @@ impl<'a> Parser<'a> {
|
|||
Err(mut path_err) => {
|
||||
// Couldn't parse as a path, return original error and parser state.
|
||||
path_err.cancel();
|
||||
mem::replace(self, parser_snapshot_after_type);
|
||||
*self = parser_snapshot_after_type;
|
||||
return Err(type_err);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
Err(mut err) => {
|
||||
err.cancel();
|
||||
std::mem::replace(self, snapshot);
|
||||
*self = snapshot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1650,7 +1650,7 @@ impl<'a> Parser<'a> {
|
|||
// Recover from attempting to parse the argument as a type without pattern.
|
||||
Err(mut err) => {
|
||||
err.cancel();
|
||||
mem::replace(self, parser_snapshot_before_ty);
|
||||
*self = parser_snapshot_before_ty;
|
||||
self.recover_arg_parse()?
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ impl<'a> Parser<'a> {
|
|||
Ok(ty) => (None, Some(ty)),
|
||||
Err(mut err) => {
|
||||
// Rewind to before attempting to parse the type and continue parsing.
|
||||
let parser_snapshot_after_type = self.clone();
|
||||
mem::replace(self, parser_snapshot_before_type);
|
||||
let parser_snapshot_after_type =
|
||||
mem::replace(self, parser_snapshot_before_type);
|
||||
if let Ok(snip) = self.span_to_snippet(pat.span) {
|
||||
err.span_label(pat.span, format!("while parsing the type for `{}`", snip));
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ impl<'a> Parser<'a> {
|
|||
// Couldn't parse the type nor the initializer, only raise the type error and
|
||||
// return to the parser state before parsing the type as the initializer.
|
||||
// let x: <parse_error>;
|
||||
mem::replace(self, snapshot);
|
||||
*self = snapshot;
|
||||
return Err(ty_err);
|
||||
}
|
||||
(Err(err), None) => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use rustc_span::symbol::{kw, sym};
|
|||
use rustc_span::Span;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::mem::{replace, take};
|
||||
use std::mem::take;
|
||||
|
||||
use log::debug;
|
||||
|
||||
|
|
@ -371,7 +371,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| {
|
||||
this.visit_body(body);
|
||||
});
|
||||
replace(&mut self.labels_in_fn, saved);
|
||||
self.labels_in_fn = saved;
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ mod lazy {
|
|||
// value (an aliasing violation). To avoid setting the "I'm running a
|
||||
// destructor" flag we just use `mem::replace` which should sequence the
|
||||
// operations a little differently and make this safe to call.
|
||||
mem::replace(&mut *ptr, Some(value));
|
||||
let _ = mem::replace(&mut *ptr, Some(value));
|
||||
|
||||
// After storing `Some` we want to get a reference to the contents of
|
||||
// what we just stored. While we could use `unwrap` here and it should
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
pub fn main() {
|
||||
use std::mem::replace;
|
||||
let mut x = 5;
|
||||
replace(&mut x, 6);
|
||||
let _ = replace(&mut x, 6);
|
||||
{
|
||||
use std::mem::*;
|
||||
let mut y = 6;
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ impl<'a> Drop for E<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
if do_drop {
|
||||
mem::replace(self, E::A(GaspA(f_a, 0xA3A0, log, D::new("drop", 6, log)), true));
|
||||
}
|
||||
|
|
|
|||
14
src/test/ui/proc-macro/auxiliary/is-available.rs
Normal file
14
src/test/ui/proc-macro/auxiliary/is-available.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
#![feature(proc_macro_is_available)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::{Literal, TokenStream, TokenTree};
|
||||
|
||||
#[proc_macro]
|
||||
pub fn from_inside_proc_macro(_input: TokenStream) -> TokenStream {
|
||||
proc_macro::is_available().to_string().parse().unwrap()
|
||||
}
|
||||
17
src/test/ui/proc-macro/is-available.rs
Normal file
17
src/test/ui/proc-macro/is-available.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(proc_macro_hygiene, proc_macro_is_available)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
// aux-build:is-available.rs
|
||||
extern crate is_available;
|
||||
|
||||
fn main() {
|
||||
let a = proc_macro::is_available();
|
||||
let b = is_available::from_inside_proc_macro!();
|
||||
let c = proc_macro::is_available();
|
||||
assert!(!a);
|
||||
assert!(b);
|
||||
assert!(!c);
|
||||
}
|
||||
|
|
@ -15,21 +15,57 @@ const WHITELIST: &[&str] = &[
|
|||
"E0727", "E0729",
|
||||
];
|
||||
|
||||
// Some error codes don't have any tests apparently...
|
||||
const IGNORE_EXPLANATION_CHECK: &[&str] =
|
||||
&["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750", "E0751"];
|
||||
|
||||
fn check_error_code_explanation(
|
||||
f: &str,
|
||||
error_codes: &mut HashMap<String, bool>,
|
||||
err_code: String,
|
||||
) {
|
||||
) -> bool {
|
||||
let mut invalid_compile_fail_format = false;
|
||||
let mut found_error_code = false;
|
||||
|
||||
for line in f.lines() {
|
||||
let s = line.trim();
|
||||
if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') {
|
||||
error_codes.insert(err_code, true);
|
||||
return;
|
||||
if s.starts_with("```") {
|
||||
if s.contains("compile_fail") && s.contains('E') {
|
||||
if !found_error_code {
|
||||
error_codes.insert(err_code.clone(), true);
|
||||
found_error_code = true;
|
||||
}
|
||||
} else if s.contains("compile-fail") {
|
||||
invalid_compile_fail_format = true;
|
||||
}
|
||||
} else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
|
||||
error_codes.get_mut(&err_code).map(|x| *x = true);
|
||||
return;
|
||||
if !found_error_code {
|
||||
error_codes.get_mut(&err_code).map(|x| *x = true);
|
||||
found_error_code = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
invalid_compile_fail_format
|
||||
}
|
||||
|
||||
fn check_if_error_code_is_test_in_explanation(f: &str, err_code: &String) -> bool {
|
||||
let mut can_be_ignored = false;
|
||||
|
||||
for line in f.lines() {
|
||||
let s = line.trim();
|
||||
if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
|
||||
return true;
|
||||
}
|
||||
if s.starts_with("```") {
|
||||
if s.contains("compile_fail") && s.contains(err_code) {
|
||||
return true;
|
||||
} else if s.contains("(") {
|
||||
// It's very likely that we can't actually make it fail compilation...
|
||||
can_be_ignored = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
can_be_ignored
|
||||
}
|
||||
|
||||
macro_rules! some_or_continue {
|
||||
|
|
@ -41,7 +77,12 @@ macro_rules! some_or_continue {
|
|||
};
|
||||
}
|
||||
|
||||
fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &Path) {
|
||||
fn extract_error_codes(
|
||||
f: &str,
|
||||
error_codes: &mut HashMap<String, bool>,
|
||||
path: &Path,
|
||||
errors: &mut Vec<String>,
|
||||
) {
|
||||
let mut reached_no_explanation = false;
|
||||
|
||||
for line in f.lines() {
|
||||
|
|
@ -55,10 +96,26 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &
|
|||
// Now we extract the tests from the markdown file!
|
||||
let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1));
|
||||
let md_file_name = some_or_continue!(md.splitn(2, "\")").next());
|
||||
let path = some_or_continue!(path.parent()).join(md_file_name);
|
||||
let path = some_or_continue!(path.parent())
|
||||
.join(md_file_name)
|
||||
.canonicalize()
|
||||
.expect("failed to canonicalize error explanation file path");
|
||||
match read_to_string(&path) {
|
||||
Ok(content) => {
|
||||
check_error_code_explanation(&content, error_codes, err_code);
|
||||
if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str())
|
||||
&& !check_if_error_code_is_test_in_explanation(&content, &err_code)
|
||||
{
|
||||
errors.push(format!(
|
||||
"`{}` doesn't use its own error code in compile_fail example",
|
||||
path.display(),
|
||||
));
|
||||
}
|
||||
if check_error_code_explanation(&content, error_codes, err_code) {
|
||||
errors.push(format!(
|
||||
"`{}` uses invalid tag `compile-fail` instead of `compile_fail`",
|
||||
path.display(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Couldn't read `{}`: {}", path.display(), e);
|
||||
|
|
@ -94,22 +151,24 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, boo
|
|||
}
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
let mut errors = Vec::new();
|
||||
println!("Checking which error codes lack tests...");
|
||||
let mut error_codes: HashMap<String, bool> = HashMap::new();
|
||||
super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
|
||||
let file_name = entry.file_name();
|
||||
if file_name == "error_codes.rs" {
|
||||
extract_error_codes(contents, &mut error_codes, entry.path());
|
||||
extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
|
||||
} else if entry.path().extension() == Some(OsStr::new("stderr")) {
|
||||
extract_error_codes_from_tests(contents, &mut error_codes);
|
||||
}
|
||||
});
|
||||
println!("Found {} error codes", error_codes.len());
|
||||
if errors.is_empty() {
|
||||
println!("Found {} error codes", error_codes.len());
|
||||
|
||||
let mut errors = Vec::new();
|
||||
for (err_code, nb) in &error_codes {
|
||||
if !*nb && !WHITELIST.contains(&err_code.as_str()) {
|
||||
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
|
||||
for (err_code, nb) in &error_codes {
|
||||
if !*nb && !WHITELIST.contains(&err_code.as_str()) {
|
||||
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
|
||||
}
|
||||
}
|
||||
}
|
||||
errors.sort();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue