Auto merge of #65454 - tmandry:rollup-0k6jiik, r=tmandry

Rollup of 14 pull requests

Successful merges:

 - #64603 (Reducing spurious unused lifetime warnings.)
 - #64623 (Remove last uses of gensyms)
 - #65235 (don't assume we can *always* find a return type hint in async fn)
 - #65242 (Fix suggestion to constrain trait for method to be found)
 - #65265 (Cleanup librustc mir err codes)
 - #65293 (Optimize `try_expand_impl_trait_type`)
 - #65307 (Try fix incorrect "explicit lifetime name needed")
 - #65308 (Add long error explanation for E0574)
 - #65353 (save-analysis: Don't ICE when resolving qualified type paths in struct members)
 - #65389 (Return `false` from `needs_drop` for all zero-sized arrays.)
 - #65402 (Add troubleshooting section to PGO chapter in rustc book.)
 - #65425 (Optimize `BitIter`)
 - #65438 (Organize `never_type`  tests)
 - #65444 (Implement AsRef<[T]> for List<T>)

Failed merges:

 - #65390 (Add long error explanation for E0576)

r? @ghost
This commit is contained in:
bors 2019-10-15 23:09:33 +00:00
commit f54911c6f2
99 changed files with 1096 additions and 508 deletions

View File

@ -125,6 +125,17 @@ RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \
cargo build --release --target=x86_64-unknown-linux-gnu
```
### Troubleshooting
- It is recommended to pass `-Cllvm-args=-pgo-warn-missing-function` during the
`-Cprofile-use` phase. LLVM by default does not warn if it cannot find
profiling data for a given function. Enabling this warning will make it
easier to spot errors in your setup.
- There is a [known issue](https://github.com/rust-lang/cargo/issues/7416) in
Cargo prior to version 1.39 that will prevent PGO from working correctly. Be
sure to use Cargo 1.39 or newer when doing PGO.
## Further Reading
`rustc`'s PGO support relies entirely on LLVM's implementation of the feature

View File

@ -3291,10 +3291,14 @@ impl<'a> LoweringContext<'a> {
let id = self.sess.next_node_id();
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
}
// This is the normal case.
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
// `PassThrough` is the normal case.
// `new_error_lifetime`, which would usually be used in the case of `ReportError`,
// is unsuitable here, as these can occur from missing lifetime parameters in a
// `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
// later, at which point a suitable error will be emitted.
| AnonymousLifetimeMode::PassThrough
| AnonymousLifetimeMode::ReportError => self.new_implicit_lifetime(span),
}
}

View File

@ -708,15 +708,22 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (name, reg) = Region::early(&self.tcx.hir(), &mut index, &param);
let def_id = if let Region::EarlyBound(_ ,def_id , _) = reg {
def_id
} else {
bug!();
};
if let hir::ParamName::Plain(param_name) = name {
if param_name.name == kw::UnderscoreLifetime {
// Pick the elided lifetime "definition" if one exists
// and use it to make an elision scope.
self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many);
elision = Some(reg);
} else {
lifetimes.insert(name, reg);
}
} else {
self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many);
lifetimes.insert(name, reg);
}
}
@ -1615,7 +1622,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
_ => None,
} {
debug!("id = {:?} span = {:?} name = {:?}", id, span, name);
if name.name == kw::UnderscoreLifetime {
continue;
}

View File

@ -701,6 +701,13 @@ impl<T> Deref for List<T> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &[T] {
self.as_ref()
}
}
impl<T> AsRef<[T]> for List<T> {
#[inline(always)]
fn as_ref(&self) -> &[T] {
unsafe {
slice::from_raw_parts(self.data.as_ptr(), self.len)
}

View File

@ -1483,7 +1483,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
}
// Replace any anonymous late-bound regions with named
// variants, using gensym'd identifiers, so that we can
// variants, using new unique identifiers, so that we can
// clearly differentiate between named and unnamed regions in
// the output. We'll probably want to tweak this over time to
// decide just how much information to give.

View File

@ -697,6 +697,9 @@ impl<'tcx> TyCtxt<'tcx> {
// that type, and when we finish expanding that type we remove the
// its DefId.
seen_opaque_tys: FxHashSet<DefId>,
// Cache of all expansions we've seen so far. This is a critical
// optimization for some large types produced by async fn trees.
expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
primary_def_id: DefId,
found_recursion: bool,
tcx: TyCtxt<'tcx>,
@ -713,9 +716,16 @@ impl<'tcx> TyCtxt<'tcx> {
}
let substs = substs.fold_with(self);
if self.seen_opaque_tys.insert(def_id) {
let generic_ty = self.tcx.type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx, substs);
let expanded_ty = self.fold_ty(concrete_ty);
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
Some(expanded_ty) => expanded_ty,
None => {
let generic_ty = self.tcx.type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx, substs);
let expanded_ty = self.fold_ty(concrete_ty);
self.expanded_cache.insert((def_id, substs), expanded_ty);
expanded_ty
}
};
self.seen_opaque_tys.remove(&def_id);
Some(expanded_ty)
} else {
@ -735,14 +745,17 @@ impl<'tcx> TyCtxt<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Opaque(def_id, substs) = t.kind {
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
} else {
} else if t.has_projections() {
t.super_fold_with(self)
} else {
t
}
}
}
let mut visitor = OpaqueTypeExpander {
seen_opaque_tys: FxHashSet::default(),
expanded_cache: FxHashMap::default(),
primary_def_id: def_id,
found_recursion: false,
tcx: self,
@ -1096,6 +1109,9 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
// Zero-length arrays never contain anything to drop.
ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
// Structural recursion.
ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),

View File

@ -168,11 +168,7 @@ impl<T: Idx> BitSet<T> {
/// Iterates over the indices of set bits in a sorted order.
#[inline]
pub fn iter(&self) -> BitIter<'_, T> {
BitIter {
cur: None,
iter: self.words.iter().enumerate(),
marker: PhantomData,
}
BitIter::new(&self.words)
}
/// Duplicates the set as a hybrid set.
@ -291,26 +287,55 @@ impl<T: Idx> ToString for BitSet<T> {
}
pub struct BitIter<'a, T: Idx> {
cur: Option<(Word, usize)>,
iter: iter::Enumerate<slice::Iter<'a, Word>>,
/// A copy of the current word, but with any already-visited bits cleared.
/// (This lets us use `trailing_zeros()` to find the next set bit.) When it
/// is reduced to 0, we move onto the next word.
word: Word,
/// The offset (measured in bits) of the current word.
offset: usize,
/// Underlying iterator over the words.
iter: slice::Iter<'a, Word>,
marker: PhantomData<T>
}
impl<'a, T: Idx> BitIter<'a, T> {
#[inline]
fn new(words: &'a [Word]) -> BitIter<'a, T> {
// We initialize `word` and `offset` to degenerate values. On the first
// call to `next()` we will fall through to getting the first word from
// `iter`, which sets `word` to the first word (if there is one) and
// `offset` to 0. Doing it this way saves us from having to maintain
// additional state about whether we have started.
BitIter {
word: 0,
offset: std::usize::MAX - (WORD_BITS - 1),
iter: words.iter(),
marker: PhantomData,
}
}
}
impl<'a, T: Idx> Iterator for BitIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
loop {
if let Some((ref mut word, offset)) = self.cur {
let bit_pos = word.trailing_zeros() as usize;
if bit_pos != WORD_BITS {
let bit = 1 << bit_pos;
*word ^= bit;
return Some(T::new(bit_pos + offset))
}
if self.word != 0 {
// Get the position of the next set bit in the current word,
// then clear the bit.
let bit_pos = self.word.trailing_zeros() as usize;
let bit = 1 << bit_pos;
self.word ^= bit;
return Some(T::new(bit_pos + self.offset))
}
let (i, word) = self.iter.next()?;
self.cur = Some((*word, WORD_BITS * i));
// Move onto the next word. `wrapping_add()` is needed to handle
// the degenerate initial value given to `offset` in `new()`.
let word = self.iter.next()?;
self.word = *word;
self.offset = self.offset.wrapping_add(WORD_BITS);
}
}
}
@ -851,11 +876,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
pub fn iter(&self, row: R) -> BitIter<'_, C> {
assert!(row.index() < self.num_rows);
let (start, end) = self.range(row);
BitIter {
cur: None,
iter: self.words[start..end].iter().enumerate(),
marker: PhantomData,
}
BitIter::new(&self.words[start..end])
}
/// Returns the number of elements in `row`.

View File

@ -104,25 +104,16 @@ impl<'tcx> TransferFunction<'_, '_, 'tcx> {
kind: mir::BorrowKind,
borrowed_place: &mir::Place<'tcx>,
) -> bool {
let borrowed_ty = borrowed_place.ty(self.body, self.tcx).ty;
// Zero-sized types cannot be mutated, since there is nothing inside to mutate.
//
// FIXME: For now, we only exempt arrays of length zero. We need to carefully
// consider the effects before extending this to all ZSTs.
if let ty::Array(_, len) = borrowed_ty.kind {
if len.try_eval_usize(self.tcx, self.param_env) == Some(0) {
return false;
}
}
match kind {
mir::BorrowKind::Mut { .. } => true,
| mir::BorrowKind::Shared
| mir::BorrowKind::Shallow
| mir::BorrowKind::Unique
=> !borrowed_ty.is_freeze(self.tcx, self.param_env, DUMMY_SP),
=> !borrowed_place
.ty(self.body, self.tcx)
.ty
.is_freeze(self.tcx, self.param_env, DUMMY_SP),
}
}
}

View File

@ -64,7 +64,9 @@ E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution. Erroneous code example:
determine the flow of execution.
Erroneous code example:
```compile_fail,E0004
enum Terminator {
@ -109,7 +111,9 @@ match x {
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee
that a name will be extracted in all cases. Erroneous code example:
that a name will be extracted in all cases.
Erroneous code example:
```compile_fail,E0005
let x = Some(1);
@ -145,6 +149,8 @@ like the following is invalid as it requires the entire `Option<String>` to be
moved into a variable called `op_string` while simultaneously requiring the
inner `String` to be moved into a variable called `s`.
Erroneous code example:
```compile_fail,E0007
let x = Some("s".to_string());
@ -208,15 +214,130 @@ match x {
```
"##,
E0010: r##"
The value of statics and constants must be known at compile time, and they live
for the entire lifetime of a program. Creating a boxed value allocates memory on
the heap at runtime, and therefore cannot be done at compile time.
Erroneous code example:
```compile_fail,E0010
#![feature(box_syntax)]
const CON : Box<i32> = box 0;
```
"##,
E0013: r##"
Static and const variables can refer to other const variables. But a const
variable cannot refer to a static variable.
Erroneous code example:
```compile_fail,E0013
static X: i32 = 42;
const Y: i32 = X;
```
In this example, `Y` cannot refer to `X` here. To fix this, the value can be
extracted as a const and then used:
```
const A: i32 = 42;
static X: i32 = A;
const Y: i32 = A;
```
"##,
// FIXME(#57563) Change the language here when const fn stabilizes
E0015: r##"
The only functions that can be called in static or constant expressions are
`const` functions, and struct/enum constructors. `const` functions are only
available on a nightly compiler. Rust currently does not support more general
compile-time function execution.
```
const FOO: Option<u8> = Some(1); // enum constructor
struct Bar {x: u8}
const BAR: Bar = Bar {x: 1}; // struct constructor
```
See [RFC 911] for more details on the design of `const fn`s.
[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
"##,
E0017: r##"
References in statics and constants may only refer to immutable values.
Erroneous code example:
```compile_fail,E0017
static X: i32 = 1;
const C: i32 = 2;
// these three are not allowed:
const CR: &mut i32 = &mut C;
static STATIC_REF: &'static mut i32 = &mut X;
static CONST_REF: &'static mut i32 = &mut C;
```
Statics are shared everywhere, and if they refer to mutable data one might
violate memory safety since holding multiple mutable references to shared data
is not allowed.
If you really want global mutable state, try using `static mut` or a global
`UnsafeCell`.
"##,
E0019: r##"
A function call isn't allowed in the const's initialization expression
because the expression's value must be known at compile-time.
Erroneous code example:
```compile_fail,E0019
#![feature(box_syntax)]
fn main() {
struct MyOwned;
static STATIC11: Box<MyOwned> = box MyOwned; // error!
}
```
Remember: you can't use a function call inside a const's initialization
expression! However, you can totally use it anywhere else:
```
enum Test {
V1
}
impl Test {
fn func(&self) -> i32 {
12
}
}
fn main() {
const FOO: Test = Test::V1;
FOO.func(); // here is good
let x = FOO.func(); // or even here!
}
```
"##,
E0030: r##"
When matching against a range, the compiler verifies that the range is
non-empty. Range patterns include both end-points, so this is equivalent to
non-empty. Range patterns include both end-points, so this is equivalent to
requiring the start of the range to be less than or equal to the end of the
range.
For example:
Erroneous code example:
```compile_fail
```compile_fail,E0030
match 5u32 {
// This range is ok, albeit pointless.
1 ..= 1 => {}
@ -226,7 +347,61 @@ match 5u32 {
```
"##,
E0133: r##"
Unsafe code was used outside of an unsafe function or block.
Erroneous code example:
```compile_fail,E0133
unsafe fn f() { return; } // This is the unsafe code
fn main() {
f(); // error: call to unsafe function requires unsafe function or block
}
```
Using unsafe functionality is potentially dangerous and disallowed by safety
checks. Examples:
* Dereferencing raw pointers
* Calling functions via FFI
* Calling functions marked unsafe
These safety checks can be relaxed for a section of the code by wrapping the
unsafe instructions with an `unsafe` block. For instance:
```
unsafe fn f() { return; }
fn main() {
unsafe { f(); } // ok!
}
```
See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
"##,
E0158: r##"
An associated const has been referenced in a pattern.
Erroneous code example:
```compile_fail,E0158
enum EFoo { A, B, C, D }
trait Foo {
const X: EFoo;
}
fn test<A: Foo>(arg: EFoo) {
match arg {
A::X => { // error!
println!("A::X");
}
}
}
```
`const` and `static` mean different things. A `const` is a compile-time
constant, an alias for a literal value. This property means you can match it
directly within a pattern.
@ -247,6 +422,39 @@ match Some(42) {
```
"##,
E0161: r##"
A value was moved. However, its size was not known at compile time, and only
values of a known size can be moved.
Erroneous code example:
```compile_fail,E0161
#![feature(box_syntax)]
fn main() {
let array: &[isize] = &[1, 2, 3];
let _x: Box<[isize]> = box *array;
// error: cannot move a value of type [isize]: the size of [isize] cannot
// be statically determined
}
```
In Rust, you can only move a value when its size is known at compile time.
To work around this restriction, consider "hiding" the value behind a reference:
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
it around as usual. Example:
```
#![feature(box_syntax)]
fn main() {
let array: &[isize] = &[1, 2, 3];
let _x: Box<&[isize]> = box array; // ok!
}
```
"##,
E0162: r##"
#### Note: this error code is no longer emitted by the compiler.
@ -468,158 +676,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
See also https://github.com/rust-lang/rust/issues/14587
"##,
E0010: r##"
The value of statics and constants must be known at compile time, and they live
for the entire lifetime of a program. Creating a boxed value allocates memory on
the heap at runtime, and therefore cannot be done at compile time. Erroneous
code example:
```compile_fail,E0010
#![feature(box_syntax)]
const CON : Box<i32> = box 0;
```
"##,
E0013: r##"
Static and const variables can refer to other const variables. But a const
variable cannot refer to a static variable. For example, `Y` cannot refer to
`X` here:
```compile_fail,E0013
static X: i32 = 42;
const Y: i32 = X;
```
To fix this, the value can be extracted as a const and then used:
```
const A: i32 = 42;
static X: i32 = A;
const Y: i32 = A;
```
"##,
// FIXME(#57563) Change the language here when const fn stabilizes
E0015: r##"
The only functions that can be called in static or constant expressions are
`const` functions, and struct/enum constructors. `const` functions are only
available on a nightly compiler. Rust currently does not support more general
compile-time function execution.
```
const FOO: Option<u8> = Some(1); // enum constructor
struct Bar {x: u8}
const BAR: Bar = Bar {x: 1}; // struct constructor
```
See [RFC 911] for more details on the design of `const fn`s.
[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
"##,
E0017: r##"
References in statics and constants may only refer to immutable values.
Erroneous code example:
```compile_fail,E0017
static X: i32 = 1;
const C: i32 = 2;
// these three are not allowed:
const CR: &mut i32 = &mut C;
static STATIC_REF: &'static mut i32 = &mut X;
static CONST_REF: &'static mut i32 = &mut C;
```
Statics are shared everywhere, and if they refer to mutable data one might
violate memory safety since holding multiple mutable references to shared data
is not allowed.
If you really want global mutable state, try using `static mut` or a global
`UnsafeCell`.
"##,
E0019: r##"
A function call isn't allowed in the const's initialization expression
because the expression's value must be known at compile-time. Erroneous code
example:
```compile_fail
enum Test {
V1
}
impl Test {
fn test(&self) -> i32 {
12
}
}
fn main() {
const FOO: Test = Test::V1;
const A: i32 = FOO.test(); // You can't call Test::func() here!
}
```
Remember: you can't use a function call inside a const's initialization
expression! However, you can totally use it anywhere else:
```
enum Test {
V1
}
impl Test {
fn func(&self) -> i32 {
12
}
}
fn main() {
const FOO: Test = Test::V1;
FOO.func(); // here is good
let x = FOO.func(); // or even here!
}
```
"##,
E0133: r##"
Unsafe code was used outside of an unsafe function or block.
Erroneous code example:
```compile_fail,E0133
unsafe fn f() { return; } // This is the unsafe code
fn main() {
f(); // error: call to unsafe function requires unsafe function or block
}
```
Using unsafe functionality is potentially dangerous and disallowed by safety
checks. Examples:
* Dereferencing raw pointers
* Calling functions via FFI
* Calling functions marked unsafe
These safety checks can be relaxed for a section of the code by wrapping the
unsafe instructions with an `unsafe` block. For instance:
```
unsafe fn f() { return; }
fn main() {
unsafe { f(); } // ok!
}
```
See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
"##,
E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
@ -672,7 +728,9 @@ about safety.
"##,
E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:
It is not allowed to use or capture an uninitialized variable.
Erroneous code example:
```compile_fail,E0381
fn main() {
@ -694,7 +752,9 @@ fn main() {
E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:
have been moved elsewhere.
Erroneous code example:
```compile_fail,E0382
struct MyStruct { s: u32 }
@ -842,7 +902,8 @@ x = Foo { a: 2 };
E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:
Erroneous code example:
```compile_fail,E0384
fn main() {
@ -862,13 +923,15 @@ fn main() {
```
"##,
/*E0386: r##"
E0386: r##"
#### Note: this error code is no longer emitted by the compiler.
This error occurs when an attempt is made to mutate the target of a mutable
reference stored inside an immutable container.
For example, this can happen when storing a `&mut` inside an immutable `Box`:
```compile_fail,E0386
```
let mut x: i64 = 1;
let y: Box<_> = Box::new(&mut x);
**y = 2; // error, cannot assign to data in an immutable container
@ -892,13 +955,15 @@ let x: i64 = 1;
let y: Box<Cell<_>> = Box::new(Cell::new(x));
y.set(2);
```
"##,*/
"##,
E0387: r##"
#### Note: this error code is no longer emitted by the compiler.
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:
that a closure has captured immutably.
Erroneous code example:
```compile_fail
// Accepts a function or a closure that captures its environment immutably.
@ -963,7 +1028,7 @@ An attempt was made to mutate data using a non-mutable reference. This
commonly occurs when attempting to assign to a non-mutable reference of a
mutable reference (`&(&mut T)`).
Example of erroneous code:
Erroneous code example:
```compile_fail
struct FancyNum {
@ -1022,43 +1087,11 @@ fn main() {
```
"##,
E0161: r##"
A value was moved. However, its size was not known at compile time, and only
values of a known size can be moved.
E0492: r##"
A borrow of a constant containing interior mutability was attempted.
Erroneous code example:
```compile_fail
#![feature(box_syntax)]
fn main() {
let array: &[isize] = &[1, 2, 3];
let _x: Box<[isize]> = box *array;
// error: cannot move a value of type [isize]: the size of [isize] cannot
// be statically determined
}
```
In Rust, you can only move a value when its size is known at compile time.
To work around this restriction, consider "hiding" the value behind a reference:
either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
it around as usual. Example:
```
#![feature(box_syntax)]
fn main() {
let array: &[isize] = &[1, 2, 3];
let _x: Box<&[isize]> = box array; // ok!
}
```
"##,
E0492: r##"
A borrow of a constant containing interior mutability was attempted. Erroneous
code example:
```compile_fail,E0492
use std::sync::atomic::AtomicUsize;
@ -1174,7 +1207,9 @@ static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields
"##,
E0499: r##"
A variable was borrowed as mutable more than once. Erroneous code example:
A variable was borrowed as mutable more than once.
Erroneous code example:
```compile_fail,E0499
let mut i = 0;
@ -1205,7 +1240,9 @@ a;
"##,
E0500: r##"
A borrowed variable was used by a closure. Example of erroneous code:
A borrowed variable was used by a closure.
Erroneous code example:
```compile_fail,E0500
fn you_know_nothing(jon_snow: &mut i32) {
@ -1256,7 +1293,7 @@ situation, the closure is borrowing the variable. Take a look at
http://rustbyexample.com/fn/closures/capture.html for more information about
capturing.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0501
fn inside_closure(x: &mut i32) {
@ -1329,7 +1366,7 @@ E0502: r##"
This error indicates that you are trying to borrow a variable as mutable when it
has already been borrowed as immutable.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0502
fn bar(x: &mut i32) {}
@ -1360,7 +1397,7 @@ https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html.
E0503: r##"
A value was used after it was mutably borrowed.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0503
fn main() {
@ -1418,7 +1455,7 @@ E0504: r##"
This error occurs when an attempt is made to move a borrowed variable into a
closure.
Example of erroneous code:
Erroneous code example:
```compile_fail
struct FancyNum {
@ -1609,7 +1646,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
E0506: r##"
This error occurs when an attempt is made to assign to a borrowed value.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0506
struct FancyNum {
@ -1827,7 +1864,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
E0508: r##"
A value was moved out of a non-copy fixed-size array.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0508
struct NonCopy;
@ -1872,7 +1909,7 @@ E0509: r##"
This error occurs when an attempt is made to move out of a value whose type
implements the `Drop` trait.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0509
struct FancyNum {
@ -1982,30 +2019,14 @@ Here executing `x = None` would modify the value being matched and require us
to go "back in time" to the `None` arm.
"##,
E0579: r##"
When matching against an exclusive range, the compiler verifies that the range
is non-empty. Exclusive range patterns include the start point but not the end
point, so this is equivalent to requiring the start of the range to be less
than the end of the range.
For example:
```compile_fail
match 5u32 {
// This range is ok, albeit pointless.
1 .. 2 => {}
// This range is empty, and the compiler can tell.
5 .. 5 => {}
}
```
"##,
E0515: r##"
Cannot return value that references local variable
Local variables, function parameters and temporaries are all dropped before the
end of the function body. So a reference to them cannot be returned.
Erroneous code example:
```compile_fail,E0515
fn get_dangling_reference() -> &'static i32 {
let x = 0;
@ -2101,6 +2122,28 @@ fn dragoooon(x: &mut isize) {
```
"##,
E0579: r##"
When matching against an exclusive range, the compiler verifies that the range
is non-empty. Exclusive range patterns include the start point but not the end
point, so this is equivalent to requiring the start of the range to be less
than the end of the range.
Erroneous code example:
```compile_fail,E0579
#![feature(exclusive_range_pattern)]
fn main() {
match 5u32 {
// This range is ok, albeit pointless.
1 .. 2 => {}
// This range is empty, and the compiler can tell.
5 .. 5 => {} // error!
}
}
```
"##,
E0595: r##"
#### Note: this error code is no longer emitted by the compiler.
@ -2124,7 +2167,7 @@ let mut c = || { x += 1 };
E0596: r##"
This error occurs because you tried to mutably borrow a non-mutable variable.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0596
let x = 1;
@ -2143,7 +2186,7 @@ let y = &mut x; // ok!
E0597: r##"
This error occurs because a value was dropped while it was still borrowed
Example of erroneous code:
Erroneous code example:
```compile_fail,E0597
struct Foo<'a> {
@ -2180,6 +2223,8 @@ E0626: r##"
This error occurs because a borrow in a generator persists across a
yield point.
Erroneous code example:
```compile_fail,E0626
# #![feature(generators, generator_trait, pin)]
# use std::ops::Generator;
@ -2271,7 +2316,7 @@ E0712: r##"
This error occurs because a borrow of a thread-local variable was made inside a
function which outlived the lifetime of the function.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0712
#![feature(thread_local)]
@ -2293,7 +2338,7 @@ E0713: r##"
This error occurs when an attempt is made to borrow state past the end of the
lifetime of a type that implements the `Drop` trait.
Example of erroneous code:
Erroneous code example:
```compile_fail,E0713
#![feature(nll)]

View File

@ -94,7 +94,8 @@ impl<'a> Resolver<'a> {
where T: ToNameBinding<'a>,
{
let binding = def.to_name_binding(self.arenas);
if let Err(old_binding) = self.try_define(parent, ident, ns, binding) {
let key = self.new_key(ident, ns);
if let Err(old_binding) = self.try_define(parent, key, binding) {
self.report_conflict(parent, ident, ns, old_binding, &binding);
}
}
@ -349,9 +350,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
self.r.indeterminate_imports.push(directive);
match directive.subclass {
// Don't add unresolved underscore imports to modules
SingleImport { target: Ident { name: kw::Underscore, .. }, .. } => {}
SingleImport { target, type_ns_only, .. } => {
self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
let key = this.new_key(target, ns);
let mut resolution = this.resolution(current_module, key).borrow_mut();
resolution.add_single_import(directive);
});
}
@ -407,7 +411,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
};
match use_tree.kind {
ast::UseTreeKind::Simple(rename, ..) => {
let mut ident = use_tree.ident().gensym_if_underscore();
let mut ident = use_tree.ident();
let mut module_path = prefix;
let mut source = module_path.pop().unwrap();
let mut type_ns_only = false;
@ -585,7 +589,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let parent_scope = &self.parent_scope;
let parent = parent_scope.module;
let expansion = parent_scope.expansion;
let ident = item.ident.gensym_if_underscore();
let ident = item.ident;
let sp = item.span;
let vis = self.resolve_visibility(&item.vis);
@ -851,10 +855,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
let parent = self.parent_scope.module;
let Export { ident, res, vis, span } = child;
// FIXME: We shouldn't create the gensym here, it should come from metadata,
// but metadata cannot encode gensyms currently, so we create it here.
// This is only a guess, two equivalent idents may incorrectly get different gensyms here.
let ident = ident.gensym_if_underscore();
let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene
// Record primary definitions.
match res {

View File

@ -80,11 +80,11 @@ impl<'a> Resolver<'a> {
names: &mut Vec<TypoSuggestion>,
filter_fn: &impl Fn(Res) -> bool,
) {
for (&(ident, _), resolution) in self.resolutions(module).borrow().iter() {
for (key, resolution) in self.resolutions(module).borrow().iter() {
if let Some(binding) = resolution.borrow().binding {
let res = binding.res();
if filter_fn(res) {
names.push(TypoSuggestion::from_res(ident.name, res));
names.push(TypoSuggestion::from_res(key.ident.name, res));
}
}
}
@ -849,7 +849,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
let resolutions = self.r.resolutions(crate_module).borrow();
let resolution = resolutions.get(&(ident, MacroNS))?;
let resolution = resolutions.get(&self.r.new_key(ident, MacroNS))?;
let binding = resolution.borrow().binding()?;
if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
let module_name = crate_module.kind.name().unwrap();

View File

@ -1611,6 +1611,56 @@ fn print_on_failure(state: &State) {
```
"##,
E0574: r##"
Something other than a struct, variant or union has been used when one was
expected.
Erroneous code example:
```compile_fail,E0574
mod Mordor {}
let sauron = Mordor { x: () }; // error!
enum Jak {
Daxter { i: isize },
}
let eco = Jak::Daxter { i: 1 };
match eco {
Jak { i } => {} // error!
}
```
In all these errors, a type was expected. For example, in the first error,
we tried to instantiate the `Mordor` module, which is impossible. If you want
to instantiate a type inside a module, you can do it as follow:
```
mod Mordor {
pub struct TheRing {
pub x: usize,
}
}
let sauron = Mordor::TheRing { x: 1 }; // ok!
```
In the second error, we tried to bind the `Jak` enum directly, which is not
possible: you can only bind one of its variants. To do so:
```
enum Jak {
Daxter { i: isize },
}
let eco = Jak::Daxter { i: 1 };
match eco {
Jak::Daxter { i } => {} // ok!
}
```
"##,
E0603: r##"
A private item was used outside its scope.
@ -1739,7 +1789,6 @@ struct Foo<X = Box<Self>> {
// E0467, removed
// E0470, removed
E0573,
E0574,
E0575,
E0576,
E0577,

View File

@ -432,7 +432,22 @@ impl ModuleKind {
}
}
type Resolutions<'a> = RefCell<FxIndexMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>;
/// A key that identifies a binding in a given `Module`.
///
/// Multiple bindings in the same module can have the same key (in a valid
/// program) if all but one of them come from glob imports.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct BindingKey {
/// The identifier for the binding, aways the `modern` version of the
/// identifier.
ident: Ident,
ns: Namespace,
/// 0 if ident is not `_`, otherwise a value that's unique to the specific
/// `_` in the expanded AST that introduced this binding.
disambiguator: u32,
}
type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>;
/// One node in the tree of modules.
pub struct ModuleData<'a> {
@ -492,8 +507,8 @@ impl<'a> ModuleData<'a> {
fn for_each_child<R, F>(&'a self, resolver: &mut R, mut f: F)
where R: AsMut<Resolver<'a>>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>)
{
for (&(ident, ns), name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding));
}
}
@ -882,6 +897,7 @@ pub struct Resolver<'a> {
module_map: FxHashMap<DefId, Module<'a>>,
extern_module_map: FxHashMap<DefId, Module<'a>>,
binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
underscore_disambiguator: u32,
/// Maps glob imports to the names of items actually imported.
pub glob_map: GlobMap,
@ -1160,6 +1176,7 @@ impl<'a> Resolver<'a> {
extern_crate_map: Default::default(),
export_map: FxHashMap::default(),
trait_map: Default::default(),
underscore_disambiguator: 0,
empty_module,
module_map,
block_map: Default::default(),
@ -1284,6 +1301,17 @@ impl<'a> Resolver<'a> {
self.arenas.alloc_module(module)
}
fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey {
let ident = ident.modern();
let disambiguator = if ident.name == kw::Underscore {
self.underscore_disambiguator += 1;
self.underscore_disambiguator
} else {
0
};
BindingKey { ident, ns, disambiguator }
}
fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> {
if module.populate_on_access.get() {
module.populate_on_access.set(false);
@ -1292,9 +1320,9 @@ impl<'a> Resolver<'a> {
&module.lazy_resolutions
}
fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace)
fn resolution(&mut self, module: Module<'a>, key: BindingKey)
-> &'a RefCell<NameResolution<'a>> {
*self.resolutions(module).borrow_mut().entry((ident.modern(), ns))
*self.resolutions(module).borrow_mut().entry(key)
.or_insert_with(|| self.arenas.alloc_name_resolution())
}

View File

@ -7,7 +7,7 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope
use crate::Determinacy::{self, *};
use crate::Namespace::{self, TypeNS, MacroNS};
use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
use crate::{Resolver, ResolutionError, Segment, ModuleKind};
use crate::{Resolver, ResolutionError, BindingKey, Segment, ModuleKind};
use crate::{names_to_string, module_to_string};
use crate::diagnostics::Suggestion;
@ -235,7 +235,8 @@ impl<'a> Resolver<'a> {
}
};
let resolution = self.resolution(module, ident, ns)
let key = self.new_key(ident, ns);
let resolution = self.resolution(module, key)
.try_borrow_mut()
.map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
@ -447,17 +448,16 @@ impl<'a> Resolver<'a> {
}
// Define the name or return the existing binding if there is a collision.
pub fn try_define(
crate fn try_define(
&mut self,
module: Module<'a>,
ident: Ident,
ns: Namespace,
key: BindingKey,
binding: &'a NameBinding<'a>,
) -> Result<(), &'a NameBinding<'a>> {
let res = binding.res();
self.check_reserved_macro_name(ident, res);
self.check_reserved_macro_name(key.ident, res);
self.set_binding_parent_module(binding, module);
self.update_resolution(module, ident, ns, |this, resolution| {
self.update_resolution(module, key, |this, resolution| {
if let Some(old_binding) = resolution.binding {
if res == Res::Err {
// Do not override real bindings with `Res::Err`s from error recovery.
@ -479,8 +479,9 @@ impl<'a> Resolver<'a> {
} else {
(binding, old_binding)
};
if glob_binding.res() != nonglob_binding.res() &&
ns == MacroNS && nonglob_binding.expansion != ExpnId::root() {
if glob_binding.res() != nonglob_binding.res()
&& key.ns == MacroNS && nonglob_binding.expansion != ExpnId::root()
{
resolution.binding = Some(this.ambiguity(
AmbiguityKind::GlobVsExpanded,
nonglob_binding,
@ -499,9 +500,9 @@ impl<'a> Resolver<'a> {
DUPLICATE_MACRO_EXPORTS,
CRATE_NODE_ID,
binding.span,
&format!("a macro named `{}` has already been exported", ident),
&format!("a macro named `{}` has already been exported", key.ident),
BuiltinLintDiagnostics::DuplicatedMacroExports(
ident, old_binding.span, binding.span));
key.ident, old_binding.span, binding.span));
resolution.binding = Some(binding);
} else {
@ -531,9 +532,9 @@ impl<'a> Resolver<'a> {
// Use `f` to mutate the resolution of the name in the module.
// If the resolution becomes a success, define it in the module's glob importers.
fn update_resolution<T, F>(
&mut self, module: Module<'a>,
ident: Ident,
ns: Namespace,
&mut self,
module: Module<'a>,
key: BindingKey,
f: F,
) -> T
where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
@ -541,7 +542,7 @@ impl<'a> Resolver<'a> {
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
let (binding, t) = {
let resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
let resolution = &mut *self.resolution(module, key).borrow_mut();
let old_binding = resolution.binding();
let t = f(self, resolution);
@ -558,7 +559,7 @@ impl<'a> Resolver<'a> {
// Define `binding` in `module`s glob importers.
for directive in module.glob_importers.borrow_mut().iter() {
let mut ident = ident.modern();
let mut ident = key.ident;
let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
Some(Some(def)) => self.macro_def_scope(def),
Some(None) => directive.parent_scope.module,
@ -566,7 +567,8 @@ impl<'a> Resolver<'a> {
};
if self.is_accessible_from(binding.vis, scope) {
let imported_binding = self.import(binding, directive);
let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding);
let key = BindingKey { ident, ..key };
let _ = self.try_define(directive.parent_scope.module, key, imported_binding);
}
}
@ -580,7 +582,8 @@ impl<'a> Resolver<'a> {
let dummy_binding = self.dummy_binding;
let dummy_binding = self.import(dummy_binding, directive);
self.per_ns(|this, ns| {
let _ = this.try_define(directive.parent_scope.module, target, ns, dummy_binding);
let key = this.new_key(target, ns);
let _ = this.try_define(directive.parent_scope.module, key, dummy_binding);
// Consider erroneous imports used to avoid duplicate diagnostics.
this.record_use(target, ns, dummy_binding, false);
});
@ -820,8 +823,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let parent = directive.parent_scope.module;
match source_bindings[ns].get() {
Err(Undetermined) => indeterminate = true,
// Don't update the resolution, because it was never added.
Err(Determined) if target.name == kw::Underscore => {}
Err(Determined) => {
this.update_resolution(parent, target, ns, |_, resolution| {
let key = this.new_key(target, ns);
this.update_resolution(parent, key, |_, resolution| {
resolution.single_imports.remove(&PtrKey(directive));
});
}
@ -1052,7 +1058,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
_ => None,
};
let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
let names = resolutions.filter_map(|(&(ref i, _), resolution)| {
let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
if *i == ident { return None; } // Never suggest the same name
match *resolution.borrow() {
NameResolution { binding: Some(name_binding), .. } => {
@ -1301,19 +1307,18 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// Ensure that `resolutions` isn't borrowed during `try_define`,
// since it might get updated via a glob cycle.
let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(ident, resolution)| {
resolution.borrow().binding().map(|binding| (*ident, binding))
let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(key, resolution)| {
resolution.borrow().binding().map(|binding| (*key, binding))
}).collect::<Vec<_>>();
for ((mut ident, ns), binding) in bindings {
let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
for (mut key, binding) in bindings {
let scope = match key.ident.span.reverse_glob_adjust(module.expansion, directive.span) {
Some(Some(def)) => self.r.macro_def_scope(def),
Some(None) => directive.parent_scope.module,
None => continue,
};
if self.r.is_accessible_from(binding.pseudo_vis(), scope) {
let imported_binding = self.r.import(binding, directive);
let _ =
self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding);
let _ = self.r.try_define(directive.parent_scope.module, key, imported_binding);
}
}
@ -1329,29 +1334,23 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let mut reexports = Vec::new();
for (&(ident, ns), resolution) in self.r.resolutions(module).borrow().iter() {
let resolution = &mut *resolution.borrow_mut();
let binding = match resolution.binding {
Some(binding) => binding,
None => continue,
};
module.for_each_child(self.r, |this, ident, ns, binding| {
// Filter away ambiguous imports and anything that has def-site
// hygiene.
// FIXME: Implement actual cross-crate hygiene.
let is_good_import = binding.is_import() && !binding.is_ambiguity()
&& !ident.span.modern().from_expansion();
&& !ident.span.from_expansion();
if is_good_import || binding.is_macro_def() {
let res = binding.res();
if res != Res::Err {
if let Some(def_id) = res.opt_def_id() {
if !def_id.is_local() {
self.r.cstore.export_macros_untracked(def_id.krate);
this.cstore.export_macros_untracked(def_id.krate);
}
}
reexports.push(Export {
ident: ident.modern(),
res: res,
ident,
res,
span: binding.span,
vis: binding.vis,
});
@ -1360,7 +1359,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {
if ns == TypeNS && orig_binding.is_variant() &&
!orig_binding.vis.is_at_least(binding.vis, &*self) {
!orig_binding.vis.is_at_least(binding.vis, &*this) {
let msg = match directive.subclass {
ImportDirectiveSubclass::SingleImport { .. } => {
format!("variant `{}` is private and cannot be re-exported",
@ -1372,33 +1371,34 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
Some(binding.span),
msg.clone());
let fresh = self.r.session.one_time_diagnostics
let fresh = this.session.one_time_diagnostics
.borrow_mut().insert(error_id);
if !fresh {
continue;
return;
}
msg
},
ref s @ _ => bug!("unexpected import subclass {:?}", s)
};
let mut err = self.r.session.struct_span_err(binding.span, &msg);
let mut err = this.session.struct_span_err(binding.span, &msg);
let imported_module = match directive.imported_module.get() {
Some(ModuleOrUniformRoot::Module(module)) => module,
_ => bug!("module should exist"),
};
let parent_module = imported_module.parent.expect("parent should exist");
let resolutions = self.r.resolutions(parent_module).borrow();
let resolutions = this.resolutions(parent_module).borrow();
let enum_path_segment_index = directive.module_path.len() - 1;
let enum_ident = directive.module_path[enum_path_segment_index].ident;
let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
let key = this.new_key(enum_ident, TypeNS);
let enum_resolution = resolutions.get(&key)
.expect("resolution should exist");
let enum_span = enum_resolution.borrow()
.binding.expect("binding should exist")
.span;
let enum_def_span = self.r.session.source_map().def_span(enum_span);
let enum_def_snippet = self.r.session.source_map()
let enum_def_span = this.session.source_map().def_span(enum_span);
let enum_def_snippet = this.session.source_map()
.span_to_snippet(enum_def_span).expect("snippet should exist");
// potentially need to strip extant `crate`/`pub(path)` for suggestion
let after_vis_index = enum_def_snippet.find("enum")
@ -1406,7 +1406,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let suggestion = format!("pub {}",
&enum_def_snippet[after_vis_index..]);
self.r.session
this.session
.diag_span_suggestion_once(&mut err,
DiagnosticMessageId::ErrorId(0),
enum_def_span,
@ -1415,7 +1415,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
err.emit();
}
}
}
});
if reexports.len() > 0 {
if let Some(def_id) = module.def_id() {

View File

@ -115,15 +115,17 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
F: FnOnce(&mut Self),
{
let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id);
if self.tcx.has_typeck_tables(item_def_id) {
let tables = self.tcx.typeck_tables_of(item_def_id);
let old_tables = self.save_ctxt.tables;
self.save_ctxt.tables = tables;
f(self);
self.save_ctxt.tables = old_tables;
let tables = if self.tcx.has_typeck_tables(item_def_id) {
self.tcx.typeck_tables_of(item_def_id)
} else {
f(self);
}
self.save_ctxt.empty_tables
};
let old_tables = self.save_ctxt.tables;
self.save_ctxt.tables = tables;
f(self);
self.save_ctxt.tables = old_tables;
}
fn span_from_span(&self, span: Span) -> SpanData {
@ -530,12 +532,14 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
);
}
for field in def.fields() {
self.process_struct_field_def(field, item.id);
self.visit_ty(&field.ty);
}
self.nest_tables(item.id, |v| {
for field in def.fields() {
v.process_struct_field_def(field, item.id);
v.visit_ty(&field.ty);
}
self.process_generic_params(ty_params, &qualname, item.id);
v.process_generic_params(ty_params, &qualname, item.id);
});
}
fn process_enum(

View File

@ -48,6 +48,9 @@ use log::{debug, error, info};
pub struct SaveContext<'l, 'tcx> {
tcx: TyCtxt<'tcx>,
tables: &'l ty::TypeckTables<'tcx>,
/// Used as a fallback when nesting the typeck tables during item processing
/// (if these are not available for that item, e.g. don't own a body)
empty_tables: &'l ty::TypeckTables<'tcx>,
access_levels: &'l AccessLevels,
span_utils: SpanUtils<'tcx>,
config: Config,
@ -1114,6 +1117,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
let save_ctxt = SaveContext {
tcx,
tables: &ty::TypeckTables::empty(None),
empty_tables: &ty::TypeckTables::empty(None),
access_levels: &access_levels,
span_utils: SpanUtils::new(&tcx.sess),
config: find_config(config),

View File

@ -611,6 +611,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
debug!("supplied_sig_of_closure: closure is async fn body");
self.deduce_future_output_from_obligations(expr_def_id)
.unwrap_or_else(|| {
// AFAIK, deducing the future output
// always succeeds *except* in error cases
// like #65159. I'd like to return Error
// here, but I can't because I can't
// easily (and locally) prove that we
// *have* reported an
// error. --nikomatsakis
astconv.ty_infer(None, decl.output.span())
})
}
_ => astconv.ty_infer(None, decl.output.span()),
@ -645,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn deduce_future_output_from_obligations(
&self,
expr_def_id: DefId,
) -> Ty<'tcx> {
) -> Option<Ty<'tcx>> {
debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
let ret_coercion =
@ -688,8 +698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
None
}
})
.unwrap();
});
debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
output_ty

View File

@ -777,7 +777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
"items from traits can only be used if the trait is implemented and in scope"
});
let mut msg = format!(
let message = |action| format!(
"the following {traits_define} an item `{name}`, perhaps you need to {action} \
{one_of_them}:",
traits_define = if candidates.len() == 1 {
@ -785,11 +785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
"traits define"
},
action = if let Some(param) = param_type {
format!("restrict type parameter `{}` with", param)
} else {
"implement".to_string()
},
action = action,
one_of_them = if candidates.len() == 1 {
"it"
} else {
@ -809,50 +805,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Get the `hir::Param` to verify whether it already has any bounds.
// We do this to avoid suggesting code that ends up as `T: FooBar`,
// instead we suggest `T: Foo + Bar` in that case.
let mut has_bounds = None;
let mut impl_trait = false;
if let Node::GenericParam(ref param) = hir.get(id) {
let kind = &param.kind;
if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = kind {
// We've found `fn foo(x: impl Trait)` instead of
// `fn foo<T>(x: T)`. We want to suggest the correct
// `fn foo(x: impl Trait + TraitBound)` instead of
// `fn foo<T: TraitBound>(x: T)`. (See #63706.)
impl_trait = true;
has_bounds = param.bounds.get(1);
} else {
has_bounds = param.bounds.get(0);
match hir.get(id) {
Node::GenericParam(ref param) => {
let mut impl_trait = false;
let has_bounds = if let hir::GenericParamKind::Type {
synthetic: Some(_), ..
} = &param.kind {
// We've found `fn foo(x: impl Trait)` instead of
// `fn foo<T>(x: T)`. We want to suggest the correct
// `fn foo(x: impl Trait + TraitBound)` instead of
// `fn foo<T: TraitBound>(x: T)`. (#63706)
impl_trait = true;
param.bounds.get(1)
} else {
param.bounds.get(0)
};
let sp = hir.span(id);
let sp = if let Some(first_bound) = has_bounds {
// `sp` only covers `T`, change it so that it covers
// `T:` when appropriate
sp.until(first_bound.span())
} else {
sp
};
// FIXME: contrast `t.def_id` against `param.bounds` to not suggest
// traits already there. That can happen when the cause is that
// we're in a const scope or associated function used as a method.
err.span_suggestions(
sp,
&message(format!(
"restrict type parameter `{}` with",
param.name.ident().as_str(),
)),
candidates.iter().map(|t| format!(
"{}{} {}{}",
param.name.ident().as_str(),
if impl_trait { " +" } else { ":" },
self.tcx.def_path_str(t.def_id),
if has_bounds.is_some() { " + "} else { "" },
)),
Applicability::MaybeIncorrect,
);
suggested = true;
}
Node::Item(hir::Item {
kind: hir::ItemKind::Trait(.., bounds, _), ident, ..
}) => {
let (sp, sep, article) = if bounds.is_empty() {
(ident.span.shrink_to_hi(), ":", "a")
} else {
(bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
};
err.span_suggestions(
sp,
&message(format!("add {} supertrait for", article)),
candidates.iter().map(|t| format!(
"{} {}",
sep,
self.tcx.def_path_str(t.def_id),
)),
Applicability::MaybeIncorrect,
);
suggested = true;
}
_ => {}
}
let sp = hir.span(id);
// `sp` only covers `T`, change it so that it covers `T:` when appropriate.
let sp = if let Some(first_bound) = has_bounds {
sp.until(first_bound.span())
} else {
sp
};
// FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
// already there. That can happen when the cause is that we're in a const
// scope or associated function used as a method.
err.span_suggestions(
sp,
&msg[..],
candidates.iter().map(|t| format!(
"{}{} {}{}",
param,
if impl_trait { " +" } else { ":" },
self.tcx.def_path_str(t.def_id),
if has_bounds.is_some() { " + " } else { "" },
)),
Applicability::MaybeIncorrect,
);
suggested = true;
}
};
}
if !suggested {
let mut msg = message(if let Some(param) = param_type {
format!("restrict type parameter `{}` with", param)
} else {
"implement".to_string()
});
for (i, trait_info) in candidates.iter().enumerate() {
msg.push_str(&format!(
"\ncandidate #{}: `{}`",

View File

@ -334,8 +334,7 @@ impl Ident {
if !Self::is_valid(&string) {
panic!("`{:?}` is not a valid identifier", string)
}
// Get rid of gensyms to conservatively check rawness on the string contents only.
if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() {
if is_raw && !sym.can_be_raw() {
panic!("`{}` cannot be a raw identifier", string);
}
Ident { sym, is_raw, span }

View File

@ -808,25 +808,13 @@ impl Ident {
Ident::new(self.name, self.span.modern_and_legacy())
}
/// Transforms an underscore identifier into one with the same name, but
/// gensymed. Leaves non-underscore identifiers unchanged.
pub fn gensym_if_underscore(self) -> Ident {
if self.name == kw::Underscore {
let name = with_interner(|interner| interner.gensymed(self.name));
Ident::new(name, self.span)
} else {
self
}
}
/// Convert the name to a `LocalInternedString`. This is a slowish
/// operation because it requires locking the symbol interner.
pub fn as_str(self) -> LocalInternedString {
self.name.as_str()
}
/// Convert the name to an `InternedString`. This is a slowish operation
/// because it requires locking the symbol interner.
/// Convert the name to an `InternedString`.
pub fn as_interned_str(self) -> InternedString {
self.name.as_interned_str()
}
@ -881,26 +869,9 @@ impl UseSpecializedDecodable for Ident {
}
}
/// A symbol is an interned or gensymed string. A gensym is a symbol that is
/// never equal to any other symbol.
/// An interned string.
///
/// Conceptually, a gensym can be thought of as a normal symbol with an
/// invisible unique suffix. Gensyms are useful when creating new identifiers
/// that must not match any existing identifiers, e.g. during macro expansion
/// and syntax desugaring. Because gensyms should always be identifiers, all
/// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
/// future the gensym-ness may be moved from `Symbol` to hygiene data.)
///
/// Examples:
/// ```
/// assert_eq!(Ident::from_str("_"), Ident::from_str("_"))
/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_"))
/// assert_ne!(
/// Ident::from_str("_").gensym_if_underscore(),
/// Ident::from_str("_").gensym_if_underscore(),
/// )
/// ```
/// Internally, a symbol is implemented as an index, and all operations
/// Internally, a `Symbol` is implemented as an index, and all operations
/// (including hashing, equality, and ordering) operate on that index. The use
/// of `rustc_index::newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
/// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes.
@ -951,12 +922,9 @@ impl Symbol {
})
}
/// Convert to an `InternedString`. This is a slowish operation because it
/// requires locking the symbol interner.
/// Convert to an `InternedString`.
pub fn as_interned_str(self) -> InternedString {
with_interner(|interner| InternedString {
symbol: interner.interned(self)
})
InternedString { symbol: self }
}
pub fn as_u32(self) -> u32 {
@ -966,12 +934,7 @@ impl Symbol {
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let is_gensymed = with_interner(|interner| interner.is_gensymed(*self));
if is_gensymed {
write!(f, "{}({:?})", self, self.0)
} else {
write!(f, "{}", self)
}
fmt::Display::fmt(self, f)
}
}
@ -994,15 +957,11 @@ impl Decodable for Symbol {
}
// The `&'static str`s in this type actually point into the arena.
//
// Note that normal symbols are indexed upward from 0, and gensyms are indexed
// downward from SymbolIndex::MAX_AS_U32.
#[derive(Default)]
pub struct Interner {
arena: DroplessArena,
names: FxHashMap<&'static str, Symbol>,
strings: Vec<&'static str>,
gensyms: Vec<Symbol>,
}
impl Interner {
@ -1035,34 +994,10 @@ impl Interner {
self.names.insert(string, name);
name
}
fn interned(&self, symbol: Symbol) -> Symbol {
if (symbol.0.as_usize()) < self.strings.len() {
symbol
} else {
self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]
}
}
fn gensymed(&mut self, symbol: Symbol) -> Symbol {
self.gensyms.push(symbol);
Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1)
}
fn is_gensymed(&mut self, symbol: Symbol) -> bool {
symbol.0.as_usize() >= self.strings.len()
}
// Get the symbol as a string. `Symbol::as_str()` should be used in
// preference to this function.
pub fn get(&self, symbol: Symbol) -> &str {
match self.strings.get(symbol.0.as_usize()) {
Some(string) => string,
None => {
let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize];
self.strings[symbol.0.as_usize()]
}
}
self.strings[symbol.0.as_usize()]
}
}
@ -1223,19 +1158,12 @@ impl fmt::Display for LocalInternedString {
}
}
/// An alternative to `Symbol` that is focused on string contents. It has two
/// main differences to `Symbol`.
/// An alternative to `Symbol` that is focused on string contents.
///
/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the
/// Its implementations of `Hash`, `PartialOrd` and `Ord` work with the
/// string chars rather than the symbol integer. This is useful when hash
/// stability is required across compile sessions, or a guaranteed sort
/// ordering is required.
///
/// Second, gensym-ness is irrelevant. E.g.:
/// ```
/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str())
/// ```
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct InternedString {
symbol: Symbol,

View File

@ -14,13 +14,6 @@ fn interner_tests() {
assert_eq!(i.intern("cat"), Symbol::new(1));
// dog is still at zero
assert_eq!(i.intern("dog"), Symbol::new(0));
let z = i.intern("zebra");
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32));
// gensym of same string gets new number:
assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
// gensym of *existing* string gets new number:
let d = i.intern("dog");
assert_eq!(i.gensymed(d), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
}
#[test]

View File

@ -0,0 +1,10 @@
// Regression test for #65159. We used to ICE.
//
// edition:2018
async fn copy() -> Result<()> //~ ERROR wrong number of type arguments
{
Ok(())
}
fn main() { }

View File

@ -0,0 +1,9 @@
error[E0107]: wrong number of type arguments: expected 2, found 1
--> $DIR/issue-65159.rs:5:20
|
LL | async fn copy() -> Result<()>
| ^^^^^^^^^^ expected 2 type arguments
error: aborting due to previous error
For more information about this error, try `rustc --explain E0107`.

View File

@ -0,0 +1,42 @@
// edition:2018
// Avoid spurious warnings of unused lifetime. The below async functions
// are desugered to have an unused lifetime
// but we don't want to warn about that as there's nothing they can do about it.
#![deny(unused_lifetimes)]
#![allow(dead_code)]
pub async fn october(s: &str) {
println!("{}", s);
}
pub async fn async_fn(&mut ref s: &mut[i32]) {
println!("{:?}", s);
}
macro_rules! foo_macro {
() => {
pub async fn async_fn_in_macro(&mut ref _s: &mut[i32]) {}
};
}
foo_macro!();
pub async fn func_with_unused_lifetime<'a>(s: &'a str) {
//~^ ERROR lifetime parameter `'a` never used
println!("{}", s);
}
pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
//~^ ERROR lifetime parameter `'a` never used
//~^^ ERROR lifetime parameter `'b` never used
println!("{}", s);
}
pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) {
//~^ ERROR lifetime parameter `'c` never used
println!("{}", s);
}
fn main() {}

View File

@ -0,0 +1,32 @@
error: lifetime parameter `'a` never used
--> $DIR/unused-lifetime.rs:26:40
|
LL | pub async fn func_with_unused_lifetime<'a>(s: &'a str) {
| ^^
|
note: lint level defined here
--> $DIR/unused-lifetime.rs:7:9
|
LL | #![deny(unused_lifetimes)]
| ^^^^^^^^^^^^^^^^
error: lifetime parameter `'a` never used
--> $DIR/unused-lifetime.rs:31:44
|
LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
| ^^
error: lifetime parameter `'b` never used
--> $DIR/unused-lifetime.rs:31:48
|
LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
| ^^
error: lifetime parameter `'c` never used
--> $DIR/unused-lifetime.rs:37:54
|
LL | pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) {
| ^^
error: aborting due to 4 previous errors

View File

@ -1,4 +1,4 @@
// build-pass (FIXME(62277): could be check-pass?)
// check-pass
#![feature(never_type)]
#![allow(unreachable_code)]

View File

@ -0,0 +1,23 @@
// check-pass
struct Generic<T>(T);
impl<T> Generic<T> {
const ARRAY: [T; 0] = [];
const NEWTYPE_ARRAY: Generic<[T; 0]> = Generic([]);
const ARRAY_FIELD: Generic<(i32, [T; 0])> = Generic((0, []));
}
pub const fn array<T>() -> &'static T {
&Generic::<T>::ARRAY[0]
}
pub const fn newtype_array<T>() -> &'static T {
&Generic::<T>::NEWTYPE_ARRAY.0[0]
}
pub const fn array_field<T>() -> &'static T {
&(Generic::<T>::ARRAY_FIELD.0).1[0]
}
fn main() {}

View File

@ -1,4 +1,5 @@
#![feature(never_type)]
fn foo() -> Result<u32, !> {
Ok(123)
}

View File

@ -1,5 +1,5 @@
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
--> $DIR/feature-gate-exhaustive-patterns.rs:7:9
--> $DIR/feature-gate-exhaustive-patterns.rs:8:9
|
LL | let Ok(_x) = foo();
| ^^^^^^ pattern `Err(_)` not covered

View File

@ -1,4 +1,5 @@
// run-pass
#![allow(unreachable_code)]
#![feature(never_type)]

View File

@ -0,0 +1,14 @@
#![crate_type="lib"]
struct Nested<K>(K);
fn should_error<T>() where T : Into<&u32> {}
//~^ ERROR `&` without an explicit lifetime name cannot be used here [E0637]
trait X<'a, K: 'a> {
fn foo<'b, L: X<&'b Nested<K>>>();
//~^ ERROR missing lifetime specifier [E0106]
}
fn bar<'b, L: X<&'b Nested<i32>>>(){}
//~^ ERROR missing lifetime specifier [E0106]

View File

@ -0,0 +1,21 @@
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:37
|
LL | fn should_error<T>() where T : Into<&u32> {}
| ^ explicit lifetime name needed here
error[E0106]: missing lifetime specifier
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19
|
LL | fn foo<'b, L: X<&'b Nested<K>>>();
| ^^^^^^^^^^^^^^^^ expected lifetime parameter
error[E0106]: missing lifetime specifier
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:15
|
LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
| ^^^^^^^^^^^^^^^^^^ expected lifetime parameter
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0106`.

View File

@ -6,3 +6,4 @@ LL | let p = foo { x: () };
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.

View File

@ -6,3 +6,4 @@ LL | Foo { i } => ()
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.

View File

@ -6,3 +6,4 @@ LL | let myVar = MyMod { T: 0 };
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.

View File

@ -6,3 +6,4 @@ LL | let _ = module { x: 0 };
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.

View File

@ -6,3 +6,4 @@ LL | char{ch} => true
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.

View File

@ -24,3 +24,4 @@ LL | u32 { x: 1 } => {}
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0574`.

View File

@ -16,4 +16,5 @@ LL | Foo::f();
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0599`.
Some errors have detailed explanations: E0574, E0599.
For more information about an error, try `rustc --explain E0574`.

View File

@ -1,5 +1,4 @@
#![feature(never_type)]
#![deny(unused_must_use)]
#[must_use]

View File

@ -1,17 +1,17 @@
error: unused return value of `foo` that must be used
--> $DIR/must_use-unit.rs:14:5
--> $DIR/must_use-unit.rs:13:5
|
LL | foo();
| ^^^^^^
|
note: lint level defined here
--> $DIR/must_use-unit.rs:3:9
--> $DIR/must_use-unit.rs:2:9
|
LL | #![deny(unused_must_use)]
| ^^^^^^^^^^^^^^^
error: unused return value of `bar` that must be used
--> $DIR/must_use-unit.rs:16:5
--> $DIR/must_use-unit.rs:15:5
|
LL | bar();
| ^^^^^^

View File

@ -1,5 +1,6 @@
// Test that a variable of type ! can coerce to another type.
// run-fail
// error-pattern:explicit
#![feature(never_type)]

View File

@ -1,5 +1,6 @@
// Test that we can use a ! for an argument of type !
// run-fail
// error-pattern:wowzers!
#![feature(never_type)]

View File

@ -1,5 +1,6 @@
// Test that we can explicitly cast ! to another type
// run-fail
// error-pattern:explicit
#![feature(never_type)]

View File

@ -4,6 +4,7 @@
#![allow(unused_assignments)]
#![allow(unused_variables)]
#![allow(unreachable_code)]
// Test various cases where we permit an unconstrained variable
// to fallback based on control-flow.
//

View File

@ -1,8 +1,9 @@
// run-pass
// Test that we can call static methods on ! both directly and when it appears in a generic
#![feature(never_type)]
// Test that we can call static methods on ! both directly and when it appears in a generic
trait StringifyType {
fn stringify_type() -> &'static str;
}

View File

@ -1,4 +1,5 @@
// build-pass (FIXME(62277): could be check-pass?)
// check-pass
#![allow(dead_code)]
#![feature(never_type)]
#![feature(exhaustive_patterns)]

View File

@ -1,9 +1,9 @@
// Test that an assignment of type ! makes the rest of the block dead code.
#![feature(never_type)]
// build-pass (FIXME(62277): could be check-pass?)
#![warn(unused)]
// check-pass
#![feature(never_type)]
#![warn(unused)]
fn main() {
let x: ! = panic!("aah"); //~ WARN unused

View File

@ -7,7 +7,7 @@ LL | drop(x);
| ^^^^^^^^ unreachable statement
|
note: lint level defined here
--> $DIR/never-assign-dead-code.rs:5:9
--> $DIR/never-assign-dead-code.rs:6:9
|
LL | #![warn(unused)]
| ^^^^^^
@ -29,7 +29,7 @@ LL | let x: ! = panic!("aah");
| ^ help: consider prefixing with an underscore: `_x`
|
note: lint level defined here
--> $DIR/never-assign-dead-code.rs:5:9
--> $DIR/never-assign-dead-code.rs:6:9
|
LL | #![warn(unused)]
| ^^^^^^

View File

@ -1,5 +1,6 @@
// Test that we can use ! as an associated type.
// run-fail
// error-pattern:kapow!
#![feature(never_type)]

View File

@ -2,6 +2,7 @@
#![allow(unused_variables)]
#![allow(unreachable_code)]
// Test that we can extract a ! through pattern matching then use it as several different types.
#![feature(never_type)]

View File

@ -1,5 +1,6 @@
// Test that we can use ! as an argument to a trait impl.
// run-fail
// error-pattern:oh no!
#![feature(never_type)]

View File

@ -1,4 +1,4 @@
// build-pass (FIXME(62277): could be check-pass?)
// check-pass
#![crate_type="lib"]

View File

@ -1,5 +1,3 @@
// compile-fail
#![feature(never_type)]
#![feature(exhaustive_patterns)]

View File

@ -1,17 +1,17 @@
error: unreachable pattern
--> $DIR/unreachable-loop-patterns.rs:20:9
--> $DIR/unreachable-loop-patterns.rs:18:9
|
LL | for _ in unimplemented!() as Void {}
| ^
|
note: lint level defined here
--> $DIR/unreachable-loop-patterns.rs:7:9
--> $DIR/unreachable-loop-patterns.rs:5:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/unreachable-loop-patterns.rs:20:14
--> $DIR/unreachable-loop-patterns.rs:18:14
|
LL | for _ in unimplemented!() as Void {}
| ^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1,4 +1,4 @@
// build-pass (FIXME(62277): could be check-pass?)
// check-pass
#![feature(never_type, exhaustive_patterns)]
#![warn(unreachable_code)]
#![warn(unreachable_patterns)]

View File

@ -14,3 +14,4 @@ LL | use std::thread::Result;
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.

View File

@ -0,0 +1,10 @@
// check-pass
// compile-flags: -Zsave-analysis
trait Trait { type Assoc; }
fn main() {
struct Data<T: Trait> {
x: T::Assoc,
}
}

View File

@ -0,0 +1,47 @@
// run-rustfix
// check-only
#[derive(Debug)]
struct Demo {
a: String
}
trait GetString {
fn get_a(&self) -> &String;
}
trait UseString: std::fmt::Debug + GetString {
fn use_string(&self) {
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
}
}
trait UseString2: GetString {
fn use_string(&self) {
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
}
}
impl GetString for Demo {
fn get_a(&self) -> &String {
&self.a
}
}
impl UseString for Demo {}
impl UseString2 for Demo {}
#[cfg(test)]
mod tests {
use crate::{Demo, UseString};
#[test]
fn it_works() {
let d = Demo { a: "test".to_string() };
d.use_string();
}
}
fn main() {}

View File

@ -0,0 +1,47 @@
// run-rustfix
// check-only
#[derive(Debug)]
struct Demo {
a: String
}
trait GetString {
fn get_a(&self) -> &String;
}
trait UseString: std::fmt::Debug {
fn use_string(&self) {
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
}
}
trait UseString2 {
fn use_string(&self) {
println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
}
}
impl GetString for Demo {
fn get_a(&self) -> &String {
&self.a
}
}
impl UseString for Demo {}
impl UseString2 for Demo {}
#[cfg(test)]
mod tests {
use crate::{Demo, UseString};
#[test]
fn it_works() {
let d = Demo { a: "test".to_string() };
d.use_string();
}
}
fn main() {}

View File

@ -0,0 +1,27 @@
error[E0599]: no method named `get_a` found for type `&Self` in the current scope
--> $DIR/constrain-trait.rs:15:31
|
LL | println!("{:?}", self.get_a());
| ^^^^^ method not found in `&Self`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `get_a`, perhaps you need to add another supertrait for it:
|
LL | trait UseString: std::fmt::Debug + GetString {
| ^^^^^^^^^^^
error[E0599]: no method named `get_a` found for type `&Self` in the current scope
--> $DIR/constrain-trait.rs:21:31
|
LL | println!("{:?}", self.get_a());
| ^^^^^ method not found in `&Self`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `get_a`, perhaps you need to add a supertrait for it:
|
LL | trait UseString2: GetString {
| ^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0599`.

View File

@ -6,3 +6,4 @@ LL | TraitNotAStruct{ value: 0 };
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.

View File

@ -21,3 +21,4 @@ LL | let try_result: Option<_> = try {
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0574`.

View File

@ -0,0 +1,33 @@
// Make sure that underscore imports with different contexts can exist in the
// same scope.
// check-pass
#![feature(decl_macro)]
mod x {
pub use std::ops::Deref as _;
}
macro n() {
pub use crate::x::*;
}
#[macro_export]
macro_rules! p {
() => { pub use crate::x::*; }
}
macro m($y:ident) {
mod $y {
crate::n!(); // Reexport of `Deref` should not be imported in `main`
crate::p!(); // Reexport of `Deref` should be imported into `main`
}
}
m!(y);
fn main() {
use crate::y::*;
(&()).deref();
}

View File

@ -0,0 +1,40 @@
// Make sure that underscore imports have the same hygiene considerations as
// other imports.
#![feature(decl_macro)]
mod x {
pub use std::ops::Deref as _;
}
macro glob_import() {
pub use crate::x::*;
}
macro underscore_import() {
use std::ops::DerefMut as _;
}
mod y {
crate::glob_import!();
crate::underscore_import!();
}
macro create_module($y:ident) {
mod $y {
crate::glob_import!();
crate::underscore_import!();
}
}
create_module!(z);
fn main() {
use crate::y::*;
use crate::z::*;
glob_import!();
underscore_import!();
(&()).deref(); //~ ERROR no method named `deref`
(&mut ()).deref_mut(); //~ ERROR no method named `deref_mut`
}

View File

@ -0,0 +1,27 @@
error[E0599]: no method named `deref` found for type `&()` in the current scope
--> $DIR/hygiene.rs:38:11
|
LL | (&()).deref();
| ^^^^^ method not found in `&()`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
LL | use std::ops::Deref;
|
error[E0599]: no method named `deref_mut` found for type `&mut ()` in the current scope
--> $DIR/hygiene.rs:39:15
|
LL | (&mut ()).deref_mut();
| ^^^^^^^^^ method not found in `&mut ()`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
LL | use std::ops::DerefMut;
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0599`.

View File

@ -0,0 +1,45 @@
// Check that macro expanded underscore imports behave as expected
// check-pass
#![feature(decl_macro, rustc_attrs)]
mod x {
pub use std::ops::Not as _;
}
macro m() {
mod w {
mod y {
pub use std::ops::Deref as _;
}
use crate::x::*;
use self::y::*;
use std::ops::DerefMut as _;
fn f() {
false.not();
(&()).deref();
(&mut ()).deref_mut();
}
}
}
#[rustc_macro_transparency = "transparent"]
macro n() {
mod z {
pub use std::ops::Deref as _;
}
use crate::x::*;
use crate::z::*;
use std::ops::DerefMut as _;
fn f() {
false.not();
(&()).deref();
(&mut ()).deref_mut();
}
}
m!();
n!();
fn main() {}

View File

@ -6,3 +6,4 @@ LL | Trait { x: 42 } => ()
error: aborting due to previous error
For more information about this error, try `rustc --explain E0574`.