Merge branch 'master' into kenta7777#53719
This commit is contained in:
commit
26dbf56196
157 changed files with 3527 additions and 1898 deletions
|
|
@ -125,9 +125,9 @@ you have a more recent version installed the build system doesn't understand
|
|||
then you may need to force rustbuild to use an older version. This can be done
|
||||
by manually calling the appropriate vcvars file before running the bootstrap.
|
||||
|
||||
```
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
|
||||
python x.py build
|
||||
```batch
|
||||
> CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
|
||||
> python x.py build
|
||||
```
|
||||
|
||||
#### Specifying an ABI
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ system.
|
|||
|
||||
The rustbuild build system has a primary entry point, a top level `x.py` script:
|
||||
|
||||
```
|
||||
python ./x.py build
|
||||
```sh
|
||||
$ python ./x.py build
|
||||
```
|
||||
|
||||
Note that if you're on Unix you should be able to execute the script directly:
|
||||
|
||||
```
|
||||
./x.py build
|
||||
```sh
|
||||
$ ./x.py build
|
||||
```
|
||||
|
||||
The script accepts commands, flags, and arguments to determine what to do:
|
||||
|
|
@ -129,18 +129,18 @@ To follow this course of action, first thing you will want to do is to
|
|||
install a nightly, presumably using `rustup`. You will then want to
|
||||
configure your directory to use this build, like so:
|
||||
|
||||
```
|
||||
```sh
|
||||
# configure to use local rust instead of downloading a beta.
|
||||
# `--local-rust-root` is optional here. If elided, we will
|
||||
# use whatever rustc we find on your PATH.
|
||||
> ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
|
||||
$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
|
||||
```
|
||||
|
||||
After that, you can use the `--incremental` flag to actually do
|
||||
incremental builds:
|
||||
|
||||
```
|
||||
> ./x.py build --incremental
|
||||
```sh
|
||||
$ ./x.py build --incremental
|
||||
```
|
||||
|
||||
The `--incremental` flag will store incremental compilation artifacts
|
||||
|
|
@ -159,7 +159,7 @@ will still be using the local nightly as your bootstrap).
|
|||
This build system houses all output under the `build` directory, which looks
|
||||
like this:
|
||||
|
||||
```
|
||||
```sh
|
||||
# Root folder of all output. Everything is scoped underneath here
|
||||
build/
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ $ cat main.rs
|
|||
fn main() {
|
||||
let x = 5;
|
||||
}
|
||||
> rustc main.rs
|
||||
$ rustc main.rs
|
||||
warning: unused variable: `x`
|
||||
--> main.rs:2:9
|
||||
|
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ pub fn foo() {
|
|||
|
||||
This will produce this warning:
|
||||
|
||||
```console
|
||||
```bash
|
||||
$ rustc lib.rs --crate-type=lib
|
||||
warning: unused variable: `x`
|
||||
--> lib.rs:2:9
|
||||
|
|
@ -69,7 +69,7 @@ fn main() {
|
|||
```
|
||||
|
||||
```bash
|
||||
> rustc main.rs
|
||||
$ rustc main.rs
|
||||
error: bitshift exceeds the type's number of bits
|
||||
--> main.rs:2:13
|
||||
|
|
||||
|
|
@ -129,7 +129,10 @@ warning: missing documentation for a function
|
|||
|
|
||||
1 | pub fn foo() {}
|
||||
| ^^^^^^^^^^^^
|
||||
> rustc lib.rs --crate-type=lib -D missing-docs
|
||||
```
|
||||
|
||||
```bash
|
||||
$ rustc lib.rs --crate-type=lib -D missing-docs
|
||||
error: missing documentation for crate
|
||||
--> lib.rs:1:1
|
||||
|
|
||||
|
|
@ -150,13 +153,13 @@ error: aborting due to 2 previous errors
|
|||
You can also pass each flag more than once for changing multiple lints:
|
||||
|
||||
```bash
|
||||
rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables
|
||||
$ rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables
|
||||
```
|
||||
|
||||
And of course, you can mix these four flags together:
|
||||
|
||||
```bash
|
||||
rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables
|
||||
$ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables
|
||||
```
|
||||
|
||||
### Via an attribute
|
||||
|
|
@ -164,7 +167,7 @@ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables
|
|||
You can also modify the lint level with a crate-wide attribute:
|
||||
|
||||
```bash
|
||||
> cat lib.rs
|
||||
$ cat lib.rs
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub fn foo() {}
|
||||
|
|
|
|||
|
|
@ -1,157 +0,0 @@
|
|||
# `used`
|
||||
|
||||
The tracking issue for this feature
|
||||
is: [40289](https://github.com/rust-lang/rust/issues/40289).
|
||||
|
||||
------------------------
|
||||
|
||||
The `#[used]` attribute can be applied to `static` variables to prevent the Rust
|
||||
compiler from optimizing them away even if they appear to be unused by the crate
|
||||
(appear to be "dead code").
|
||||
|
||||
``` rust
|
||||
#![feature(used)]
|
||||
|
||||
#[used]
|
||||
static FOO: i32 = 1;
|
||||
|
||||
static BAR: i32 = 2;
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
If you compile this program into an object file, you'll see that `FOO` makes it
|
||||
to the object file but `BAR` doesn't. Neither static variable is used by the
|
||||
program.
|
||||
|
||||
``` text
|
||||
$ rustc -C opt-level=3 --emit=obj used.rs
|
||||
|
||||
$ nm -C used.o
|
||||
0000000000000000 T main
|
||||
U std::rt::lang_start
|
||||
0000000000000000 r used::FOO
|
||||
0000000000000000 t used::main
|
||||
```
|
||||
|
||||
Note that the *linker* knows nothing about the `#[used]` attribute and will
|
||||
remove `#[used]` symbols if they are not referenced by other parts of the
|
||||
program:
|
||||
|
||||
``` text
|
||||
$ rustc -C opt-level=3 used.rs
|
||||
|
||||
$ nm -C used | grep FOO
|
||||
```
|
||||
|
||||
"This doesn't sound too useful then!" you may think but keep reading.
|
||||
|
||||
To preserve the symbols all the way to the final binary, you'll need the
|
||||
cooperation of the linker. Here's one example:
|
||||
|
||||
The ELF standard defines two special sections, `.init_array` and
|
||||
`.pre_init_array`, that may contain function pointers which will be executed
|
||||
*before* the `main` function is invoked. The linker will preserve symbols placed
|
||||
in these sections (at least when linking programs that target the `*-*-linux-*`
|
||||
targets).
|
||||
|
||||
``` rust,ignore
|
||||
#![feature(used)]
|
||||
|
||||
extern "C" fn before_main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
||||
#[link_section = ".init_array"]
|
||||
#[used]
|
||||
static INIT_ARRAY: [extern "C" fn(); 1] = [before_main];
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
So, `#[used]` and `#[link_section]` can be combined to obtain "life before
|
||||
main".
|
||||
|
||||
``` text
|
||||
$ rustc -C opt-level=3 before-main.rs
|
||||
|
||||
$ ./before-main
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Another example: ARM Cortex-M microcontrollers need their reset handler, a
|
||||
pointer to the function that will executed right after the microcontroller is
|
||||
turned on, to be placed near the start of their FLASH memory to boot properly.
|
||||
|
||||
This condition can be met using `#[used]` and `#[link_section]` plus a linker
|
||||
script.
|
||||
|
||||
``` rust,ignore
|
||||
#![feature(panic_handler)]
|
||||
#![feature(used)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
extern "C" fn reset_handler() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[link_section = ".reset_handler"]
|
||||
#[used]
|
||||
static RESET_HANDLER: extern "C" fn() -> ! = reset_handler;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
```
|
||||
|
||||
``` text
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x08000000, LENGTH = 128K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text ORIGIN(FLASH) :
|
||||
{
|
||||
/* Vector table */
|
||||
LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */
|
||||
KEEP(*(.reset_handler));
|
||||
|
||||
/* Omitted: The rest of the vector table */
|
||||
|
||||
*(.text.*);
|
||||
} > FLASH
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
/* Unused unwinding stuff */
|
||||
*(.ARM.exidx.*)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
``` text
|
||||
$ xargo rustc --target thumbv7m-none-eabi --release -- \
|
||||
-C link-arg=-Tlink.x -C link-arg=-nostartfiles
|
||||
|
||||
$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app
|
||||
./target/thumbv7m-none-eabi/release/app: file format elf32-littlearm
|
||||
|
||||
|
||||
Disassembly of section .text:
|
||||
|
||||
08000000 <app::RESET_HANDLER-0x4>:
|
||||
8000000: 20005000 .word 0x20005000
|
||||
|
||||
08000004 <app::RESET_HANDLER>:
|
||||
8000004: 08000009 ....
|
||||
|
||||
08000008 <app::reset_handler>:
|
||||
8000008: e7fe b.n 8000008 <app::reset_handler>
|
||||
```
|
||||
|
|
@ -122,6 +122,9 @@ nonzero_integers! {
|
|||
/// all standard arithmetic operations on the underlying value are
|
||||
/// intended to have wrapping semantics.
|
||||
///
|
||||
/// The underlying value can be retrieved through the `.0` index of the
|
||||
/// `Wrapping` tuple.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -470,6 +470,36 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Maps a `Result<T, E>` to `U` by applying a function to a
|
||||
/// contained [`Ok`] value, or a fallback function to a
|
||||
/// contained [`Err`] value.
|
||||
///
|
||||
/// This function can be used to unpack a successful result
|
||||
/// while handling an error.
|
||||
///
|
||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||
/// [`Err`]: enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(result_map_or_else)]
|
||||
/// let k = 21;
|
||||
///
|
||||
/// let x : Result<_, &str> = Ok("foo");
|
||||
/// assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3);
|
||||
///
|
||||
/// let x : Result<&str, _> = Err("bar");
|
||||
/// assert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "result_map_or_else", issue = "53268")]
|
||||
pub fn map_or_else<U, M: FnOnce(T) -> U, F: FnOnce(E) -> U>(self, fallback: F, map: M) -> U {
|
||||
self.map(map).unwrap_or_else(fallback)
|
||||
}
|
||||
|
||||
/// Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a
|
||||
/// contained [`Err`] value, leaving an [`Ok`] value untouched.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@
|
|||
//! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and
|
||||
//! custom derive attributes`#[proc_macro_derive]`.
|
||||
//!
|
||||
//! Note that this crate is intentionally bare-bones currently.
|
||||
//! This functionality is intended to be expanded over time as more surface
|
||||
//! area for macro authors is stabilized.
|
||||
//!
|
||||
//! See [the book](../book/first-edition/procedural-macros.html) for more.
|
||||
|
||||
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
|
|
@ -73,9 +69,6 @@ use syntax_pos::{Pos, FileName};
|
|||
///
|
||||
/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
|
||||
/// and `#[proc_macro_derive]` definitions.
|
||||
///
|
||||
/// The API of this type is intentionally bare-bones, but it'll be expanded over
|
||||
/// time!
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
#[derive(Clone)]
|
||||
pub struct TokenStream(tokenstream::TokenStream);
|
||||
|
|
|
|||
|
|
@ -76,23 +76,38 @@ impl<'a> DefCollector<'a> {
|
|||
fn visit_async_fn(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
async_node_id: NodeId,
|
||||
return_impl_trait_id: NodeId,
|
||||
name: Name,
|
||||
span: Span,
|
||||
visit_fn: impl FnOnce(&mut DefCollector<'a>)
|
||||
header: &FnHeader,
|
||||
generics: &'a Generics,
|
||||
decl: &'a FnDecl,
|
||||
body: &'a Block,
|
||||
) {
|
||||
let (closure_id, return_impl_trait_id) = match header.asyncness {
|
||||
IsAsync::Async {
|
||||
closure_id,
|
||||
return_impl_trait_id,
|
||||
} => (closure_id, return_impl_trait_id),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// For async functions, we need to create their inner defs inside of a
|
||||
// closure to match their desugared representation.
|
||||
let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
|
||||
let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
|
||||
return self.with_parent(fn_def, |this| {
|
||||
this.create_def(return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span);
|
||||
let closure_def = this.create_def(async_node_id,
|
||||
|
||||
visit::walk_generics(this, generics);
|
||||
visit::walk_fn_decl(this, decl);
|
||||
|
||||
let closure_def = this.create_def(closure_id,
|
||||
DefPathData::ClosureExpr,
|
||||
REGULAR_SPACE,
|
||||
span);
|
||||
this.with_parent(closure_def, visit_fn)
|
||||
this.with_parent(closure_def, |this| {
|
||||
visit::walk_block(this, body);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -122,17 +137,20 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
|
||||
return visit::walk_item(self, i);
|
||||
}
|
||||
ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async {
|
||||
closure_id,
|
||||
return_impl_trait_id,
|
||||
}, .. }, ..) => {
|
||||
ItemKind::Fn(
|
||||
ref decl,
|
||||
ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
|
||||
ref generics,
|
||||
ref body,
|
||||
) => {
|
||||
return self.visit_async_fn(
|
||||
i.id,
|
||||
closure_id,
|
||||
return_impl_trait_id,
|
||||
i.ident.name,
|
||||
i.span,
|
||||
|this| visit::walk_item(this, i)
|
||||
header,
|
||||
generics,
|
||||
decl,
|
||||
body,
|
||||
)
|
||||
}
|
||||
ItemKind::Mod(..) => DefPathData::Module(i.ident.as_interned_str()),
|
||||
|
|
@ -233,18 +251,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
|||
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
|
||||
let def_data = match ii.node {
|
||||
ImplItemKind::Method(MethodSig {
|
||||
header: FnHeader { asyncness: IsAsync::Async {
|
||||
closure_id,
|
||||
return_impl_trait_id,
|
||||
}, .. }, ..
|
||||
}, ..) => {
|
||||
header: ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
|
||||
ref decl,
|
||||
}, ref body) => {
|
||||
return self.visit_async_fn(
|
||||
ii.id,
|
||||
closure_id,
|
||||
return_impl_trait_id,
|
||||
ii.ident.name,
|
||||
ii.span,
|
||||
|this| visit::walk_impl_item(this, ii)
|
||||
header,
|
||||
&ii.generics,
|
||||
decl,
|
||||
body,
|
||||
)
|
||||
}
|
||||
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
|
|||
impl_stable_hash_for!(struct mir::LocalDecl<'tcx> {
|
||||
mutability,
|
||||
ty,
|
||||
user_ty,
|
||||
name,
|
||||
source_info,
|
||||
visibility_scope,
|
||||
|
|
@ -255,9 +256,10 @@ for mir::StatementKind<'gcx> {
|
|||
op.hash_stable(hcx, hasher);
|
||||
places.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::StatementKind::UserAssertTy(ref c_ty, ref local) => {
|
||||
mir::StatementKind::AscribeUserType(ref place, ref variance, ref c_ty) => {
|
||||
place.hash_stable(hcx, hasher);
|
||||
variance.hash_stable(hcx, hasher);
|
||||
c_ty.hash_stable(hcx, hasher);
|
||||
local.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::StatementKind::Nop => {}
|
||||
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1117,6 +1117,13 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
|
|||
}
|
||||
|
||||
fn visit_mac(&mut self, mac: &'a ast::Mac) {
|
||||
// FIXME(#54110): So, this setup isn't really right. I think
|
||||
// that (a) the libsyntax visitor ought to be doing this as
|
||||
// part of `walk_mac`, and (b) we should be calling
|
||||
// `visit_path`, *but* that would require a `NodeId`, and I
|
||||
// want to get #53686 fixed quickly. -nmatsakis
|
||||
ast_visit::walk_path(self, &mac.node.path);
|
||||
|
||||
run_lints!(self, check_mac, mac);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ use ty::query::Providers;
|
|||
use util::nodemap::NodeMap;
|
||||
|
||||
pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
|
||||
check_crate, check_ast_crate,
|
||||
check_crate, check_ast_crate, CheckLintNameResult,
|
||||
FutureIncompatibleInfo, BufferedEarlyLint};
|
||||
|
||||
/// Specification of a single lint.
|
||||
|
|
|
|||
|
|
@ -640,6 +640,12 @@ pub struct LocalDecl<'tcx> {
|
|||
/// Type of this local.
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
/// If the user manually ascribed a type to this variable,
|
||||
/// e.g. via `let x: T`, then we carry that type here. The MIR
|
||||
/// borrow checker needs this information since it can affect
|
||||
/// region inference.
|
||||
pub user_ty: Option<CanonicalTy<'tcx>>,
|
||||
|
||||
/// Name of the local, used in debuginfo and pretty-printing.
|
||||
///
|
||||
/// Note that function arguments can also have this set to `Some(_)`
|
||||
|
|
@ -802,6 +808,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||
LocalDecl {
|
||||
mutability,
|
||||
ty,
|
||||
user_ty: None,
|
||||
name: None,
|
||||
source_info: SourceInfo {
|
||||
span,
|
||||
|
|
@ -821,6 +828,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||
LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: return_ty,
|
||||
user_ty: None,
|
||||
source_info: SourceInfo {
|
||||
span,
|
||||
scope: OUTERMOST_SOURCE_SCOPE,
|
||||
|
|
@ -1636,22 +1644,19 @@ pub enum StatementKind<'tcx> {
|
|||
/// (The starting point(s) arise implicitly from borrows.)
|
||||
EndRegion(region::Scope),
|
||||
|
||||
/// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect
|
||||
/// them. For example:
|
||||
/// Encodes a user's type ascription. These need to be preserved
|
||||
/// intact so that NLL can respect them. For example:
|
||||
///
|
||||
/// let (a, b): (T, U) = y;
|
||||
/// let a: T = y;
|
||||
///
|
||||
/// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y`
|
||||
/// is the right thing.
|
||||
/// The effect of this annotation is to relate the type `T_y` of the place `y`
|
||||
/// to the user-given type `T`. The effect depends on the specified variance:
|
||||
///
|
||||
/// `CanonicalTy` is used to capture "inference variables" from the user's types. For example:
|
||||
///
|
||||
/// let x: Vec<_> = ...;
|
||||
/// let y: &u32 = ...;
|
||||
///
|
||||
/// would result in `Vec<?0>` and `&'?0 u32` respectively (where `?0` is a canonicalized
|
||||
/// variable).
|
||||
UserAssertTy(CanonicalTy<'tcx>, Local),
|
||||
/// - `Covariant` -- requires that `T_y <: T`
|
||||
/// - `Contravariant` -- requires that `T_y :> T`
|
||||
/// - `Invariant` -- requires that `T_y == T`
|
||||
/// - `Bivariant` -- no effect
|
||||
AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
|
||||
|
||||
/// No-op. Useful for deleting instructions without affecting statement indices.
|
||||
Nop,
|
||||
|
|
@ -1728,8 +1733,8 @@ impl<'tcx> Debug for Statement<'tcx> {
|
|||
ref outputs,
|
||||
ref inputs,
|
||||
} => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs),
|
||||
UserAssertTy(ref c_ty, ref local) => {
|
||||
write!(fmt, "UserAssertTy({:?}, {:?})", c_ty, local)
|
||||
AscribeUserType(ref place, ref variance, ref c_ty) => {
|
||||
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
||||
}
|
||||
Nop => write!(fmt, "nop"),
|
||||
}
|
||||
|
|
@ -2616,6 +2621,7 @@ BraceStructTypeFoldableImpl! {
|
|||
is_user_variable,
|
||||
internal,
|
||||
ty,
|
||||
user_ty,
|
||||
name,
|
||||
source_info,
|
||||
visibility_scope,
|
||||
|
|
@ -2652,7 +2658,7 @@ EnumTypeFoldableImpl! {
|
|||
(StatementKind::InlineAsm) { asm, outputs, inputs },
|
||||
(StatementKind::Validate)(a, b),
|
||||
(StatementKind::EndRegion)(a),
|
||||
(StatementKind::UserAssertTy)(a, b),
|
||||
(StatementKind::AscribeUserType)(a, v, b),
|
||||
(StatementKind::Nop),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,11 +144,12 @@ macro_rules! make_mir_visitor {
|
|||
self.super_operand(operand, location);
|
||||
}
|
||||
|
||||
fn visit_user_assert_ty(&mut self,
|
||||
c_ty: & $($mutability)* CanonicalTy<'tcx>,
|
||||
local: & $($mutability)* Local,
|
||||
location: Location) {
|
||||
self.super_user_assert_ty(c_ty, local, location);
|
||||
fn visit_ascribe_user_ty(&mut self,
|
||||
place: & $($mutability)* Place<'tcx>,
|
||||
variance: & $($mutability)* ty::Variance,
|
||||
c_ty: & $($mutability)* CanonicalTy<'tcx>,
|
||||
location: Location) {
|
||||
self.super_ascribe_user_ty(place, variance, c_ty, location);
|
||||
}
|
||||
|
||||
fn visit_place(&mut self,
|
||||
|
|
@ -386,9 +387,12 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_operand(input, location);
|
||||
}
|
||||
}
|
||||
StatementKind::UserAssertTy(ref $($mutability)* c_ty,
|
||||
ref $($mutability)* local) => {
|
||||
self.visit_user_assert_ty(c_ty, local, location);
|
||||
StatementKind::AscribeUserType(
|
||||
ref $($mutability)* place,
|
||||
ref $($mutability)* variance,
|
||||
ref $($mutability)* c_ty,
|
||||
) => {
|
||||
self.visit_ascribe_user_ty(place, variance, c_ty, location);
|
||||
}
|
||||
StatementKind::Nop => {}
|
||||
}
|
||||
|
|
@ -629,12 +633,13 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
}
|
||||
|
||||
fn super_user_assert_ty(&mut self,
|
||||
c_ty: & $($mutability)* CanonicalTy<'tcx>,
|
||||
local: & $($mutability)* Local,
|
||||
location: Location) {
|
||||
fn super_ascribe_user_ty(&mut self,
|
||||
place: & $($mutability)* Place<'tcx>,
|
||||
_variance: & $($mutability)* ty::Variance,
|
||||
c_ty: & $($mutability)* CanonicalTy<'tcx>,
|
||||
location: Location) {
|
||||
self.visit_place(place, PlaceContext::Validate, location);
|
||||
self.visit_canonical_ty(c_ty);
|
||||
self.visit_local(local, PlaceContext::Validate, location);
|
||||
}
|
||||
|
||||
fn super_place(&mut self,
|
||||
|
|
@ -716,6 +721,7 @@ macro_rules! make_mir_visitor {
|
|||
let LocalDecl {
|
||||
mutability: _,
|
||||
ref $($mutability)* ty,
|
||||
ref $($mutability)* user_ty,
|
||||
name: _,
|
||||
ref $($mutability)* source_info,
|
||||
ref $($mutability)* visibility_scope,
|
||||
|
|
@ -727,6 +733,9 @@ macro_rules! make_mir_visitor {
|
|||
local,
|
||||
source_info: *source_info,
|
||||
});
|
||||
if let Some(user_ty) = user_ty {
|
||||
self.visit_canonical_ty(user_ty);
|
||||
}
|
||||
self.visit_source_info(source_info);
|
||||
self.visit_source_scope(visibility_scope);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,8 +356,8 @@ pub struct TypeckTables<'tcx> {
|
|||
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
|
||||
field_indices: ItemLocalMap<usize>,
|
||||
|
||||
/// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
|
||||
/// MIR.
|
||||
/// Stores the canonicalized types provided by the user. See also
|
||||
/// `AscribeUserType` statement in MIR.
|
||||
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
|
||||
|
||||
/// Stores the types for various nodes in the AST. Note that this table
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
|
|||
::ty::ClosureKind,
|
||||
::ty::IntVarValue,
|
||||
::ty::ParamTy,
|
||||
::ty::Variance,
|
||||
::syntax_pos::Span,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ const TAG_MASK: usize = 0b11;
|
|||
const TYPE_TAG: usize = 0b00;
|
||||
const REGION_TAG: usize = 0b01;
|
||||
|
||||
#[derive(Debug, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum UnpackedKind<'tcx> {
|
||||
Lifetime(ty::Region<'tcx>),
|
||||
Type(Ty<'tcx>),
|
||||
|
|
@ -74,17 +74,7 @@ impl<'tcx> UnpackedKind<'tcx> {
|
|||
|
||||
impl<'tcx> Ord for Kind<'tcx> {
|
||||
fn cmp(&self, other: &Kind) -> Ordering {
|
||||
match (self.unpack(), other.unpack()) {
|
||||
(UnpackedKind::Type(_), UnpackedKind::Lifetime(_)) => Ordering::Greater,
|
||||
|
||||
(UnpackedKind::Type(ty1), UnpackedKind::Type(ty2)) => {
|
||||
ty1.sty.cmp(&ty2.sty)
|
||||
}
|
||||
|
||||
(UnpackedKind::Lifetime(reg1), UnpackedKind::Lifetime(reg2)) => reg1.cmp(reg2),
|
||||
|
||||
(UnpackedKind::Lifetime(_), UnpackedKind::Type(_)) => Ordering::Less,
|
||||
}
|
||||
self.unpack().cmp(&other.unpack())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
|||
use rustc::session::Session;
|
||||
use rustc::session::config::Sanitizer;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::layout::HasTyCtxt;
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
@ -32,12 +33,16 @@ use value::Value;
|
|||
|
||||
/// Mark LLVM function to use provided inline heuristic.
|
||||
#[inline]
|
||||
pub fn inline(val: &'ll Value, inline: InlineAttr) {
|
||||
pub fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
|
||||
use self::InlineAttr::*;
|
||||
match inline {
|
||||
Hint => Attribute::InlineHint.apply_llfn(Function, val),
|
||||
Always => Attribute::AlwaysInline.apply_llfn(Function, val),
|
||||
Never => Attribute::NoInline.apply_llfn(Function, val),
|
||||
Never => {
|
||||
if cx.tcx().sess.target.target.arch != "amdgpu" {
|
||||
Attribute::NoInline.apply_llfn(Function, val);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
Attribute::InlineHint.unapply_llfn(Function, val);
|
||||
Attribute::AlwaysInline.unapply_llfn(Function, val);
|
||||
|
|
@ -143,7 +148,7 @@ pub fn from_fn_attrs(
|
|||
let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id))
|
||||
.unwrap_or(CodegenFnAttrs::new());
|
||||
|
||||
inline(llfn, codegen_fn_attrs.inline);
|
||||
inline(cx, llfn, codegen_fn_attrs.inline);
|
||||
|
||||
// The `uwtable` attribute according to LLVM is:
|
||||
//
|
||||
|
|
|
|||
|
|
@ -496,6 +496,14 @@ impl Builder<'a, 'll, 'tcx> {
|
|||
|
||||
|
||||
pub fn range_metadata(&self, load: &'ll Value, range: Range<u128>) {
|
||||
if self.sess().target.target.arch == "amdgpu" {
|
||||
// amdgpu/LLVM does something weird and thinks a i64 value is
|
||||
// split into a v2i32, halving the bitwidth LLVM expects,
|
||||
// tripping an assertion. So, for now, just disable this
|
||||
// optimization.
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let llty = val_ty(load);
|
||||
let v = [
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ pub fn get_fn(
|
|||
debug!("get_fn: not casting pointer!");
|
||||
|
||||
if instance.def.is_inline(tcx) {
|
||||
attributes::inline(llfn, attributes::InlineAttr::Hint);
|
||||
attributes::inline(cx, llfn, attributes::InlineAttr::Hint);
|
||||
}
|
||||
attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()));
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
|
|||
mir::StatementKind::ReadForMatch(_) |
|
||||
mir::StatementKind::EndRegion(_) |
|
||||
mir::StatementKind::Validate(..) |
|
||||
mir::StatementKind::UserAssertTy(..) |
|
||||
mir::StatementKind::AscribeUserType(..) |
|
||||
mir::StatementKind::Nop => bx,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
|||
|
||||
debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
|
||||
if instance.def.is_inline(cx.tcx) {
|
||||
attributes::inline(lldecl, attributes::InlineAttr::Hint);
|
||||
attributes::inline(cx, lldecl, attributes::InlineAttr::Hint);
|
||||
}
|
||||
attributes::from_fn_attrs(cx, lldecl, Some(instance.def.def_id()));
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
macro_rules! add_pre_expansion_builtin {
|
||||
($sess:ident, $($name:ident),*,) => (
|
||||
{$(
|
||||
store.register_early_pass($sess, false, box $name);
|
||||
store.register_pre_expansion_pass($sess, box $name);
|
||||
)*}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ fn main() {
|
|||
let is_crossed = target != host;
|
||||
|
||||
let mut optional_components =
|
||||
vec!["x86", "arm", "aarch64", "mips", "powerpc",
|
||||
vec!["x86", "arm", "aarch64", "amdgpu", "mips", "powerpc",
|
||||
"systemz", "jsbackend", "webassembly", "msp430", "sparc", "nvptx"];
|
||||
|
||||
let mut version_cmd = Command::new(&llvm_config);
|
||||
|
|
|
|||
|
|
@ -535,10 +535,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||
// flow_state already handled).
|
||||
}
|
||||
StatementKind::Nop
|
||||
| StatementKind::UserAssertTy(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Validate(..)
|
||||
| StatementKind::StorageLive(..) => {
|
||||
// `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
|
||||
// `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
|
||||
// to borrow check.
|
||||
}
|
||||
StatementKind::StorageDead(local) => {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use rustc::infer::InferCtxt;
|
|||
use rustc::mir::visit::TyContext;
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
|
||||
use rustc::mir::{Local, Statement, Terminator};
|
||||
use rustc::mir::{Statement, Terminator};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid};
|
||||
|
|
@ -175,10 +175,11 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
|
|||
self.super_terminator(block, terminator, location);
|
||||
}
|
||||
|
||||
fn visit_user_assert_ty(
|
||||
fn visit_ascribe_user_ty(
|
||||
&mut self,
|
||||
_place: &Place<'tcx>,
|
||||
_variance: &ty::Variance,
|
||||
_c_ty: &CanonicalTy<'tcx>,
|
||||
_local: &Local,
|
||||
_location: Location,
|
||||
) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,10 +144,10 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc
|
|||
// EndRegion matters to older NLL/MIR AST borrowck, not to alias NLL
|
||||
StatementKind::EndRegion(..) |
|
||||
StatementKind::Nop |
|
||||
StatementKind::UserAssertTy(..) |
|
||||
StatementKind::AscribeUserType(..) |
|
||||
StatementKind::Validate(..) |
|
||||
StatementKind::StorageLive(..) => {
|
||||
// `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
|
||||
// `Nop`, `AscribeUserType`, `Validate`, and `StorageLive` are irrelevant
|
||||
// to borrow check.
|
||||
}
|
||||
StatementKind::StorageDead(local) => {
|
||||
|
|
|
|||
|
|
@ -319,23 +319,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
for variable in self.definitions.indices() {
|
||||
let scc = self.constraint_sccs.scc(variable);
|
||||
|
||||
match self.definitions[variable].origin {
|
||||
NLLRegionVariableOrigin::FreeRegion => {
|
||||
// For each free, universally quantified region X:
|
||||
|
||||
// Add all nodes in the CFG to liveness constraints
|
||||
let variable_scc = self.constraint_sccs.scc(variable);
|
||||
self.liveness_constraints.add_all_points(variable);
|
||||
self.scc_values.add_all_points(variable_scc);
|
||||
self.scc_values.add_all_points(scc);
|
||||
|
||||
// Add `end(X)` into the set for X.
|
||||
self.add_element_to_scc_of(variable, variable);
|
||||
self.scc_values.add_element(scc, variable);
|
||||
}
|
||||
|
||||
NLLRegionVariableOrigin::BoundRegion(ui) => {
|
||||
// Each placeholder region X outlives its
|
||||
// associated universe but nothing else.
|
||||
self.add_element_to_scc_of(variable, ui);
|
||||
// associated universe but nothing else. Every
|
||||
// placeholder region is always in a universe that
|
||||
// contains `ui` -- but when placeholder regions
|
||||
// are placed into an SCC, that SCC may include
|
||||
// things from other universes that do not include
|
||||
// `ui`.
|
||||
let scc_universe = self.scc_universes[scc];
|
||||
if ui.is_subset_of(scc_universe) {
|
||||
self.scc_values.add_element(scc, ui);
|
||||
} else {
|
||||
self.add_incompatible_universe(scc);
|
||||
}
|
||||
}
|
||||
|
||||
NLLRegionVariableOrigin::Existential => {
|
||||
|
|
@ -383,13 +394,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
self.scc_universes[scc]
|
||||
}
|
||||
|
||||
/// Adds `elem` to the value of the SCC in which `v` appears.
|
||||
fn add_element_to_scc_of(&mut self, v: RegionVid, elem: impl ToElementIndex) {
|
||||
debug!("add_live_element({:?}, {:?})", v, elem);
|
||||
let scc = self.constraint_sccs.scc(v);
|
||||
self.scc_values.add_element(scc, elem);
|
||||
}
|
||||
|
||||
/// Perform region inference and report errors if we see any
|
||||
/// unsatisfiable constraints. If this is a closure, returns the
|
||||
/// region requirements to propagate to our creator, if any.
|
||||
|
|
@ -516,22 +520,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// merge the bits.
|
||||
self.scc_values.add_region(scc_a, scc_b);
|
||||
} else {
|
||||
// Otherwise, the only way for `A` to outlive `B`
|
||||
// is for it to outlive static. This is actually stricter
|
||||
// than necessary: ideally, we'd support bounds like `for<'a: 'b`>`
|
||||
// that might then allow us to approximate `'a` with `'b` and not
|
||||
// `'static`. But it will have to do for now.
|
||||
//
|
||||
// The code here is a bit hacky: we grab the current
|
||||
// value of the SCC in which `'static` appears, but
|
||||
// this value may not be fully computed yet. That's ok
|
||||
// though: it will contain the base liveness values,
|
||||
// which include (a) the static free region element
|
||||
// and (b) all the points in the CFG, so it is "good
|
||||
// enough" to bring it in here for our purposes.
|
||||
let fr_static = self.universal_regions.fr_static;
|
||||
let scc_static = constraint_sccs.scc(fr_static);
|
||||
self.scc_values.add_region(scc_a, scc_static);
|
||||
self.add_incompatible_universe(scc_a);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -563,6 +552,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
.all(|u| u.is_subset_of(universe_a))
|
||||
}
|
||||
|
||||
/// Extend `scc` so that it can outlive some placeholder region
|
||||
/// from a universe it can't name; at present, the only way for
|
||||
/// this to be true is if `scc` outlives `'static`. This is
|
||||
/// actually stricter than necessary: ideally, we'd support bounds
|
||||
/// like `for<'a: 'b`>` that might then allow us to approximate
|
||||
/// `'a` with `'b` and not `'static`. But it will have to do for
|
||||
/// now.
|
||||
fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
|
||||
let fr_static = self.universal_regions.fr_static;
|
||||
self.scc_values.add_all_points(scc);
|
||||
self.scc_values.add_element(scc, fr_static);
|
||||
}
|
||||
|
||||
/// Once regions have been propagated, this method is used to see
|
||||
/// whether the "type tests" produced by typeck were satisfied;
|
||||
/// type tests encode type-outlives relationships like `T:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
|
||||
use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
|
||||
use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
|
||||
use rustc::mir::visit::{MutVisitor, TyContext};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
|
||||
|
|
@ -112,8 +112,13 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
|
|||
debug!("visit_closure_substs: substs={:?}", substs);
|
||||
}
|
||||
|
||||
fn visit_user_assert_ty(&mut self, _c_ty: &mut CanonicalTy<'tcx>, _local: &mut Local,
|
||||
_location: Location) {
|
||||
fn visit_ascribe_user_ty(
|
||||
&mut self,
|
||||
_place: &mut Place<'tcx>,
|
||||
_variance: &mut ty::Variance,
|
||||
_c_ty: &mut CanonicalTy<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
// User-assert-ty statements represent types that the user added explicitly.
|
||||
// We don't want to erase the regions from these types: rather, we want to
|
||||
// add them as constraints at type-check time.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
|
|||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
|
||||
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
|
||||
use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
|
||||
use borrow_check::nll::type_check::free_region_relations::{
|
||||
CreateResult, UniversalRegionRelations,
|
||||
};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use dataflow::move_paths::MoveData;
|
||||
|
|
@ -246,10 +248,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
self.sanitize_type(constant, constant.ty);
|
||||
|
||||
if let Some(user_ty) = constant.user_ty {
|
||||
if let Err(terr) =
|
||||
self.cx
|
||||
.eq_canonical_type_and_type(user_ty, constant.ty, location.boring())
|
||||
{
|
||||
if let Err(terr) = self.cx.relate_type_and_user_type(
|
||||
constant.ty,
|
||||
ty::Variance::Invariant,
|
||||
user_ty,
|
||||
location.boring(),
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
constant,
|
||||
|
|
@ -271,6 +275,25 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
self.super_local_decl(local, local_decl);
|
||||
self.sanitize_type(local_decl, local_decl.ty);
|
||||
|
||||
if let Some(user_ty) = local_decl.user_ty {
|
||||
if let Err(terr) = self.cx.relate_type_and_user_type(
|
||||
local_decl.ty,
|
||||
ty::Variance::Invariant,
|
||||
user_ty,
|
||||
Locations::All,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
local,
|
||||
"bad user type on variable {:?}: {:?} != {:?} ({:?})",
|
||||
local,
|
||||
local_decl.ty,
|
||||
local_decl.user_ty,
|
||||
terr,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
|
||||
|
|
@ -850,15 +873,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
fn eq_canonical_type_and_type(
|
||||
fn relate_type_and_user_type(
|
||||
&mut self,
|
||||
a: CanonicalTy<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
v: ty::Variance,
|
||||
b: CanonicalTy<'tcx>,
|
||||
locations: Locations,
|
||||
) -> Fallible<()> {
|
||||
relate_tys::eq_canonical_type_and_type(
|
||||
relate_tys::relate_type_and_user_type(
|
||||
self.infcx,
|
||||
a,
|
||||
v,
|
||||
b,
|
||||
locations,
|
||||
self.borrowck_context.as_mut().map(|x| &mut **x),
|
||||
|
|
@ -879,8 +904,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
// of lowering. Assignments to other sorts of places *are* interesting
|
||||
// though.
|
||||
let is_temp = if let Place::Local(l) = *place {
|
||||
l != RETURN_PLACE &&
|
||||
!mir.local_decls[l].is_user_variable.is_some()
|
||||
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
|
@ -905,9 +929,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
if let Some(user_ty) = self.rvalue_user_ty(rv) {
|
||||
if let Err(terr) = self.eq_canonical_type_and_type(
|
||||
user_ty,
|
||||
if let Err(terr) = self.relate_type_and_user_type(
|
||||
rv_ty,
|
||||
ty::Variance::Invariant,
|
||||
user_ty,
|
||||
location.boring(),
|
||||
) {
|
||||
span_mirbug!(
|
||||
|
|
@ -955,15 +980,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
);
|
||||
};
|
||||
}
|
||||
StatementKind::UserAssertTy(c_ty, local) => {
|
||||
let local_ty = mir.local_decls()[local].ty;
|
||||
if let Err(terr) = self.eq_canonical_type_and_type(c_ty, local_ty, Locations::All) {
|
||||
StatementKind::AscribeUserType(ref place, variance, c_ty) => {
|
||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||
if let Err(terr) =
|
||||
self.relate_type_and_user_type(place_ty, variance, c_ty, Locations::All)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
"bad type assert ({:?} = {:?}): {:?}",
|
||||
"bad type assert ({:?} <: {:?}): {:?}",
|
||||
place_ty,
|
||||
c_ty,
|
||||
local_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
|
|
@ -1142,8 +1169,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
Some((ref dest, _target_block)) => {
|
||||
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
|
||||
let is_temp = if let Place::Local(l) = *dest {
|
||||
l != RETURN_PLACE &&
|
||||
!mir.local_decls[l].is_user_variable.is_some()
|
||||
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
|
@ -1562,22 +1588,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
/// If this rvalue supports a user-given type annotation, then
|
||||
/// extract and return it. This represents the final type of the
|
||||
/// rvalue and will be unified with the inferred type.
|
||||
fn rvalue_user_ty(
|
||||
&self,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
) -> Option<CanonicalTy<'tcx>> {
|
||||
fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<CanonicalTy<'tcx>> {
|
||||
match rvalue {
|
||||
Rvalue::Use(_) |
|
||||
Rvalue::Repeat(..) |
|
||||
Rvalue::Ref(..) |
|
||||
Rvalue::Len(..) |
|
||||
Rvalue::Cast(..) |
|
||||
Rvalue::BinaryOp(..) |
|
||||
Rvalue::CheckedBinaryOp(..) |
|
||||
Rvalue::NullaryOp(..) |
|
||||
Rvalue::UnaryOp(..) |
|
||||
Rvalue::Discriminant(..) =>
|
||||
None,
|
||||
Rvalue::Use(_)
|
||||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Ref(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::Cast(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
| Rvalue::NullaryOp(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
| Rvalue::Discriminant(..) => None,
|
||||
|
||||
Rvalue::Aggregate(aggregate, _) => match **aggregate {
|
||||
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
|
||||
|
|
@ -1585,7 +1607,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
AggregateKind::Tuple => None,
|
||||
AggregateKind::Closure(_, _) => None,
|
||||
AggregateKind::Generator(_, _, _) => None,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ use rustc::ty::subst::Kind;
|
|||
use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use std::mem;
|
||||
|
||||
/// Adds sufficient constraints to ensure that `a <: b`.
|
||||
pub(super) fn sub_types<'tcx>(
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
|
|
@ -41,6 +41,7 @@ pub(super) fn sub_types<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds sufficient constraints to ensure that `a == b`.
|
||||
pub(super) fn eq_types<'tcx>(
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
|
|
@ -59,28 +60,38 @@ pub(super) fn eq_types<'tcx>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn eq_canonical_type_and_type<'tcx>(
|
||||
/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
|
||||
/// a user-given type (which means it may have canonical variables
|
||||
/// encoding things like `_`).
|
||||
pub(super) fn relate_type_and_user_type<'tcx>(
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
a: CanonicalTy<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
v: ty::Variance,
|
||||
b: CanonicalTy<'tcx>,
|
||||
locations: Locations,
|
||||
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
|
||||
) -> Fallible<()> {
|
||||
debug!(
|
||||
"eq_canonical_type_and_type(a={:?}, b={:?}, locations={:?})",
|
||||
"sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
|
||||
a, b, locations
|
||||
);
|
||||
let Canonical {
|
||||
variables: a_variables,
|
||||
value: a_value,
|
||||
} = a;
|
||||
variables: b_variables,
|
||||
value: b_value,
|
||||
} = b;
|
||||
|
||||
// The `TypeRelating` code assumes that the "canonical variables"
|
||||
// appear in the "a" side, so flip `Contravariant` ambient
|
||||
// variance to get the right relationship.
|
||||
let v1 = ty::Contravariant.xform(v);
|
||||
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
ty::Variance::Invariant,
|
||||
v1,
|
||||
locations,
|
||||
borrowck_context,
|
||||
a_variables,
|
||||
).relate(&a_value, &b)?;
|
||||
b_variables,
|
||||
).relate(&b_value, &a)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +139,7 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
|||
/// how can we enforce that? I guess I could add some kind of
|
||||
/// "minimum universe constraint" that we can feed to the NLL checker.
|
||||
/// --> also, we know this doesn't happen
|
||||
canonical_var_values: IndexVec<CanonicalVar, Option<ScopesAndKind<'tcx>>>,
|
||||
canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -194,23 +205,44 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
scope
|
||||
}
|
||||
|
||||
/// When we encounter binders during the type traversal, we record
|
||||
/// the value to substitute for each of the things contained in
|
||||
/// that binder. (This will be either a universal placeholder or
|
||||
/// an existential inference variable.) Given the debruijn index
|
||||
/// `debruijn` (and name `br`) of some binder we have now
|
||||
/// encountered, this routine finds the value that we instantiated
|
||||
/// the region with; to do so, it indexes backwards into the list
|
||||
/// of ambient scopes `scopes`.
|
||||
fn lookup_bound_region(
|
||||
debruijn: ty::DebruijnIndex,
|
||||
br: &ty::BoundRegion,
|
||||
first_free_index: ty::DebruijnIndex,
|
||||
scopes: &[BoundRegionScope],
|
||||
) -> RegionVid {
|
||||
// The debruijn index is a "reverse index" into the
|
||||
// scopes listing. So when we have INNERMOST (0), we
|
||||
// want the *last* scope pushed, and so forth.
|
||||
let debruijn_index = debruijn.index() - first_free_index.index();
|
||||
let scope = &scopes[scopes.len() - debruijn_index - 1];
|
||||
|
||||
// Find this bound region in that scope to map to a
|
||||
// particular region.
|
||||
scope.map[br]
|
||||
}
|
||||
|
||||
/// If `r` is a bound region, find the scope in which it is bound
|
||||
/// (from `scopes`) and return the value that we instantiated it
|
||||
/// with. Otherwise just return `r`.
|
||||
fn replace_bound_region(
|
||||
&self,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
first_free_index: ty::DebruijnIndex,
|
||||
scopes: &[BoundRegionScope],
|
||||
) -> RegionVid {
|
||||
match r {
|
||||
ty::ReLateBound(debruijn, br) => {
|
||||
// The debruijn index is a "reverse index" into the
|
||||
// scopes listing. So when we have INNERMOST (0), we
|
||||
// want the *last* scope pushed, and so forth.
|
||||
let debruijn_index = debruijn.index() - ty::INNERMOST.index();
|
||||
let scope = &scopes[scopes.len() - debruijn_index - 1];
|
||||
|
||||
// Find this bound region in that scope to map to a
|
||||
// particular region.
|
||||
scope.map[br]
|
||||
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
|
||||
}
|
||||
|
||||
ty::ReVar(v) => *v,
|
||||
|
|
@ -219,6 +251,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Push a new outlives requirement into our output set of
|
||||
/// constraints.
|
||||
fn push_outlives(&mut self, sup: RegionVid, sub: RegionVid) {
|
||||
debug!("push_outlives({:?}: {:?})", sup, sub);
|
||||
|
||||
|
|
@ -236,46 +270,55 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn equate_var(
|
||||
/// When we encounter a canonical variable `var` in the output,
|
||||
/// equate it with `kind`. If the variable has been previously
|
||||
/// equated, then equate it again.
|
||||
fn relate_var(
|
||||
&mut self,
|
||||
var: CanonicalVar,
|
||||
b_kind: Kind<'tcx>,
|
||||
) -> RelateResult<'tcx, Kind<'tcx>> {
|
||||
debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
|
||||
|
||||
// We only encounter canonical variables when equating.
|
||||
assert_eq!(self.ambient_variance, ty::Variance::Invariant);
|
||||
let generalized_kind = match self.canonical_var_values[var] {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
let generalized_kind = self.generalize_value(b_kind);
|
||||
self.canonical_var_values[var] = Some(generalized_kind);
|
||||
generalized_kind
|
||||
}
|
||||
};
|
||||
|
||||
// The canonical variable already had a value. Equate that
|
||||
// value with `b`.
|
||||
let old_value = self.canonical_var_values[var].clone();
|
||||
if let Some(ScopesAndKind { scopes, kind }) = old_value {
|
||||
debug!("equate_var: installing kind={:?} scopes={:?}", kind, scopes);
|
||||
let old_a_scopes = mem::replace(&mut self.a_scopes, scopes);
|
||||
let result = self.relate(&kind, &b_kind);
|
||||
self.a_scopes = old_a_scopes;
|
||||
debug!("equate_var: complete, result = {:?}", result);
|
||||
return result;
|
||||
}
|
||||
// The generalized values we extract from `canonical_var_values` have
|
||||
// been fully instantiated and hence the set of scopes we have
|
||||
// doesn't matter -- just to be sure, put an empty vector
|
||||
// in there.
|
||||
let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
|
||||
|
||||
// Not yet. Capture the value from the RHS and carry on.
|
||||
self.canonical_var_values[var] = Some(ScopesAndKind {
|
||||
scopes: self.b_scopes.clone(),
|
||||
kind: b_kind,
|
||||
});
|
||||
debug!(
|
||||
"equate_var: capturing value {:?}",
|
||||
self.canonical_var_values[var]
|
||||
);
|
||||
// Relate the generalized kind to the original one.
|
||||
let result = self.relate(&generalized_kind, &b_kind);
|
||||
|
||||
// FIXME -- technically, we should add some sort of
|
||||
// assertion that this value can be named in the universe
|
||||
// of the canonical variable. But in practice these
|
||||
// canonical variables only arise presently in cases where
|
||||
// they are in the root universe and the main typeck has
|
||||
// ensured there are no universe errors. So we just kind
|
||||
// of over look this right now.
|
||||
Ok(b_kind)
|
||||
// Restore the old scopes now.
|
||||
self.a_scopes = old_a_scopes;
|
||||
|
||||
debug!("equate_var: complete, result = {:?}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn generalize_value(
|
||||
&self,
|
||||
kind: Kind<'tcx>,
|
||||
) -> Kind<'tcx> {
|
||||
TypeGeneralizer {
|
||||
type_rel: self,
|
||||
first_free_index: ty::INNERMOST,
|
||||
ambient_variance: self.ambient_variance,
|
||||
|
||||
// These always correspond to an `_` or `'_` written by
|
||||
// user, and those are always in the root universe.
|
||||
universe: ty::UniverseIndex::ROOT,
|
||||
}.relate(&kind, &kind)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +369,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
// Watch out for the case that we are matching a `?T` against the
|
||||
// right-hand side.
|
||||
if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
|
||||
self.equate_var(var, b.into())?;
|
||||
self.relate_var(var, b.into())?;
|
||||
Ok(a)
|
||||
} else {
|
||||
debug!(
|
||||
|
|
@ -348,7 +391,7 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
}) = self.borrowck_context
|
||||
{
|
||||
if let ty::ReCanonical(var) = a {
|
||||
self.equate_var(*var, b.into())?;
|
||||
self.relate_var(*var, b.into())?;
|
||||
return Ok(a);
|
||||
}
|
||||
|
||||
|
|
@ -357,8 +400,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
a, b, self.ambient_variance
|
||||
);
|
||||
|
||||
let v_a = self.replace_bound_region(universal_regions, a, &self.a_scopes);
|
||||
let v_b = self.replace_bound_region(universal_regions, b, &self.b_scopes);
|
||||
let v_a =
|
||||
self.replace_bound_region(universal_regions, a, ty::INNERMOST, &self.a_scopes);
|
||||
let v_b =
|
||||
self.replace_bound_region(universal_regions, b, ty::INNERMOST, &self.b_scopes);
|
||||
|
||||
debug!("regions: v_a = {:?}", v_a);
|
||||
debug!("regions: v_b = {:?}", v_b);
|
||||
|
|
@ -425,19 +470,30 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
self.b_scopes.push(b_scope);
|
||||
self.a_scopes.push(a_scope);
|
||||
|
||||
// FIXME -- to be fully correct, we would set the ambient
|
||||
// variance to Covariant here. As is, we will sometimes
|
||||
// propagate down an ambient variance of Equal -- this in
|
||||
// turn causes us to report errors in some cases where
|
||||
// types perhaps *ought* to be equal. See the
|
||||
// `hr-fn-aau-eq-abu.rs` test for an example. Fixing this
|
||||
// though is a bit nontrivial: in particular, it would
|
||||
// require a more involved handling of canonical
|
||||
// variables, since we would no longer be able to rely on
|
||||
// having an `==` relationship for canonical variables.
|
||||
// Reset the ambient variance to covariant. This is needed
|
||||
// to correctly handle cases like
|
||||
//
|
||||
// for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
|
||||
//
|
||||
// Somewhat surprisingly, these two types are actually
|
||||
// **equal**, even though the one on the right looks more
|
||||
// polymorphic. The reason is due to subtyping. To see it,
|
||||
// consider that each function can call the other:
|
||||
//
|
||||
// - The left function can call the right with `'b` and
|
||||
// `'c` both equal to `'a`
|
||||
//
|
||||
// - The right function can call the left with `'a` set to
|
||||
// `{P}`, where P is the point in the CFG where the call
|
||||
// itself occurs. Note that `'b` and `'c` must both
|
||||
// include P. At the point, the call works because of
|
||||
// subtyping (i.e., `&'b u32 <: &{P} u32`).
|
||||
let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
|
||||
|
||||
self.relate(a.skip_binder(), b.skip_binder())?;
|
||||
|
||||
self.ambient_variance = variance;
|
||||
|
||||
self.b_scopes.pop().unwrap();
|
||||
self.a_scopes.pop().unwrap();
|
||||
}
|
||||
|
|
@ -458,8 +514,17 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
self.a_scopes.push(a_scope);
|
||||
self.b_scopes.push(b_scope);
|
||||
|
||||
// Reset ambient variance to contravariance. See the
|
||||
// covariant case above for an explanation.
|
||||
let variance = ::std::mem::replace(
|
||||
&mut self.ambient_variance,
|
||||
ty::Variance::Contravariant,
|
||||
);
|
||||
|
||||
self.relate(a.skip_binder(), b.skip_binder())?;
|
||||
|
||||
self.ambient_variance = variance;
|
||||
|
||||
self.b_scopes.pop().unwrap();
|
||||
self.a_scopes.pop().unwrap();
|
||||
}
|
||||
|
|
@ -468,7 +533,14 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
}
|
||||
}
|
||||
|
||||
struct ScopeInstantiator<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
|
||||
/// When we encounter a binder like `for<..> fn(..)`, we actually have
|
||||
/// to walk the `fn` value to find all the values bound by the `for`
|
||||
/// (these are not explicitly present in the ty representation right
|
||||
/// now). This visitor handles that: it descends the type, tracking
|
||||
/// binder depth, and finds late-bound regions targeting the
|
||||
/// `for<..`>. For each of those, it creates an entry in
|
||||
/// `bound_region_scope`.
|
||||
struct ScopeInstantiator<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
// The debruijn index of the scope we are instantiating.
|
||||
target_index: ty::DebruijnIndex,
|
||||
|
|
@ -510,3 +582,143 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// The "type generalize" is used when handling inference variables.
|
||||
///
|
||||
/// The basic strategy for handling a constraint like `?A <: B` is to
|
||||
/// apply a "generalization strategy" to the type `B` -- this replaces
|
||||
/// all the lifetimes in the type `B` with fresh inference
|
||||
/// variables. (You can read more about the strategy in this [blog
|
||||
/// post].)
|
||||
///
|
||||
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
|
||||
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
|
||||
/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
|
||||
/// establishes `'0: 'x` as a constraint.
|
||||
///
|
||||
/// As a side-effect of this generalization procedure, we also replace
|
||||
/// all the bound regions that we have traversed with concrete values,
|
||||
/// so that the resulting generalized type is independent from the
|
||||
/// scopes.
|
||||
///
|
||||
/// [blog post]: https://is.gd/0hKvIr
|
||||
struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
||||
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
|
||||
|
||||
/// After we generalize this type, we are going to relative it to
|
||||
/// some other type. What will be the variance at this point?
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
first_free_index: ty::DebruijnIndex,
|
||||
|
||||
universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
|
||||
self.type_rel.infcx.tcx
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
"nll::generalizer"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
a: &T,
|
||||
b: &T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
debug!(
|
||||
"TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
|
||||
variance, a, b
|
||||
);
|
||||
|
||||
let old_ambient_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||
|
||||
debug!(
|
||||
"TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
|
||||
self.ambient_variance
|
||||
);
|
||||
|
||||
let r = self.relate(a, b)?;
|
||||
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
|
||||
debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
debug!("TypeGeneralizer::tys(a={:?})", a,);
|
||||
|
||||
match a.sty {
|
||||
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
|
||||
bug!(
|
||||
"unexpected inference variable encountered in NLL generalization: {:?}",
|
||||
a
|
||||
);
|
||||
}
|
||||
|
||||
_ => relate::super_relate_tys(self, a, a),
|
||||
}
|
||||
}
|
||||
|
||||
fn regions(
|
||||
&mut self,
|
||||
a: ty::Region<'tcx>,
|
||||
_: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
debug!("TypeGeneralizer::regions(a={:?})", a,);
|
||||
|
||||
if let ty::ReLateBound(debruijn, _) = a {
|
||||
if *debruijn < self.first_free_index {
|
||||
return Ok(a);
|
||||
}
|
||||
}
|
||||
|
||||
// For now, we just always create a fresh region variable to
|
||||
// replace all the regions in the source type. In the main
|
||||
// type checker, we special case the case where the ambient
|
||||
// variance is `Invariant` and try to avoid creating a fresh
|
||||
// region variable, but since this comes up so much less in
|
||||
// NLL (only when users use `_` etc) it is much less
|
||||
// important.
|
||||
//
|
||||
// As an aside, since these new variables are created in
|
||||
// `self.universe` universe, this also serves to enforce the
|
||||
// universe scoping rules.
|
||||
//
|
||||
// FIXME(#54105) -- if the ambient variance is bivariant,
|
||||
// though, we may however need to check well-formedness or
|
||||
// risk a problem like #41677 again.
|
||||
|
||||
let replacement_region_vid = self.type_rel
|
||||
.infcx
|
||||
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
|
||||
|
||||
Ok(replacement_region_vid)
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: &ty::Binder<T>,
|
||||
_: &ty::Binder<T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
debug!("TypeGeneralizer::binders(a={:?})", a,);
|
||||
|
||||
self.first_free_index.shift_in(1);
|
||||
let result = self.relate(a.skip_binder(), a.skip_binder())?;
|
||||
self.first_free_index.shift_out(1);
|
||||
Ok(ty::Binder::bind(result))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
remainder_scope,
|
||||
init_scope,
|
||||
pattern,
|
||||
ty,
|
||||
initializer,
|
||||
lint_level
|
||||
} => {
|
||||
|
|
@ -136,7 +135,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
|
||||
let scope = (init_scope, source_info);
|
||||
this.in_scope(scope, lint_level, block, |this| {
|
||||
this.expr_into_pattern(block, ty, pattern, init)
|
||||
this.expr_into_pattern(block, pattern, init)
|
||||
})
|
||||
}));
|
||||
} else {
|
||||
|
|
@ -144,16 +143,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
None, remainder_span, lint_level, slice::from_ref(&pattern),
|
||||
ArmHasGuard(false), None);
|
||||
|
||||
// FIXME(#47184): We currently only insert `UserAssertTy` statements for
|
||||
// patterns that are bindings, this is as we do not want to deconstruct
|
||||
// the type being assertion to match the pattern.
|
||||
if let PatternKind::Binding { var, .. } = *pattern.kind {
|
||||
if let Some(ty) = ty {
|
||||
this.user_assert_ty(block, ty, var, span);
|
||||
}
|
||||
}
|
||||
|
||||
this.visit_bindings(&pattern, &mut |this, _, _, _, node, span, _| {
|
||||
this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(block, node, span, OutsideGuard);
|
||||
this.schedule_drop_for_binding(node, span, OutsideGuard);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -296,6 +296,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let ptr_temp = this.local_decls.push(LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: ptr_ty,
|
||||
user_ty: None,
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -23,7 +23,7 @@
|
|||
//! testing a value against a constant.
|
||||
|
||||
use build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use build::matches::{Binding, MatchPair, Candidate};
|
||||
use build::matches::{Ascription, Binding, MatchPair, Candidate};
|
||||
use hair::*;
|
||||
use rustc::mir::*;
|
||||
|
||||
|
|
@ -63,6 +63,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
candidate: &mut Candidate<'pat, 'tcx>)
|
||||
-> Result<(), MatchPair<'pat, 'tcx>> {
|
||||
match *match_pair.pattern.kind {
|
||||
PatternKind::AscribeUserType { ref subpattern, user_ty } => {
|
||||
candidate.ascriptions.push(Ascription {
|
||||
span: match_pair.pattern.span,
|
||||
user_ty,
|
||||
source: match_pair.place.clone(),
|
||||
});
|
||||
|
||||
candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
PatternKind::Wild => {
|
||||
// nothing left to do
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -70,13 +70,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
PatternKind::Range { lo, hi, end } => {
|
||||
PatternKind::Range { lo, hi, ty, end } => {
|
||||
assert!(ty == match_pair.pattern.ty);
|
||||
Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Range {
|
||||
lo,
|
||||
hi,
|
||||
ty: match_pair.pattern.ty.clone(),
|
||||
ty,
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
|
@ -96,6 +97,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
PatternKind::AscribeUserType { .. } |
|
||||
PatternKind::Array { .. } |
|
||||
PatternKind::Slice { .. } |
|
||||
PatternKind::Wild |
|
||||
|
|
@ -138,6 +140,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
PatternKind::Array { .. } |
|
||||
PatternKind::Wild |
|
||||
PatternKind::Binding { .. } |
|
||||
PatternKind::AscribeUserType { .. } |
|
||||
PatternKind::Leaf { .. } |
|
||||
PatternKind::Deref { .. } => {
|
||||
// don't know how to add these patterns to a switch
|
||||
|
|
@ -638,6 +641,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
span: candidate.span,
|
||||
match_pairs: other_match_pairs,
|
||||
bindings: candidate.bindings.clone(),
|
||||
ascriptions: candidate.ascriptions.clone(),
|
||||
guard: candidate.guard.clone(),
|
||||
arm_index: candidate.arm_index,
|
||||
pat_index: candidate.pat_index,
|
||||
|
|
@ -702,6 +706,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
span: candidate.span,
|
||||
match_pairs: all_match_pairs,
|
||||
bindings: candidate.bindings.clone(),
|
||||
ascriptions: candidate.ascriptions.clone(),
|
||||
guard: candidate.guard.clone(),
|
||||
arm_index: candidate.arm_index,
|
||||
pat_index: candidate.pat_index,
|
||||
|
|
|
|||
|
|
@ -730,6 +730,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
self.local_decls.push(LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty,
|
||||
user_ty: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
|||
mir::StatementKind::SetDiscriminant { .. } |
|
||||
mir::StatementKind::StorageLive(..) |
|
||||
mir::StatementKind::Validate(..) |
|
||||
mir::StatementKind::UserAssertTy(..) |
|
||||
mir::StatementKind::AscribeUserType(..) |
|
||||
mir::StatementKind::Nop => {}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
}
|
||||
StatementKind::EndRegion(_) |
|
||||
StatementKind::Validate(..) |
|
||||
StatementKind::UserAssertTy(..) |
|
||||
StatementKind::AscribeUserType(..) |
|
||||
StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,14 +76,26 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
|||
first_statement_index: region::FirstStatementIndex::new(index),
|
||||
});
|
||||
|
||||
let ty = local.ty.clone().map(|ty| ty.hir_id);
|
||||
let pattern = cx.pattern_from_hir(&local.pat);
|
||||
let mut pattern = cx.pattern_from_hir(&local.pat);
|
||||
|
||||
if let Some(ty) = &local.ty {
|
||||
if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
|
||||
pattern = Pattern {
|
||||
ty: pattern.ty,
|
||||
span: pattern.span,
|
||||
kind: Box::new(PatternKind::AscribeUserType {
|
||||
user_ty: *user_ty,
|
||||
subpattern: pattern
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
result.push(StmtRef::Mirror(Box::new(Stmt {
|
||||
kind: StmtKind::Let {
|
||||
remainder_scope: remainder_scope,
|
||||
init_scope: region::Scope::Node(hir_id.local_id),
|
||||
pattern,
|
||||
ty,
|
||||
initializer: local.init.to_ref(),
|
||||
lint_level: cx.lint_level_of(local.id),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -93,12 +93,11 @@ pub enum StmtKind<'tcx> {
|
|||
/// lifetime of temporaries
|
||||
init_scope: region::Scope,
|
||||
|
||||
/// let <PAT>: ty = ...
|
||||
/// `let <PAT> = ...`
|
||||
///
|
||||
/// if a type is included, it is added as an ascription pattern
|
||||
pattern: Pattern<'tcx>,
|
||||
|
||||
/// let pat: <TY> = init ...
|
||||
ty: Option<hir::HirId>,
|
||||
|
||||
/// let pat: ty = <INIT> ...
|
||||
initializer: Option<ExprRef<'tcx>>,
|
||||
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ pub enum Constructor<'tcx> {
|
|||
/// Literal values.
|
||||
ConstantValue(&'tcx ty::Const<'tcx>),
|
||||
/// Ranges of literal values (`2...5` and `2..5`).
|
||||
ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
|
||||
ConstantRange(u128, u128, Ty<'tcx>, RangeEnd),
|
||||
/// Array patterns of length n.
|
||||
Slice(u64),
|
||||
}
|
||||
|
|
@ -588,7 +588,12 @@ impl<'tcx> Witness<'tcx> {
|
|||
_ => {
|
||||
match *ctor {
|
||||
ConstantValue(value) => PatternKind::Constant { value },
|
||||
ConstantRange(lo, hi, end) => PatternKind::Range { lo, hi, end },
|
||||
ConstantRange(lo, hi, ty, end) => PatternKind::Range {
|
||||
lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
|
||||
hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
|
||||
ty,
|
||||
end,
|
||||
},
|
||||
_ => PatternKind::Wild,
|
||||
}
|
||||
}
|
||||
|
|
@ -648,14 +653,18 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
|||
.collect()
|
||||
}
|
||||
ty::Char if exhaustive_integer_patterns => {
|
||||
let endpoint = |c: char| {
|
||||
let ty = ty::ParamEnv::empty().and(cx.tcx.types.char);
|
||||
ty::Const::from_bits(cx.tcx, c as u128, ty)
|
||||
};
|
||||
vec![
|
||||
// The valid Unicode Scalar Value ranges.
|
||||
ConstantRange(endpoint('\u{0000}'), endpoint('\u{D7FF}'), RangeEnd::Included),
|
||||
ConstantRange(endpoint('\u{E000}'), endpoint('\u{10FFFF}'), RangeEnd::Included),
|
||||
ConstantRange('\u{0000}' as u128,
|
||||
'\u{D7FF}' as u128,
|
||||
cx.tcx.types.char,
|
||||
RangeEnd::Included
|
||||
),
|
||||
ConstantRange('\u{E000}' as u128,
|
||||
'\u{10FFFF}' as u128,
|
||||
cx.tcx.types.char,
|
||||
RangeEnd::Included
|
||||
),
|
||||
]
|
||||
}
|
||||
ty::Int(ity) if exhaustive_integer_patterns => {
|
||||
|
|
@ -663,19 +672,13 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
|||
let bits = Integer::from_attr(cx.tcx, SignedInt(ity)).size().bits() as u128;
|
||||
let min = 1u128 << (bits - 1);
|
||||
let max = (1u128 << (bits - 1)) - 1;
|
||||
let ty = ty::ParamEnv::empty().and(pcx.ty);
|
||||
vec![ConstantRange(ty::Const::from_bits(cx.tcx, min as u128, ty),
|
||||
ty::Const::from_bits(cx.tcx, max as u128, ty),
|
||||
RangeEnd::Included)]
|
||||
vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included)]
|
||||
}
|
||||
ty::Uint(uty) if exhaustive_integer_patterns => {
|
||||
// FIXME(49937): refactor these bit manipulations into interpret.
|
||||
let bits = Integer::from_attr(cx.tcx, UnsignedInt(uty)).size().bits() as u128;
|
||||
let max = !0u128 >> (128 - bits);
|
||||
let ty = ty::ParamEnv::empty().and(pcx.ty);
|
||||
vec![ConstantRange(ty::Const::from_bits(cx.tcx, 0, ty),
|
||||
ty::Const::from_bits(cx.tcx, max, ty),
|
||||
RangeEnd::Included)]
|
||||
vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included)]
|
||||
}
|
||||
_ => {
|
||||
if cx.is_uninhabited(pcx.ty) {
|
||||
|
|
@ -811,26 +814,18 @@ impl<'tcx> IntRange<'tcx> {
|
|||
ctor: &Constructor<'tcx>)
|
||||
-> Option<IntRange<'tcx>> {
|
||||
match ctor {
|
||||
ConstantRange(lo, hi, end) => {
|
||||
assert_eq!(lo.ty, hi.ty);
|
||||
let ty = lo.ty;
|
||||
let env_ty = ty::ParamEnv::empty().and(ty);
|
||||
if let Some(lo) = lo.assert_bits(tcx, env_ty) {
|
||||
if let Some(hi) = hi.assert_bits(tcx, env_ty) {
|
||||
// Perform a shift if the underlying types are signed,
|
||||
// which makes the interval arithmetic simpler.
|
||||
let bias = IntRange::signed_bias(tcx, ty);
|
||||
let (lo, hi) = (lo ^ bias, hi ^ bias);
|
||||
// Make sure the interval is well-formed.
|
||||
return if lo > hi || lo == hi && *end == RangeEnd::Excluded {
|
||||
None
|
||||
} else {
|
||||
let offset = (*end == RangeEnd::Excluded) as u128;
|
||||
Some(IntRange { range: lo..=(hi - offset), ty })
|
||||
};
|
||||
}
|
||||
ConstantRange(lo, hi, ty, end) => {
|
||||
// Perform a shift if the underlying types are signed,
|
||||
// which makes the interval arithmetic simpler.
|
||||
let bias = IntRange::signed_bias(tcx, ty);
|
||||
let (lo, hi) = (lo ^ bias, hi ^ bias);
|
||||
// Make sure the interval is well-formed.
|
||||
if lo > hi || lo == hi && *end == RangeEnd::Excluded {
|
||||
None
|
||||
} else {
|
||||
let offset = (*end == RangeEnd::Excluded) as u128;
|
||||
Some(IntRange { range: lo..=(hi - offset), ty })
|
||||
}
|
||||
None
|
||||
}
|
||||
ConstantValue(val) => {
|
||||
let ty = val.ty;
|
||||
|
|
@ -853,7 +848,12 @@ impl<'tcx> IntRange<'tcx> {
|
|||
-> Option<IntRange<'tcx>> {
|
||||
Self::from_ctor(tcx, &match pat.kind {
|
||||
box PatternKind::Constant { value } => ConstantValue(value),
|
||||
box PatternKind::Range { lo, hi, end } => ConstantRange(lo, hi, end),
|
||||
box PatternKind::Range { lo, hi, ty, end } => ConstantRange(
|
||||
lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
|
||||
hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
|
||||
ty,
|
||||
end,
|
||||
),
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
|
@ -876,14 +876,12 @@ impl<'tcx> IntRange<'tcx> {
|
|||
r: RangeInclusive<u128>,
|
||||
) -> Constructor<'tcx> {
|
||||
let bias = IntRange::signed_bias(tcx, ty);
|
||||
let ty = ty::ParamEnv::empty().and(ty);
|
||||
let (lo, hi) = r.into_inner();
|
||||
if lo == hi {
|
||||
let ty = ty::ParamEnv::empty().and(ty);
|
||||
ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty))
|
||||
} else {
|
||||
ConstantRange(ty::Const::from_bits(tcx, lo ^ bias, ty),
|
||||
ty::Const::from_bits(tcx, hi ^ bias, ty),
|
||||
RangeEnd::Included)
|
||||
ConstantRange(lo ^ bias, hi ^ bias, ty, RangeEnd::Included)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1228,20 +1226,28 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>(
|
|||
/// Slice patterns, however, can match slices of different lengths. For instance,
|
||||
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
|
||||
///
|
||||
/// Returns `None` in case of a catch-all, which can't be specialized.
|
||||
fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
|
||||
/// Returns None in case of a catch-all, which can't be specialized.
|
||||
fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
||||
pat: &Pattern<'tcx>,
|
||||
pcx: PatternContext)
|
||||
-> Option<Vec<Constructor<'tcx>>>
|
||||
{
|
||||
match *pat.kind {
|
||||
PatternKind::AscribeUserType { ref subpattern, .. } =>
|
||||
pat_constructors(cx, subpattern, pcx),
|
||||
PatternKind::Binding { .. } | PatternKind::Wild => None,
|
||||
PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]),
|
||||
PatternKind::Variant { adt_def, variant_index, .. } => {
|
||||
Some(vec![Variant(adt_def.variants[variant_index].did)])
|
||||
}
|
||||
PatternKind::Constant { value } => Some(vec![ConstantValue(value)]),
|
||||
PatternKind::Range { lo, hi, end } => Some(vec![ConstantRange(lo, hi, end)]),
|
||||
PatternKind::Range { lo, hi, ty, end } =>
|
||||
Some(vec![ConstantRange(
|
||||
lo.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
|
||||
hi.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
|
||||
ty,
|
||||
end,
|
||||
)]),
|
||||
PatternKind::Array { .. } => match pcx.ty.sty {
|
||||
ty::Array(_, length) => Some(vec![
|
||||
Slice(length.unwrap_usize(cx.tcx))
|
||||
|
|
@ -1381,10 +1387,13 @@ fn slice_pat_covered_by_constructor<'tcx>(
|
|||
// constructor is a range or constant with an integer type.
|
||||
fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Constructor<'tcx>) -> bool {
|
||||
if tcx.features().exhaustive_integer_patterns {
|
||||
if let ConstantValue(value) | ConstantRange(value, _, _) = ctor {
|
||||
if let ty::Char | ty::Int(_) | ty::Uint(_) = value.ty.sty {
|
||||
return true;
|
||||
}
|
||||
let ty = match ctor {
|
||||
ConstantValue(value) => value.ty,
|
||||
ConstantRange(_, _, ty, _) => ty,
|
||||
_ => return false,
|
||||
};
|
||||
if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.sty {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
|
|
@ -1535,7 +1544,7 @@ fn constructor_covered_by_range<'a, 'tcx>(
|
|||
) -> Result<bool, ErrorReported> {
|
||||
let (from, to, end, ty) = match pat.kind {
|
||||
box PatternKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
|
||||
box PatternKind::Range { lo, hi, end } => (lo, hi, end, lo.ty),
|
||||
box PatternKind::Range { lo, hi, ty, end } => (lo, hi, end, ty),
|
||||
_ => bug!("`constructor_covered_by_range` called with {:?}", pat),
|
||||
};
|
||||
trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
|
||||
|
|
@ -1557,17 +1566,33 @@ fn constructor_covered_by_range<'a, 'tcx>(
|
|||
(end == RangeEnd::Included && to == Ordering::Equal);
|
||||
Ok(some_or_ok!(cmp_from(value)) && end)
|
||||
},
|
||||
ConstantRange(from, to, RangeEnd::Included) => {
|
||||
let to = some_or_ok!(cmp_to(to));
|
||||
ConstantRange(from, to, ty, RangeEnd::Included) => {
|
||||
let to = some_or_ok!(cmp_to(ty::Const::from_bits(
|
||||
tcx,
|
||||
to,
|
||||
ty::ParamEnv::empty().and(ty),
|
||||
)));
|
||||
let end = (to == Ordering::Less) ||
|
||||
(end == RangeEnd::Included && to == Ordering::Equal);
|
||||
Ok(some_or_ok!(cmp_from(from)) && end)
|
||||
Ok(some_or_ok!(cmp_from(ty::Const::from_bits(
|
||||
tcx,
|
||||
from,
|
||||
ty::ParamEnv::empty().and(ty),
|
||||
))) && end)
|
||||
},
|
||||
ConstantRange(from, to, RangeEnd::Excluded) => {
|
||||
let to = some_or_ok!(cmp_to(to));
|
||||
ConstantRange(from, to, ty, RangeEnd::Excluded) => {
|
||||
let to = some_or_ok!(cmp_to(ty::Const::from_bits(
|
||||
tcx,
|
||||
to,
|
||||
ty::ParamEnv::empty().and(ty)
|
||||
)));
|
||||
let end = (to == Ordering::Less) ||
|
||||
(end == RangeEnd::Excluded && to == Ordering::Equal);
|
||||
Ok(some_or_ok!(cmp_from(from)) && end)
|
||||
Ok(some_or_ok!(cmp_from(ty::Const::from_bits(
|
||||
tcx,
|
||||
from,
|
||||
ty::ParamEnv::empty().and(ty)))
|
||||
) && end)
|
||||
}
|
||||
Single => Ok(true),
|
||||
_ => bug!(),
|
||||
|
|
@ -1606,6 +1631,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
|||
let pat = &r[0];
|
||||
|
||||
let head: Option<Vec<&Pattern>> = match *pat.kind {
|
||||
PatternKind::AscribeUserType { ref subpattern, .. } =>
|
||||
specialize(cx, ::std::slice::from_ref(&subpattern), constructor, wild_patterns),
|
||||
|
||||
PatternKind::Binding { .. } | PatternKind::Wild => {
|
||||
Some(wild_patterns.to_owned())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use interpret::{const_field, const_variant_index};
|
|||
|
||||
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
|
||||
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
|
||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
|
||||
use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
|
||||
use rustc::ty::subst::{Substs, Kind};
|
||||
use rustc::hir::{self, PatKind, RangeEnd};
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
|
|
@ -66,6 +66,11 @@ pub struct Pattern<'tcx> {
|
|||
pub enum PatternKind<'tcx> {
|
||||
Wild,
|
||||
|
||||
AscribeUserType {
|
||||
user_ty: CanonicalTy<'tcx>,
|
||||
subpattern: Pattern<'tcx>,
|
||||
},
|
||||
|
||||
/// x, ref x, x @ P, etc
|
||||
Binding {
|
||||
mutability: Mutability,
|
||||
|
|
@ -101,6 +106,7 @@ pub enum PatternKind<'tcx> {
|
|||
Range {
|
||||
lo: &'tcx ty::Const<'tcx>,
|
||||
hi: &'tcx ty::Const<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
end: RangeEnd,
|
||||
},
|
||||
|
||||
|
|
@ -125,6 +131,8 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self.kind {
|
||||
PatternKind::Wild => write!(f, "_"),
|
||||
PatternKind::AscribeUserType { ref subpattern, .. } =>
|
||||
write!(f, "{}: _", subpattern),
|
||||
PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => {
|
||||
let is_mut = match mode {
|
||||
BindingMode::ByValue => mutability == Mutability::Mut,
|
||||
|
|
@ -230,7 +238,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
|||
PatternKind::Constant { value } => {
|
||||
fmt_const_val(f, value)
|
||||
}
|
||||
PatternKind::Range { lo, hi, end } => {
|
||||
PatternKind::Range { lo, hi, ty: _, end } => {
|
||||
fmt_const_val(f, lo)?;
|
||||
match end {
|
||||
RangeEnd::Included => write!(f, "..=")?,
|
||||
|
|
@ -359,7 +367,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
);
|
||||
match (end, cmp) {
|
||||
(RangeEnd::Excluded, Some(Ordering::Less)) =>
|
||||
PatternKind::Range { lo, hi, end },
|
||||
PatternKind::Range { lo, hi, ty, end },
|
||||
(RangeEnd::Excluded, _) => {
|
||||
span_err!(
|
||||
self.tcx.sess,
|
||||
|
|
@ -373,7 +381,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
PatternKind::Constant { value: lo }
|
||||
}
|
||||
(RangeEnd::Included, Some(Ordering::Less)) => {
|
||||
PatternKind::Range { lo, hi, end }
|
||||
PatternKind::Range { lo, hi, ty, end }
|
||||
}
|
||||
(RangeEnd::Included, _) => {
|
||||
let mut err = struct_span_err!(
|
||||
|
|
@ -939,7 +947,7 @@ macro_rules! CloneImpls {
|
|||
CloneImpls!{ <'tcx>
|
||||
Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
|
||||
Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
|
||||
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>
|
||||
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
|
||||
|
|
@ -973,6 +981,13 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
|
|||
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
PatternKind::Wild => PatternKind::Wild,
|
||||
PatternKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
user_ty,
|
||||
} => PatternKind::AscribeUserType {
|
||||
subpattern: subpattern.fold_with(folder),
|
||||
user_ty: user_ty.fold_with(folder),
|
||||
},
|
||||
PatternKind::Binding {
|
||||
mutability,
|
||||
name,
|
||||
|
|
@ -1017,10 +1032,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
|
|||
PatternKind::Range {
|
||||
lo,
|
||||
hi,
|
||||
ty,
|
||||
end,
|
||||
} => PatternKind::Range {
|
||||
lo: lo.fold_with(folder),
|
||||
hi: hi.fold_with(folder),
|
||||
ty: ty.fold_with(folder),
|
||||
end,
|
||||
},
|
||||
PatternKind::Slice {
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
EndRegion(..) => {}
|
||||
UserAssertTy(..) => {}
|
||||
AscribeUserType(..) => {}
|
||||
|
||||
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
||||
// size of MIR constantly.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
#![feature(if_while_or_patterns)]
|
||||
#![feature(try_from)]
|
||||
#![feature(reverse_bits)]
|
||||
#![feature(underscore_imports)]
|
||||
|
||||
#![recursion_limit="256"]
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,9 @@ enum CallKind {
|
|||
fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl {
|
||||
let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span };
|
||||
LocalDecl {
|
||||
mutability, ty, name: None,
|
||||
mutability, ty,
|
||||
user_ty: None,
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
internal: false,
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
StatementKind::StorageDead(..) |
|
||||
StatementKind::EndRegion(..) |
|
||||
StatementKind::Validate(..) |
|
||||
StatementKind::UserAssertTy(..) |
|
||||
StatementKind::AscribeUserType(..) |
|
||||
StatementKind::Nop => {
|
||||
// safe (at least as emitted during MIR construction)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
//!
|
||||
//! - `CleanEndRegions`, that reduces the set of `EndRegion` statements
|
||||
//! in the MIR.
|
||||
//! - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements
|
||||
//! - `CleanAscribeUserType`, that replaces all `AscribeUserType` statements
|
||||
//! with `Nop`.
|
||||
//!
|
||||
//! The `CleanEndRegions` "pass" is actually implemented as two
|
||||
|
|
@ -24,10 +24,10 @@
|
|||
//! MIR and removes any `EndRegion` that is applied to a region that
|
||||
//! was not seen in the previous pass.
|
||||
//!
|
||||
//! The `CleanUserAssertTy` pass runs at a distinct time from the
|
||||
//! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy`
|
||||
//! The `CleanAscribeUserType` pass runs at a distinct time from the
|
||||
//! `CleanEndRegions` pass. It is important that the `CleanAscribeUserType`
|
||||
//! pass runs after the MIR borrowck so that the NLL type checker can
|
||||
//! perform the type assertion when it encounters the `UserAssertTy`
|
||||
//! perform the type assertion when it encounters the `AscribeUserType`
|
||||
//! statements.
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -110,26 +110,26 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CleanUserAssertTy;
|
||||
pub struct CleanAscribeUserType;
|
||||
|
||||
pub struct DeleteUserAssertTy;
|
||||
pub struct DeleteAscribeUserType;
|
||||
|
||||
impl MirPass for CleanUserAssertTy {
|
||||
impl MirPass for CleanAscribeUserType {
|
||||
fn run_pass<'a, 'tcx>(&self,
|
||||
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
_source: MirSource,
|
||||
mir: &mut Mir<'tcx>) {
|
||||
let mut delete = DeleteUserAssertTy;
|
||||
let mut delete = DeleteAscribeUserType;
|
||||
delete.visit_mir(mir);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy {
|
||||
impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType {
|
||||
fn visit_statement(&mut self,
|
||||
block: BasicBlock,
|
||||
statement: &mut Statement<'tcx>,
|
||||
location: Location) {
|
||||
if let StatementKind::UserAssertTy(..) = statement.kind {
|
||||
if let StatementKind::AscribeUserType(..) = statement.kind {
|
||||
statement.make_nop();
|
||||
}
|
||||
self.super_statement(block, statement, location);
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ fn replace_result_variable<'tcx>(
|
|||
let new_ret = LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: ret_ty,
|
||||
user_ty: None,
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
|
|
@ -656,6 +657,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
|
|||
mir.local_decls[RETURN_PLACE] = LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: tcx.mk_unit(),
|
||||
user_ty: None,
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
|
|
@ -672,6 +674,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
|
|||
ty: gen_ty,
|
||||
mutbl: hir::Mutability::MutMutable,
|
||||
}),
|
||||
user_ty: None,
|
||||
name: None,
|
||||
source_info,
|
||||
visibility_scope: source_info.scope,
|
||||
|
|
|
|||
|
|
@ -238,8 +238,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
|
|||
simplify_branches::SimplifyBranches::new("initial"),
|
||||
remove_noop_landing_pads::RemoveNoopLandingPads,
|
||||
simplify::SimplifyCfg::new("early-opt"),
|
||||
// Remove all `UserAssertTy` statements.
|
||||
cleanup_post_borrowck::CleanUserAssertTy,
|
||||
// Remove all `AscribeUserType` statements.
|
||||
cleanup_post_borrowck::CleanAscribeUserType,
|
||||
|
||||
// These next passes must be executed together
|
||||
add_call_guards::CriticalCallEdges,
|
||||
|
|
|
|||
|
|
@ -1098,7 +1098,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
StatementKind::InlineAsm {..} |
|
||||
StatementKind::EndRegion(_) |
|
||||
StatementKind::Validate(..) |
|
||||
StatementKind::UserAssertTy(..) |
|
||||
StatementKind::AscribeUserType(..) |
|
||||
StatementKind::Nop => {}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ fn check_statement(
|
|||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Validate(..)
|
||||
| StatementKind::EndRegion(_)
|
||||
| StatementKind::UserAssertTy(..)
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Nop => Ok(()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ impl RemoveNoopLandingPads {
|
|||
StatementKind::StorageLive(_) |
|
||||
StatementKind::StorageDead(_) |
|
||||
StatementKind::EndRegion(_) |
|
||||
StatementKind::UserAssertTy(..) |
|
||||
StatementKind::AscribeUserType(..) |
|
||||
StatementKind::Nop => {
|
||||
// These are all nops in a landing pad (there's some
|
||||
// borrowck interaction between EndRegion and storage
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
mir::StatementKind::InlineAsm { .. } |
|
||||
mir::StatementKind::EndRegion(_) |
|
||||
mir::StatementKind::Validate(..) |
|
||||
mir::StatementKind::UserAssertTy(..) |
|
||||
mir::StatementKind::AscribeUserType(..) |
|
||||
mir::StatementKind::Nop => continue,
|
||||
mir::StatementKind::SetDiscriminant{ .. } =>
|
||||
span_bug!(stmt.source_info.span,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use rustc::ty::item_path;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use std::fmt::Display;
|
||||
use std::fmt::Write as _;
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -493,14 +494,18 @@ fn write_scope_tree(
|
|||
};
|
||||
|
||||
let indent = indent + INDENT.len();
|
||||
let indented_var = format!(
|
||||
"{0:1$}let {2}{3:?}: {4:?};",
|
||||
let mut indented_var = format!(
|
||||
"{0:1$}let {2}{3:?}: {4:?}",
|
||||
INDENT,
|
||||
indent,
|
||||
mut_str,
|
||||
local,
|
||||
var.ty
|
||||
);
|
||||
if let Some(user_ty) = var.user_ty {
|
||||
write!(indented_var, " as {:?}", user_ty).unwrap();
|
||||
}
|
||||
indented_var.push_str(";");
|
||||
writeln!(
|
||||
w,
|
||||
"{0:1$} // \"{2}\" in {3}",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use syntax::ast::*;
|
|||
use syntax::attr;
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::symbol::keywords;
|
||||
use syntax::ptr::P;
|
||||
use syntax::visit::{self, Visitor};
|
||||
use syntax_pos::Span;
|
||||
use errors;
|
||||
|
|
@ -98,14 +99,11 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
|
||||
match constness.node {
|
||||
Constness::Const => {
|
||||
struct_span_err!(self.session, constness.span, E0379,
|
||||
"trait fns cannot be declared const")
|
||||
.span_label(constness.span, "trait fns cannot be const")
|
||||
.emit();
|
||||
}
|
||||
_ => {}
|
||||
if constness.node == Constness::Const {
|
||||
struct_span_err!(self.session, constness.span, E0379,
|
||||
"trait fns cannot be declared const")
|
||||
.span_label(constness.span, "trait fns cannot be const")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +111,7 @@ impl<'a> AstValidator<'a> {
|
|||
for bound in bounds {
|
||||
if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
|
||||
let mut err = self.err_handler().struct_span_err(poly.span,
|
||||
&format!("`?Trait` is not permitted in {}", where_));
|
||||
&format!("`?Trait` is not permitted in {}", where_));
|
||||
if is_trait {
|
||||
err.note(&format!("traits are `?{}` by default", poly.trait_ref.path));
|
||||
}
|
||||
|
|
@ -152,26 +150,76 @@ impl<'a> AstValidator<'a> {
|
|||
// Check only lifetime parameters are present and that the lifetime
|
||||
// parameters that are present have no bounds.
|
||||
let non_lt_param_spans: Vec<_> = params.iter().filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.err_handler()
|
||||
.span_err(spans, "lifetime bounds cannot be used in this context");
|
||||
}
|
||||
None
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.err_handler()
|
||||
.span_err(spans, "lifetime bounds cannot be used in this context");
|
||||
}
|
||||
_ => Some(param.ident.span),
|
||||
}).collect();
|
||||
None
|
||||
}
|
||||
_ => Some(param.ident.span),
|
||||
}).collect();
|
||||
if !non_lt_param_spans.is_empty() {
|
||||
self.err_handler().span_err(non_lt_param_spans,
|
||||
"only lifetime parameters can be used in this context");
|
||||
}
|
||||
}
|
||||
|
||||
/// With eRFC 2497, we need to check whether an expression is ambigious and warn or error
|
||||
/// depending on the edition, this function handles that.
|
||||
fn while_if_let_ambiguity(&self, expr: &P<Expr>) {
|
||||
if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) {
|
||||
let mut err = self.err_handler().struct_span_err(
|
||||
span, &format!("ambigious use of `{}`", op_kind.to_string())
|
||||
);
|
||||
|
||||
err.note(
|
||||
"this will be a error until the `let_chains` feature is stabilized"
|
||||
);
|
||||
err.note(
|
||||
"see rust-lang/rust#53668 for more information"
|
||||
);
|
||||
|
||||
if let Ok(snippet) = self.session.source_map().span_to_snippet(span) {
|
||||
err.span_suggestion(
|
||||
span, "consider adding parentheses", format!("({})", snippet),
|
||||
);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of
|
||||
/// `&&` and `||` in a if-let statement be unambigious. This function returns a span and
|
||||
/// a `BinOpKind` (either `&&` or `||` depending on what was ambigious) if it is determined
|
||||
/// that the current expression parsed is ambigious and will break in future.
|
||||
fn while_if_let_expr_ambiguity(&self, expr: &P<Expr>) -> Option<(Span, BinOpKind)> {
|
||||
debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node);
|
||||
match &expr.node {
|
||||
ExprKind::Binary(op, _, _) if op.node == BinOpKind::And || op.node == BinOpKind::Or => {
|
||||
Some((expr.span, op.node))
|
||||
},
|
||||
ExprKind::Range(ref lhs, ref rhs, _) => {
|
||||
let lhs_ambigious = lhs.as_ref()
|
||||
.and_then(|lhs| self.while_if_let_expr_ambiguity(lhs));
|
||||
let rhs_ambigious = rhs.as_ref()
|
||||
.and_then(|rhs| self.while_if_let_expr_ambiguity(rhs));
|
||||
|
||||
lhs_ambigious.or(rhs_ambigious)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
match expr.node {
|
||||
ExprKind::IfLet(_, ref expr, _, _) | ExprKind::WhileLet(_, ref expr, _, _) =>
|
||||
self.while_if_let_ambiguity(&expr),
|
||||
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
|
||||
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
|
||||
}
|
||||
|
|
@ -387,7 +435,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.err_handler().span_err(item.span,
|
||||
"tuple and unit unions are not permitted");
|
||||
}
|
||||
if vdata.fields().len() == 0 {
|
||||
if vdata.fields().is_empty() {
|
||||
self.err_handler().span_err(item.span,
|
||||
"unions cannot have zero fields");
|
||||
}
|
||||
|
|
@ -414,14 +462,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
fn visit_vis(&mut self, vis: &'a Visibility) {
|
||||
match vis.node {
|
||||
VisibilityKind::Restricted { ref path, .. } => {
|
||||
path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
|
||||
self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
|
||||
"generic arguments in visibility path");
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
if let VisibilityKind::Restricted { ref path, .. } = vis.node {
|
||||
path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
|
||||
self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
|
||||
"generic arguments in visibility path");
|
||||
});
|
||||
}
|
||||
|
||||
visit::walk_vis(self, vis)
|
||||
|
|
@ -591,8 +636,7 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
|
|||
TyKind::ImplTrait(..) => {
|
||||
if self.is_banned {
|
||||
struct_span_err!(self.session, t.span, E0667,
|
||||
"`impl Trait` is not allowed in path parameters")
|
||||
.emit();
|
||||
"`impl Trait` is not allowed in path parameters").emit();
|
||||
}
|
||||
}
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
|
|
@ -616,7 +660,7 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
|
|||
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
// Allow `impl Trait` iff we're on the final path segment
|
||||
if i == (path.segments.len() - 1) {
|
||||
if i == path.segments.len() - 1 {
|
||||
visit::walk_path_segment(self, path.span, segment);
|
||||
} else {
|
||||
self.with_ban(|this|
|
||||
|
|
|
|||
|
|
@ -61,10 +61,8 @@ pub fn print_ast_stats<'v>(krate: &'v ast::Crate, title: &str) {
|
|||
impl<'k> StatCollector<'k> {
|
||||
|
||||
fn record<T>(&mut self, label: &'static str, id: Id, node: &T) {
|
||||
if id != Id::None {
|
||||
if !self.seen.insert(id) {
|
||||
return
|
||||
}
|
||||
if id != Id::None && !self.seen.insert(id) {
|
||||
return
|
||||
}
|
||||
|
||||
let entry = self.data.entry(label).or_insert(NodeData {
|
||||
|
|
@ -135,40 +133,46 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
hir_visit::walk_item(self, i)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn visit_mod(&mut self, m: &'v hir::Mod, _s: Span, n: NodeId) {
|
||||
self.record("Mod", Id::None, m);
|
||||
hir_visit::walk_mod(self, m, n)
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem) {
|
||||
self.record("ForeignItem", Id::Node(i.id), i);
|
||||
hir_visit::walk_foreign_item(self, i)
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &'v hir::Local) {
|
||||
self.record("Local", Id::Node(l.id), l);
|
||||
hir_visit::walk_local(self, l)
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, b: &'v hir::Block) {
|
||||
self.record("Block", Id::Node(b.id), b);
|
||||
hir_visit::walk_block(self, b)
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, s: &'v hir::Stmt) {
|
||||
self.record("Stmt", Id::Node(s.node.id()), s);
|
||||
hir_visit::walk_stmt(self, s)
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, a: &'v hir::Arm) {
|
||||
self.record("Arm", Id::None, a);
|
||||
hir_visit::walk_arm(self, a)
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &'v hir::Pat) {
|
||||
self.record("Pat", Id::Node(p.id), p);
|
||||
hir_visit::walk_pat(self, p)
|
||||
}
|
||||
|
||||
fn visit_decl(&mut self, d: &'v hir::Decl) {
|
||||
self.record("Decl", Id::None, d);
|
||||
hir_visit::walk_decl(self, d)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr) {
|
||||
self.record("Expr", Id::Node(ex.id), ex);
|
||||
hir_visit::walk_expr(self, ex)
|
||||
|
|
@ -198,6 +202,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
self.record("TraitItem", Id::Node(ti.id), ti);
|
||||
hir_visit::walk_trait_item(self, ti)
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
|
||||
self.record("ImplItem", Id::Node(ii.id), ii);
|
||||
hir_visit::walk_impl_item(self, ii)
|
||||
|
|
@ -220,31 +225,38 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
self.record("Variant", Id::None, v);
|
||||
hir_visit::walk_variant(self, v, g, item_id)
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
|
||||
self.record("Lifetime", Id::Node(lifetime.id), lifetime);
|
||||
hir_visit::walk_lifetime(self, lifetime)
|
||||
}
|
||||
|
||||
fn visit_qpath(&mut self, qpath: &'v hir::QPath, id: hir::HirId, span: Span) {
|
||||
self.record("QPath", Id::None, qpath);
|
||||
hir_visit::walk_qpath(self, qpath, id, span)
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &'v hir::Path, _id: hir::HirId) {
|
||||
self.record("Path", Id::None, path);
|
||||
hir_visit::walk_path(self, path)
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self,
|
||||
path_span: Span,
|
||||
path_segment: &'v hir::PathSegment) {
|
||||
self.record("PathSegment", Id::None, path_segment);
|
||||
hir_visit::walk_path_segment(self, path_span, path_segment)
|
||||
}
|
||||
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding) {
|
||||
self.record("TypeBinding", Id::Node(type_binding.id), type_binding);
|
||||
hir_visit::walk_assoc_type_binding(self, type_binding)
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
|
||||
self.record("Attribute", Id::Attr(attr.id), attr);
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef) {
|
||||
self.record("MacroDef", Id::Node(macro_def.id), macro_def);
|
||||
hir_visit::walk_macro_def(self, macro_def)
|
||||
|
|
|
|||
|
|
@ -114,9 +114,8 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
};
|
||||
|
||||
if loop_id != ast::DUMMY_NODE_ID {
|
||||
match self.hir_map.find(loop_id).unwrap() {
|
||||
Node::Block(_) => return,
|
||||
_=> (),
|
||||
if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,10 +152,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
|
||||
self.require_break_cx("break", e.span);
|
||||
}
|
||||
hir::ExprKind::Continue(label) => {
|
||||
self.require_label_in_labeled_block(e.span, &label, "continue");
|
||||
hir::ExprKind::Continue(destination) => {
|
||||
self.require_label_in_labeled_block(e.span, &destination, "continue");
|
||||
|
||||
match label.target_id {
|
||||
match destination.target_id {
|
||||
Ok(loop_id) => {
|
||||
if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
|
||||
struct_span_err!(self.sess, e.span, E0696,
|
||||
|
|
@ -171,7 +170,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
|
||||
self.emit_unlabled_cf_in_while_condition(e.span, "continue");
|
||||
}
|
||||
_ => {}
|
||||
Err(_) => {}
|
||||
}
|
||||
self.require_break_cx("continue", e.span)
|
||||
},
|
||||
|
|
@ -192,8 +191,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
|||
|
||||
fn require_break_cx(&self, name: &str, span: Span) {
|
||||
match self.cx {
|
||||
LabeledBlock |
|
||||
Loop(_) => {}
|
||||
LabeledBlock | Loop(_) => {}
|
||||
Closure => {
|
||||
struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
|
||||
.span_label(span, "cannot break inside of a closure")
|
||||
|
|
|
|||
|
|
@ -65,15 +65,12 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
self.super_mir(mir);
|
||||
}
|
||||
|
||||
fn visit_basic_block_data(&mut self,
|
||||
block: BasicBlock,
|
||||
data: &BasicBlockData<'tcx>) {
|
||||
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
|
||||
self.record("BasicBlockData", data);
|
||||
self.super_basic_block_data(block, data);
|
||||
}
|
||||
|
||||
fn visit_source_scope_data(&mut self,
|
||||
scope_data: &SourceScopeData) {
|
||||
fn visit_source_scope_data(&mut self, scope_data: &SourceScopeData) {
|
||||
self.record("SourceScopeData", scope_data);
|
||||
self.super_source_scope_data(scope_data);
|
||||
}
|
||||
|
|
@ -92,7 +89,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
StatementKind::StorageLive(..) => "StatementKind::StorageLive",
|
||||
StatementKind::StorageDead(..) => "StatementKind::StorageDead",
|
||||
StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
|
||||
StatementKind::UserAssertTy(..) => "StatementKind::UserAssertTy",
|
||||
StatementKind::AscribeUserType(..) => "StatementKind::AscribeUserType",
|
||||
StatementKind::Nop => "StatementKind::Nop",
|
||||
}, &statement.kind);
|
||||
self.super_statement(block, statement, location);
|
||||
|
|
@ -130,9 +127,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
self.super_terminator_kind(block, kind, location);
|
||||
}
|
||||
|
||||
fn visit_assert_message(&mut self,
|
||||
msg: &AssertMessage<'tcx>,
|
||||
location: Location) {
|
||||
fn visit_assert_message(&mut self, msg: &AssertMessage<'tcx>, location: Location) {
|
||||
self.record("AssertMessage", msg);
|
||||
self.record(match *msg {
|
||||
EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
|
||||
|
|
@ -151,9 +146,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
self.super_assert_message(msg, location);
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location) {
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
self.record("Rvalue", rvalue);
|
||||
let rvalue_kind = match *rvalue {
|
||||
Rvalue::Use(..) => "Rvalue::Use",
|
||||
|
|
@ -184,9 +177,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_operand(&mut self,
|
||||
operand: &Operand<'tcx>,
|
||||
location: Location) {
|
||||
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
||||
self.record("Operand", operand);
|
||||
self.record(match *operand {
|
||||
Operand::Copy(..) => "Operand::Copy",
|
||||
|
|
@ -234,42 +225,32 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
self.super_projection_elem(place, context, location);
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self,
|
||||
constant: &Constant<'tcx>,
|
||||
location: Location) {
|
||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
||||
self.record("Constant", constant);
|
||||
self.super_constant(constant, location);
|
||||
}
|
||||
|
||||
fn visit_source_info(&mut self,
|
||||
source_info: &SourceInfo) {
|
||||
fn visit_source_info(&mut self, source_info: &SourceInfo) {
|
||||
self.record("SourceInfo", source_info);
|
||||
self.super_source_info(source_info);
|
||||
}
|
||||
|
||||
fn visit_closure_substs(&mut self,
|
||||
substs: &ClosureSubsts<'tcx>,
|
||||
_: Location) {
|
||||
fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, _: Location) {
|
||||
self.record("ClosureSubsts", substs);
|
||||
self.super_closure_substs(substs);
|
||||
}
|
||||
|
||||
fn visit_const(&mut self,
|
||||
constant: &&'tcx ty::Const<'tcx>,
|
||||
_: Location) {
|
||||
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
|
||||
self.record("Const", constant);
|
||||
self.super_const(constant);
|
||||
}
|
||||
|
||||
fn visit_local_decl(&mut self,
|
||||
local: Local,
|
||||
local_decl: &LocalDecl<'tcx>) {
|
||||
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
self.record("LocalDecl", local_decl);
|
||||
self.super_local_decl(local, local_decl);
|
||||
}
|
||||
|
||||
fn visit_source_scope(&mut self,
|
||||
scope: &SourceScope) {
|
||||
fn visit_source_scope(&mut self, scope: &SourceScope) {
|
||||
self.record("VisiblityScope", scope);
|
||||
self.super_source_scope(scope);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@ use syntax::ast;
|
|||
use syntax::attr;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use self::Promotability::*;
|
||||
use std::ops::{BitAnd, BitOr};
|
||||
|
||||
use std::ops::{BitAnd, BitAndAssign, BitOr};
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
|
|
@ -114,7 +113,7 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum Promotability {
|
||||
Promotable,
|
||||
NotPromotable
|
||||
|
|
@ -125,23 +124,25 @@ impl BitAnd for Promotability {
|
|||
|
||||
fn bitand(self, rhs: Self) -> Self {
|
||||
match (self, rhs) {
|
||||
(Promotable, NotPromotable) => NotPromotable,
|
||||
(NotPromotable, Promotable) => NotPromotable,
|
||||
(NotPromotable, NotPromotable) => NotPromotable,
|
||||
(Promotable, Promotable) => Promotable,
|
||||
_ => NotPromotable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAndAssign for Promotability {
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
*self = *self & rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for Promotability {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
match (self, rhs) {
|
||||
(Promotable, NotPromotable) => Promotable,
|
||||
(NotPromotable, Promotable) => Promotable,
|
||||
(NotPromotable, NotPromotable) => NotPromotable,
|
||||
(Promotable, Promotable) => Promotable,
|
||||
_ => Promotable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -161,7 +162,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
|
|||
|
||||
fn handle_const_fn_call(&mut self, def_id: DefId,
|
||||
ret_ty: Ty<'gcx>, span: Span) -> Promotability {
|
||||
if let NotPromotable = self.type_promotability(ret_ty) {
|
||||
if self.type_promotability(ret_ty) == NotPromotable {
|
||||
return NotPromotable;
|
||||
}
|
||||
|
||||
|
|
@ -266,9 +267,8 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
match local.init {
|
||||
Some(ref expr) => { let _ = self.check_expr(&expr); },
|
||||
None => {},
|
||||
if let Some(ref expr) = local.init {
|
||||
let _ = self.check_expr(&expr);
|
||||
}
|
||||
NotPromotable
|
||||
}
|
||||
|
|
@ -287,7 +287,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
|||
fn check_expr(&mut self, ex: &'tcx hir::Expr) -> Promotability {
|
||||
let node_ty = self.tables.node_id_to_type(ex.hir_id);
|
||||
let mut outer = check_expr_kind(self, ex, node_ty);
|
||||
outer = outer & check_adjustments(self, ex);
|
||||
outer &= check_adjustments(self, ex);
|
||||
|
||||
// Handle borrows on (or inside the autorefs of) this expression.
|
||||
if self.mut_rvalue_borrows.remove(&ex.id) {
|
||||
|
|
@ -303,7 +303,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
|||
fn check_block(&mut self, block: &'tcx hir::Block) -> Promotability {
|
||||
let mut iter_result = Promotable;
|
||||
for index in block.stmts.iter() {
|
||||
iter_result = iter_result & self.check_stmt(index);
|
||||
iter_result &= self.check_stmt(index);
|
||||
}
|
||||
match block.expr {
|
||||
Some(ref box_expr) => iter_result & self.check_expr(&*box_expr),
|
||||
|
|
@ -336,10 +336,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
}
|
||||
hir::ExprKind::Unary(op, ref expr) => {
|
||||
let expr_promotability = v.check_expr(expr);
|
||||
if v.tables.is_method_call(e) {
|
||||
return NotPromotable;
|
||||
}
|
||||
if op == hir::UnDeref {
|
||||
if v.tables.is_method_call(e) || op == hir::UnDeref {
|
||||
return NotPromotable;
|
||||
}
|
||||
expr_promotability
|
||||
|
|
@ -353,8 +350,8 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
match v.tables.node_id_to_type(lhs.hir_id).sty {
|
||||
ty::RawPtr(_) => {
|
||||
assert!(op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne ||
|
||||
op.node == hir::BinOpKind::Le || op.node == hir::BinOpKind::Lt ||
|
||||
op.node == hir::BinOpKind::Ge || op.node == hir::BinOpKind::Gt);
|
||||
op.node == hir::BinOpKind::Le || op.node == hir::BinOpKind::Lt ||
|
||||
op.node == hir::BinOpKind::Ge || op.node == hir::BinOpKind::Gt);
|
||||
|
||||
NotPromotable
|
||||
}
|
||||
|
|
@ -400,7 +397,6 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
debug!("Reference to Static(id={:?}) is unpromotable as it is not \
|
||||
referenced from a static", did);
|
||||
NotPromotable
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -425,7 +421,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
hir::ExprKind::Call(ref callee, ref hirvec) => {
|
||||
let mut call_result = v.check_expr(callee);
|
||||
for index in hirvec.iter() {
|
||||
call_result = call_result & v.check_expr(index);
|
||||
call_result &= v.check_expr(index);
|
||||
}
|
||||
let mut callee = &**callee;
|
||||
loop {
|
||||
|
|
@ -464,7 +460,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
hir::ExprKind::MethodCall(ref _pathsegment, ref _span, ref hirvec) => {
|
||||
let mut method_call_result = Promotable;
|
||||
for index in hirvec.iter() {
|
||||
method_call_result = method_call_result & v.check_expr(index);
|
||||
method_call_result &= v.check_expr(index);
|
||||
}
|
||||
if let Some(def) = v.tables.type_dependent_defs().get(e.hir_id) {
|
||||
let def_id = def.def_id();
|
||||
|
|
@ -483,11 +479,10 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
hir::ExprKind::Struct(ref _qpath, ref hirvec, ref option_expr) => {
|
||||
let mut struct_result = Promotable;
|
||||
for index in hirvec.iter() {
|
||||
struct_result = struct_result & v.check_expr(&index.expr);
|
||||
struct_result &= v.check_expr(&index.expr);
|
||||
}
|
||||
match *option_expr {
|
||||
Some(ref expr) => { struct_result = struct_result & v.check_expr(&expr); },
|
||||
None => {},
|
||||
if let Some(ref expr) = *option_expr {
|
||||
struct_result &= v.check_expr(&expr);
|
||||
}
|
||||
if let ty::Adt(adt, ..) = v.tables.expr_ty(e).sty {
|
||||
// unsafe_cell_type doesn't necessarily exist with no_core
|
||||
|
|
@ -506,7 +501,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
}
|
||||
|
||||
hir::ExprKind::Closure(_capture_clause, ref _box_fn_decl,
|
||||
body_id, _span, _option_generator_movability) => {
|
||||
body_id, _span, _option_generator_movability) => {
|
||||
let nested_body_promotable = v.check_nested_body(body_id);
|
||||
// Paths in constant contexts cannot refer to local variables,
|
||||
// as there are none, and thus closures can't have upvars there.
|
||||
|
|
@ -543,7 +538,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
hir::ExprKind::Array(ref hirvec) => {
|
||||
let mut array_result = Promotable;
|
||||
for index in hirvec.iter() {
|
||||
array_result = array_result & v.check_expr(index);
|
||||
array_result &= v.check_expr(index);
|
||||
}
|
||||
array_result
|
||||
}
|
||||
|
|
@ -555,7 +550,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
hir::ExprKind::Tup(ref hirvec) => {
|
||||
let mut tup_result = Promotable;
|
||||
for index in hirvec.iter() {
|
||||
tup_result = tup_result & v.check_expr(index);
|
||||
tup_result &= v.check_expr(index);
|
||||
}
|
||||
tup_result
|
||||
}
|
||||
|
|
@ -576,12 +571,9 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
let _ = v.check_expr(expr);
|
||||
for index in hirvec_arm.iter() {
|
||||
let _ = v.check_expr(&*index.body);
|
||||
match index.guard {
|
||||
Some(hir::Guard::If(ref expr)) => {
|
||||
let _ = v.check_expr(&expr);
|
||||
},
|
||||
None => {},
|
||||
};
|
||||
if let Some(hir::Guard::If(ref expr)) = index.guard {
|
||||
let _ = v.check_expr(&expr);
|
||||
}
|
||||
}
|
||||
NotPromotable
|
||||
}
|
||||
|
|
@ -589,10 +581,9 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
hir::ExprKind::If(ref lhs, ref rhs, ref option_expr) => {
|
||||
let _ = v.check_expr(lhs);
|
||||
let _ = v.check_expr(rhs);
|
||||
match option_expr {
|
||||
Some(ref expr) => { let _ = v.check_expr(&expr); },
|
||||
None => {},
|
||||
};
|
||||
if let Some(ref expr) = option_expr {
|
||||
let _ = v.check_expr(&expr);
|
||||
}
|
||||
NotPromotable
|
||||
}
|
||||
|
||||
|
|
@ -610,9 +601,8 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
|
||||
// More control flow (also not very meaningful).
|
||||
hir::ExprKind::Break(_, ref option_expr) | hir::ExprKind::Ret(ref option_expr) => {
|
||||
match *option_expr {
|
||||
Some(ref expr) => { let _ = v.check_expr(&expr); },
|
||||
None => {},
|
||||
if let Some(ref expr) = *option_expr {
|
||||
let _ = v.check_expr(&expr);
|
||||
}
|
||||
NotPromotable
|
||||
}
|
||||
|
|
@ -635,10 +625,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
}
|
||||
|
||||
hir::ExprKind::InlineAsm(ref _inline_asm, ref hirvec_lhs, ref hirvec_rhs) => {
|
||||
for index in hirvec_lhs.iter() {
|
||||
let _ = v.check_expr(index);
|
||||
}
|
||||
for index in hirvec_rhs.iter() {
|
||||
for index in hirvec_lhs.iter().chain(hirvec_rhs.iter()) {
|
||||
let _ = v.check_expr(index);
|
||||
}
|
||||
NotPromotable
|
||||
|
|
@ -703,11 +690,8 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
|
|||
// These occur when we convert a &T or *T to a *U, as well as
|
||||
// when making a thin pointer (e.g., `*T`) into a fat pointer
|
||||
// (e.g., `*Trait`).
|
||||
match loan_cause {
|
||||
euv::LoanCause::AutoUnsafe => {
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
if let euv::LoanCause::AutoUnsafe = loan_cause {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut cur = cmt;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use syntax::ext::base::{MacroKind, SyntaxExtension};
|
|||
use syntax::ext::base::Determinacy::Undetermined;
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::feature_gate::is_builtin_attr;
|
||||
use syntax::parse::token::{self, Token};
|
||||
use syntax::std_inject::injected_crate_name;
|
||||
use syntax::symbol::keywords;
|
||||
|
|
@ -194,27 +195,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// ergonomically unacceptable.
|
||||
let emit_uniform_paths_canary =
|
||||
!uniform_paths_canary_emitted &&
|
||||
uniform_paths &&
|
||||
self.session.rust_2018() &&
|
||||
starts_with_non_keyword;
|
||||
if emit_uniform_paths_canary {
|
||||
let source = prefix_start.unwrap();
|
||||
|
||||
// HACK(eddyb) For `use x::{self, ...};`, use the ID of the
|
||||
// `self` nested import for the canary. This allows the
|
||||
// ambiguity reporting scope to ignore false positives
|
||||
// in the same way it does for `use x;` (by comparing IDs).
|
||||
let mut canary_id = id;
|
||||
if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
|
||||
for &(ref use_tree, id) in items {
|
||||
if let ast::UseTreeKind::Simple(..) = use_tree.kind {
|
||||
if use_tree.ident().name == keywords::SelfValue.name() {
|
||||
canary_id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper closure to emit a canary with the given base path.
|
||||
let emit = |this: &mut Self, base: Option<Ident>| {
|
||||
let subclass = SingleImport {
|
||||
|
|
@ -234,7 +219,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
base.into_iter().collect(),
|
||||
subclass.clone(),
|
||||
source.span,
|
||||
canary_id,
|
||||
id,
|
||||
root_use_tree.span,
|
||||
root_id,
|
||||
ty::Visibility::Invisible,
|
||||
|
|
@ -833,7 +818,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
binding: &'a NameBinding<'a>,
|
||||
span: Span,
|
||||
allow_shadowing: bool) {
|
||||
if self.macro_prelude.insert(name, binding).is_some() && !allow_shadowing {
|
||||
if self.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing {
|
||||
let msg = format!("`{}` is already in scope", name);
|
||||
let note =
|
||||
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
|
||||
|
|
@ -1073,4 +1058,13 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
|
||||
if !attr.is_sugared_doc && is_builtin_attr(attr) {
|
||||
self.resolver.current_module.builtin_attrs.borrow_mut().push((
|
||||
attr.path.segments[0].ident, self.expansion, self.current_legacy_scope
|
||||
));
|
||||
}
|
||||
visit::walk_attribute(self, attr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ use std::mem::replace;
|
|||
use rustc_data_structures::sync::Lrc;
|
||||
|
||||
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
|
||||
use macros::{InvocationData, LegacyBinding};
|
||||
use macros::{InvocationData, LegacyBinding, LegacyScope};
|
||||
|
||||
// NB: This module needs to be declared first so diagnostics are
|
||||
// registered before they are used.
|
||||
|
|
@ -160,8 +160,6 @@ enum ResolutionError<'a> {
|
|||
SelfImportCanOnlyAppearOnceInTheList,
|
||||
/// error E0431: `self` import can only appear in an import list with a non-empty prefix
|
||||
SelfImportOnlyInImportListWithNonEmptyPrefix,
|
||||
/// error E0432: unresolved import
|
||||
UnresolvedImport(Option<(Span, &'a str, &'a str)>),
|
||||
/// error E0433: failed to resolve
|
||||
FailedToResolve(&'a str),
|
||||
/// error E0434: can't capture dynamic environment in a fn item
|
||||
|
|
@ -370,17 +368,6 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
|||
err.span_label(span, "can only appear in an import list with a non-empty prefix");
|
||||
err
|
||||
}
|
||||
ResolutionError::UnresolvedImport(name) => {
|
||||
let (span, msg) = match name {
|
||||
Some((sp, n, _)) => (sp, format!("unresolved import `{}`", n)),
|
||||
None => (span, "unresolved import".to_owned()),
|
||||
};
|
||||
let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg);
|
||||
if let Some((_, _, p)) = name {
|
||||
err.span_label(span, p);
|
||||
}
|
||||
err
|
||||
}
|
||||
ResolutionError::FailedToResolve(msg) => {
|
||||
let mut err = struct_span_err!(resolver.session, span, E0433,
|
||||
"failed to resolve. {}", msg);
|
||||
|
|
@ -1023,8 +1010,9 @@ pub struct ModuleData<'a> {
|
|||
normal_ancestor_id: DefId,
|
||||
|
||||
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, MacroKind, Option<Def>)>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>,
|
||||
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
|
||||
builtin_attrs: RefCell<Vec<(Ident, Mark, LegacyScope<'a>)>>,
|
||||
|
||||
// Macro invocations that can expand into items in this module.
|
||||
unresolved_invocations: RefCell<FxHashSet<Mark>>,
|
||||
|
|
@ -1063,6 +1051,7 @@ impl<'a> ModuleData<'a> {
|
|||
resolutions: RefCell::new(FxHashMap()),
|
||||
legacy_macro_resolutions: RefCell::new(Vec::new()),
|
||||
macro_resolutions: RefCell::new(Vec::new()),
|
||||
builtin_attrs: RefCell::new(Vec::new()),
|
||||
unresolved_invocations: RefCell::new(FxHashSet()),
|
||||
no_implicit_prelude: false,
|
||||
glob_importers: RefCell::new(Vec::new()),
|
||||
|
|
@ -1278,23 +1267,30 @@ impl<'a> NameBinding<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn macro_kind(&self) -> Option<MacroKind> {
|
||||
match self.def_ignoring_ambiguity() {
|
||||
Def::Macro(_, kind) => Some(kind),
|
||||
Def::NonMacroAttr(..) => Some(MacroKind::Attr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn descr(&self) -> &'static str {
|
||||
if self.is_extern_crate() { "extern crate" } else { self.def().kind_name() }
|
||||
}
|
||||
|
||||
// Suppose that we resolved macro invocation with `invoc_id` to binding `binding` at some
|
||||
// expansion round `max(invoc_id, binding)` when they both emerged from macros.
|
||||
// Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding`
|
||||
// at some expansion round `max(invoc, binding)` when they both emerged from macros.
|
||||
// Then this function returns `true` if `self` may emerge from a macro *after* that
|
||||
// in some later round and screw up our previously found resolution.
|
||||
// See more detailed explanation in
|
||||
// https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049
|
||||
fn may_appear_after(&self, invoc_id: Mark, binding: &NameBinding) -> bool {
|
||||
// self > max(invoc_id, binding) => !(self <= invoc_id || self <= binding)
|
||||
fn may_appear_after(&self, invoc_parent_expansion: Mark, binding: &NameBinding) -> bool {
|
||||
// self > max(invoc, binding) => !(self <= invoc || self <= binding)
|
||||
// Expansions are partially ordered, so "may appear after" is an inversion of
|
||||
// "certainly appears before or simultaneously" and includes unordered cases.
|
||||
let self_parent_expansion = self.expansion;
|
||||
let other_parent_expansion = binding.expansion;
|
||||
let invoc_parent_expansion = invoc_id.parent();
|
||||
let certainly_before_other_or_simultaneously =
|
||||
other_parent_expansion.is_descendant_of(self_parent_expansion);
|
||||
let certainly_before_invoc_or_simultaneously =
|
||||
|
|
@ -1440,8 +1436,8 @@ pub struct Resolver<'a, 'b: 'a> {
|
|||
|
||||
crate_loader: &'a mut CrateLoader<'b>,
|
||||
macro_names: FxHashSet<Ident>,
|
||||
macro_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
|
||||
unshadowable_attrs: FxHashMap<Name, &'a NameBinding<'a>>,
|
||||
builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
|
||||
macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
|
||||
pub all_macros: FxHashMap<Name, Def>,
|
||||
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
|
||||
macro_defs: FxHashMap<Mark, DefId>,
|
||||
|
|
@ -1757,8 +1753,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
|
||||
crate_loader,
|
||||
macro_names: FxHashSet(),
|
||||
macro_prelude: FxHashMap(),
|
||||
unshadowable_attrs: FxHashMap(),
|
||||
builtin_macros: FxHashMap(),
|
||||
macro_use_prelude: FxHashMap(),
|
||||
all_macros: FxHashMap(),
|
||||
macro_map: FxHashMap(),
|
||||
invocations,
|
||||
|
|
@ -3340,10 +3336,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
};
|
||||
}
|
||||
}
|
||||
let is_global = self.macro_prelude.get(&path[0].name).cloned()
|
||||
.map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
|
||||
if primary_ns != MacroNS && (is_global ||
|
||||
self.macro_names.contains(&path[0].modern())) {
|
||||
if primary_ns != MacroNS &&
|
||||
(self.macro_names.contains(&path[0].modern()) ||
|
||||
self.builtin_macros.get(&path[0].name).cloned()
|
||||
.and_then(NameBinding::macro_kind) == Some(MacroKind::Bang) ||
|
||||
self.macro_use_prelude.get(&path[0].name).cloned()
|
||||
.and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) {
|
||||
// Return some dummy definition, it's enough for error reporting.
|
||||
return Some(
|
||||
PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
|
||||
|
|
@ -3497,16 +3495,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
) -> PathResult<'a> {
|
||||
self.resolve_path_with_invoc_id(base_module, path, opt_ns, Mark::root(),
|
||||
record_used, path_span, crate_lint)
|
||||
self.resolve_path_with_parent_expansion(base_module, path, opt_ns, Mark::root(),
|
||||
record_used, path_span, crate_lint)
|
||||
}
|
||||
|
||||
fn resolve_path_with_invoc_id(
|
||||
fn resolve_path_with_parent_expansion(
|
||||
&mut self,
|
||||
base_module: Option<ModuleOrUniformRoot<'a>>,
|
||||
path: &[Ident],
|
||||
opt_ns: Option<Namespace>, // `None` indicates a module path
|
||||
invoc_id: Mark,
|
||||
parent_expansion: Mark,
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
|
|
@ -3599,8 +3597,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
|
||||
} else if opt_ns == Some(MacroNS) {
|
||||
assert!(ns == TypeNS);
|
||||
self.resolve_lexical_macro_path_segment(ident, ns, invoc_id, record_used,
|
||||
record_used, false, path_span)
|
||||
self.resolve_lexical_macro_path_segment(ident, ns, None, parent_expansion,
|
||||
record_used, record_used, path_span)
|
||||
.map(|(binding, _)| binding)
|
||||
} else {
|
||||
let record_used_id =
|
||||
|
|
|
|||
|
|
@ -109,6 +109,13 @@ pub struct ProcMacError {
|
|||
warn_msg: &'static str,
|
||||
}
|
||||
|
||||
// For compatibility bang macros are skipped when resolving potentially built-in attributes.
|
||||
fn macro_kind_mismatch(name: Name, requirement: Option<MacroKind>, candidate: Option<MacroKind>)
|
||||
-> bool {
|
||||
requirement == Some(MacroKind::Attr) && candidate == Some(MacroKind::Bang) &&
|
||||
(name == "test" || name == "bench" || is_builtin_attr_name(name))
|
||||
}
|
||||
|
||||
impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
||||
fn next_node_id(&mut self) -> ast::NodeId {
|
||||
self.session.next_node_id()
|
||||
|
|
@ -214,24 +221,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
vis: ty::Visibility::Invisible,
|
||||
expansion: Mark::root(),
|
||||
});
|
||||
self.macro_prelude.insert(ident.name, binding);
|
||||
}
|
||||
|
||||
fn add_unshadowable_attr(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
|
||||
let def_id = DefId {
|
||||
krate: BUILTIN_MACROS_CRATE,
|
||||
index: DefIndex::from_array_index(self.macro_map.len(),
|
||||
DefIndexAddressSpace::Low),
|
||||
};
|
||||
let kind = ext.kind();
|
||||
self.macro_map.insert(def_id, ext);
|
||||
let binding = self.arenas.alloc_name_binding(NameBinding {
|
||||
kind: NameBindingKind::Def(Def::Macro(def_id, kind), false),
|
||||
span: DUMMY_SP,
|
||||
vis: ty::Visibility::Invisible,
|
||||
expansion: Mark::root(),
|
||||
});
|
||||
self.unshadowable_attrs.insert(ident.name, binding);
|
||||
if self.builtin_macros.insert(ident.name, binding).is_some() {
|
||||
self.session.span_err(ident.span,
|
||||
&format!("built-in macro `{}` was already defined", ident));
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_imports(&mut self) {
|
||||
|
|
@ -249,7 +242,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
attr::mark_known(&attrs[i]);
|
||||
}
|
||||
|
||||
match self.macro_prelude.get(&name).cloned() {
|
||||
match self.builtin_macros.get(&name).cloned() {
|
||||
Some(binding) => match *binding.get_macro(self) {
|
||||
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
|
||||
return Some(attrs.remove(i))
|
||||
|
|
@ -285,7 +278,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
}
|
||||
let trait_name = traits[j].segments[0].ident.name;
|
||||
let legacy_name = Symbol::intern(&format!("derive_{}", trait_name));
|
||||
if !self.macro_prelude.contains_key(&legacy_name) {
|
||||
if !self.builtin_macros.contains_key(&legacy_name) {
|
||||
continue
|
||||
}
|
||||
let span = traits.remove(j).span;
|
||||
|
|
@ -327,7 +320,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
None
|
||||
}
|
||||
|
||||
fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
|
||||
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
|
||||
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
|
||||
let (path, kind, derives_in_scope) = match invoc.kind {
|
||||
InvocationKind::Attr { attr: None, .. } =>
|
||||
|
|
@ -340,7 +333,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
(path, MacroKind::Derive, &[][..]),
|
||||
};
|
||||
|
||||
let (def, ext) = self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?;
|
||||
let (def, ext) = self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?;
|
||||
|
||||
if let Def::Macro(def_id, _) = def {
|
||||
self.macro_defs.insert(invoc.expansion_data.mark, def_id);
|
||||
|
|
@ -355,10 +348,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
Ok(Some(ext))
|
||||
}
|
||||
|
||||
fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
|
||||
fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
|
||||
derives_in_scope: &[ast::Path], force: bool)
|
||||
-> Result<Lrc<SyntaxExtension>, Determinacy> {
|
||||
Ok(self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?.1)
|
||||
Ok(self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?.1)
|
||||
}
|
||||
|
||||
fn check_unused_macros(&self) {
|
||||
|
|
@ -380,10 +373,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
}
|
||||
|
||||
impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
|
||||
fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
|
||||
derives_in_scope: &[ast::Path], force: bool)
|
||||
-> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
|
||||
let def = self.resolve_macro_to_def_inner(path, kind, scope, derives_in_scope, force);
|
||||
let def = self.resolve_macro_to_def_inner(path, kind, invoc_id, derives_in_scope, force);
|
||||
|
||||
// Report errors and enforce feature gates for the resolved macro.
|
||||
if def != Err(Determinacy::Undetermined) {
|
||||
|
|
@ -453,8 +446,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
let ast::Path { ref segments, span } = *path;
|
||||
let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
|
||||
let invocation = self.invocations[&invoc_id];
|
||||
let module = invocation.module.get();
|
||||
self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };
|
||||
let parent_expansion = invoc_id.parent();
|
||||
let parent_legacy_scope = invocation.parent_legacy_scope.get();
|
||||
self.current_module = invocation.module.get().nearest_item_scope();
|
||||
|
||||
// Possibly apply the macro helper hack
|
||||
if kind == MacroKind::Bang && path.len() == 1 &&
|
||||
|
|
@ -464,8 +458,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
|
||||
if path.len() > 1 {
|
||||
let def = match self.resolve_path_with_invoc_id(None, &path, Some(MacroNS), invoc_id,
|
||||
false, span, CrateLint::No) {
|
||||
let def = match self.resolve_path_with_parent_expansion(None, &path, Some(MacroNS),
|
||||
parent_expansion, false, span,
|
||||
CrateLint::No) {
|
||||
PathResult::NonModule(path_res) => match path_res.base_def() {
|
||||
Def::Err => Err(Determinacy::Determined),
|
||||
def @ _ => {
|
||||
|
|
@ -485,25 +480,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
Err(Determinacy::Determined)
|
||||
},
|
||||
};
|
||||
self.current_module.nearest_item_scope().macro_resolutions.borrow_mut()
|
||||
self.current_module.macro_resolutions.borrow_mut()
|
||||
.push((path.into_boxed_slice(), span));
|
||||
return def;
|
||||
}
|
||||
|
||||
if kind == MacroKind::Attr {
|
||||
if let Some(ext) = self.unshadowable_attrs.get(&path[0].name) {
|
||||
return Ok(ext.def());
|
||||
}
|
||||
}
|
||||
|
||||
let legacy_resolution = self.resolve_legacy_scope(
|
||||
path[0], invoc_id, invocation.parent_legacy_scope.get(), false
|
||||
path[0], Some(kind), parent_expansion, parent_legacy_scope, false
|
||||
);
|
||||
let result = if let Some(legacy_binding) = legacy_resolution {
|
||||
Ok(legacy_binding.def())
|
||||
} else {
|
||||
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, invoc_id, false, force,
|
||||
kind == MacroKind::Attr, span) {
|
||||
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, Some(kind),
|
||||
parent_expansion, false, force, span) {
|
||||
Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
|
||||
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
|
||||
Err(Determinacy::Determined) => {
|
||||
|
|
@ -513,8 +502,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
};
|
||||
|
||||
self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
|
||||
.push((invoc_id, path[0], kind, result.ok()));
|
||||
self.current_module.legacy_macro_resolutions.borrow_mut()
|
||||
.push((path[0], kind, parent_expansion, parent_legacy_scope, result.ok()));
|
||||
|
||||
if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
|
||||
return result;
|
||||
|
|
@ -561,10 +550,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
&mut self,
|
||||
mut ident: Ident,
|
||||
ns: Namespace,
|
||||
invoc_id: Mark,
|
||||
kind: Option<MacroKind>,
|
||||
parent_expansion: Mark,
|
||||
record_used: bool,
|
||||
force: bool,
|
||||
is_attr: bool,
|
||||
path_span: Span,
|
||||
) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
|
||||
// General principles:
|
||||
|
|
@ -585,14 +574,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// (Macro NS)
|
||||
// 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
|
||||
// (open, not controlled).
|
||||
// 2. Macro prelude (language, standard library, user-defined legacy plugins lumped into
|
||||
// one set) (open, the open part is from macro expansions, not controlled).
|
||||
// 2. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
|
||||
// 2a. User-defined prelude from macro-use
|
||||
// (open, the open part is from macro expansions, not controlled).
|
||||
// 2b. Standard library prelude, currently just a macro-use (closed, controlled)
|
||||
// 2c. Language prelude, perhaps including builtin attributes
|
||||
// (closed, controlled, except for legacy plugins).
|
||||
// 3. Builtin attributes (closed, controlled).
|
||||
// 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
|
||||
// 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
|
||||
// 4. Language prelude: builtin attributes (closed, controlled).
|
||||
|
||||
assert!(ns == TypeNS || ns == MacroNS);
|
||||
assert!(force || !record_used); // `record_used` implies `force`
|
||||
|
|
@ -613,12 +600,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
|
||||
enum WhereToResolve<'a> {
|
||||
Module(Module<'a>),
|
||||
MacroPrelude,
|
||||
MacroUsePrelude,
|
||||
BuiltinMacros,
|
||||
BuiltinAttrs,
|
||||
ExternPrelude,
|
||||
ToolPrelude,
|
||||
StdLibPrelude,
|
||||
PrimitiveTypes,
|
||||
BuiltinTypes,
|
||||
}
|
||||
|
||||
// Go through all the scopes and try to resolve the name.
|
||||
|
|
@ -639,8 +627,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
self.current_module = orig_current_module;
|
||||
binding.map(|binding| (binding, FromPrelude(false)))
|
||||
}
|
||||
WhereToResolve::MacroPrelude => {
|
||||
match self.macro_prelude.get(&ident.name).cloned() {
|
||||
WhereToResolve::MacroUsePrelude => {
|
||||
match self.macro_use_prelude.get(&ident.name).cloned() {
|
||||
Some(binding) => Ok((binding, FromPrelude(true))),
|
||||
None => Err(Determinacy::Determined),
|
||||
}
|
||||
}
|
||||
WhereToResolve::BuiltinMacros => {
|
||||
match self.builtin_macros.get(&ident.name).cloned() {
|
||||
Some(binding) => Ok((binding, FromPrelude(true))),
|
||||
None => Err(Determinacy::Determined),
|
||||
}
|
||||
|
|
@ -649,7 +643,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// FIXME: Only built-in attributes are not considered as candidates for
|
||||
// non-attributes to fight off regressions on stable channel (#53205).
|
||||
// We need to come up with some more principled approach instead.
|
||||
if is_attr && is_builtin_attr_name(ident.name) {
|
||||
if kind == Some(MacroKind::Attr) && is_builtin_attr_name(ident.name) {
|
||||
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
|
||||
ty::Visibility::Public, ident.span, Mark::root())
|
||||
.to_name_binding(self.arenas);
|
||||
|
|
@ -708,7 +702,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
result
|
||||
}
|
||||
WhereToResolve::PrimitiveTypes => {
|
||||
WhereToResolve::BuiltinTypes => {
|
||||
if let Some(prim_ty) =
|
||||
self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
|
||||
let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
|
||||
|
|
@ -728,19 +722,20 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
None => {
|
||||
use_prelude = !module.no_implicit_prelude;
|
||||
if ns == MacroNS {
|
||||
WhereToResolve::MacroPrelude
|
||||
WhereToResolve::MacroUsePrelude
|
||||
} else {
|
||||
WhereToResolve::ExternPrelude
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WhereToResolve::MacroPrelude => WhereToResolve::BuiltinAttrs,
|
||||
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
|
||||
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
|
||||
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
|
||||
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
|
||||
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
|
||||
WhereToResolve::StdLibPrelude => WhereToResolve::PrimitiveTypes,
|
||||
WhereToResolve::PrimitiveTypes => break, // nowhere else to search
|
||||
WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
|
||||
WhereToResolve::BuiltinTypes => break, // nowhere else to search
|
||||
};
|
||||
|
||||
continue;
|
||||
|
|
@ -748,6 +743,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
|
||||
match result {
|
||||
Ok(result) => {
|
||||
if macro_kind_mismatch(ident.name, kind, result.0.macro_kind()) {
|
||||
continue_search!();
|
||||
}
|
||||
|
||||
if !record_used {
|
||||
return Ok(result);
|
||||
}
|
||||
|
|
@ -756,7 +755,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// Found another solution, if the first one was "weak", report an error.
|
||||
if result.0.def() != innermost_result.0.def() &&
|
||||
(innermost_result.0.is_glob_import() ||
|
||||
innermost_result.0.may_appear_after(invoc_id, result.0)) {
|
||||
innermost_result.0.may_appear_after(parent_expansion, result.0)) {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
ident,
|
||||
b1: innermost_result.0,
|
||||
|
|
@ -784,9 +783,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
|
||||
let determinacy = Determinacy::determined(force);
|
||||
if determinacy == Determinacy::Determined && is_attr {
|
||||
if determinacy == Determinacy::Determined && kind == Some(MacroKind::Attr) {
|
||||
// For single-segment attributes interpret determinate "no resolution" as a custom
|
||||
// attribute. (Lexical resolution implies the first segment and is_attr should imply
|
||||
// attribute. (Lexical resolution implies the first segment and attr kind should imply
|
||||
// the last segment, so we are certainly working with a single-segment attribute here.)
|
||||
assert!(ns == MacroNS);
|
||||
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom),
|
||||
|
|
@ -800,10 +799,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
|
||||
fn resolve_legacy_scope(&mut self,
|
||||
ident: Ident,
|
||||
invoc_id: Mark,
|
||||
invoc_parent_legacy_scope: LegacyScope<'a>,
|
||||
kind: Option<MacroKind>,
|
||||
parent_expansion: Mark,
|
||||
parent_legacy_scope: LegacyScope<'a>,
|
||||
record_used: bool)
|
||||
-> Option<&'a NameBinding<'a>> {
|
||||
if macro_kind_mismatch(ident.name, kind, Some(MacroKind::Bang)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let ident = ident.modern();
|
||||
|
||||
// This is *the* result, resolution from the scope closest to the resolved identifier.
|
||||
|
|
@ -820,7 +824,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
let mut innermost_result: Option<&NameBinding> = None;
|
||||
|
||||
// Go through all the scopes and try to resolve the name.
|
||||
let mut where_to_resolve = invoc_parent_legacy_scope;
|
||||
let mut where_to_resolve = parent_legacy_scope;
|
||||
loop {
|
||||
let result = match where_to_resolve {
|
||||
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
|
||||
|
|
@ -848,7 +852,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
if let Some(innermost_result) = innermost_result {
|
||||
// Found another solution, if the first one was "weak", report an error.
|
||||
if result.def() != innermost_result.def() &&
|
||||
innermost_result.may_appear_after(invoc_id, result) {
|
||||
innermost_result.may_appear_after(parent_expansion, result) {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
ident,
|
||||
b1: innermost_result,
|
||||
|
|
@ -885,14 +889,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
}
|
||||
|
||||
for &(invoc_id, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() {
|
||||
for &(ident, kind, parent_expansion, parent_legacy_scope, def)
|
||||
in module.legacy_macro_resolutions.borrow().iter() {
|
||||
let span = ident.span;
|
||||
let invocation = self.invocations[&invoc_id];
|
||||
let legacy_resolution = self.resolve_legacy_scope(
|
||||
ident, invoc_id, invocation.parent_legacy_scope.get(), true
|
||||
ident, Some(kind), parent_expansion, parent_legacy_scope, true
|
||||
);
|
||||
let resolution = self.resolve_lexical_macro_path_segment(
|
||||
ident, MacroNS, invoc_id, true, true, kind == MacroKind::Attr, span
|
||||
ident, MacroNS, Some(kind), parent_expansion, true, true, span
|
||||
);
|
||||
|
||||
let check_consistency = |this: &Self, new_def: Def| {
|
||||
|
|
@ -926,12 +930,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
err.emit();
|
||||
},
|
||||
(Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
|
||||
if !from_prelude || legacy_binding.may_appear_after(invoc_id, binding) => {
|
||||
if legacy_binding.def_ignoring_ambiguity() != binding.def_ignoring_ambiguity() {
|
||||
self.report_ambiguity_error(ident, legacy_binding, binding);
|
||||
}
|
||||
if legacy_binding.def() != binding.def_ignoring_ambiguity() &&
|
||||
(!from_prelude ||
|
||||
legacy_binding.may_appear_after(parent_expansion, binding)) => {
|
||||
self.report_ambiguity_error(ident, legacy_binding, binding);
|
||||
},
|
||||
// OK, non-macro-expanded legacy wins over prelude even if defs are different
|
||||
// Also, legacy and modern can co-exist if their defs are same
|
||||
(Some(legacy_binding), Ok(_)) |
|
||||
// OK, unambiguous resolution
|
||||
(Some(legacy_binding), Err(_)) => {
|
||||
|
|
@ -947,6 +952,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
for &(ident, parent_expansion, parent_legacy_scope)
|
||||
in module.builtin_attrs.borrow().iter() {
|
||||
let resolve_legacy = |this: &mut Self| this.resolve_legacy_scope(
|
||||
ident, Some(MacroKind::Attr), parent_expansion, parent_legacy_scope, true
|
||||
);
|
||||
let resolve_modern = |this: &mut Self| this.resolve_lexical_macro_path_segment(
|
||||
ident, MacroNS, Some(MacroKind::Attr), parent_expansion, true, true, ident.span
|
||||
).map(|(binding, _)| binding).ok();
|
||||
|
||||
if let Some(binding) = resolve_legacy(self).or_else(|| resolve_modern(self)) {
|
||||
if binding.def_ignoring_ambiguity() !=
|
||||
Def::NonMacroAttr(NonMacroAttrKind::Builtin) {
|
||||
let builtin_binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
|
||||
ty::Visibility::Public, ident.span, Mark::root())
|
||||
.to_name_binding(self.arenas);
|
||||
self.report_ambiguity_error(ident, binding, builtin_binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
|
||||
|
|
@ -958,14 +983,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
None
|
||||
// Then check global macros.
|
||||
}.or_else(|| {
|
||||
// FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
|
||||
let macro_prelude = self.macro_prelude.clone();
|
||||
let names = macro_prelude.iter().filter_map(|(name, binding)| {
|
||||
if binding.get_macro(self).kind() == kind {
|
||||
Some(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let names = self.builtin_macros.iter().chain(self.macro_use_prelude.iter())
|
||||
.filter_map(|(name, binding)| {
|
||||
if binding.macro_kind() == Some(kind) { Some(name) } else { None }
|
||||
});
|
||||
find_best_match_for_name(names, name, None)
|
||||
// Then check modules.
|
||||
|
|
@ -1063,6 +1083,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
self.define(module, ident, MacroNS,
|
||||
(def, vis, item.span, expansion, IsMacroExport));
|
||||
} else {
|
||||
if !attr::contains_name(&item.attrs, "rustc_doc_only_macro") {
|
||||
self.check_reserved_macro_name(ident, MacroNS);
|
||||
}
|
||||
self.unused_macros.insert(def_id);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
|
|||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::symbol::keywords;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{MultiSpan, Span};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::BTreeMap;
|
||||
|
|
@ -452,6 +452,16 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
|
|||
})
|
||||
}
|
||||
|
||||
crate fn check_reserved_macro_name(&self, ident: Ident, ns: Namespace) {
|
||||
// Reserve some names that are not quite covered by the general check
|
||||
// performed on `Resolver::builtin_attrs`.
|
||||
if ns == MacroNS &&
|
||||
(ident.name == "cfg" || ident.name == "cfg_attr" || ident.name == "derive") {
|
||||
self.session.span_err(ident.span,
|
||||
&format!("name `{}` is reserved in macro namespace", ident));
|
||||
}
|
||||
}
|
||||
|
||||
// Define the name or return the existing binding if there is a collision.
|
||||
pub fn try_define(&mut self,
|
||||
module: Module<'a>,
|
||||
|
|
@ -459,6 +469,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
|
|||
ns: Namespace,
|
||||
binding: &'a NameBinding<'a>)
|
||||
-> Result<(), &'a NameBinding<'a>> {
|
||||
self.check_reserved_macro_name(ident, ns);
|
||||
self.update_resolution(module, ident, ns, |this, resolution| {
|
||||
if let Some(old_binding) = resolution.binding {
|
||||
if binding.is_glob_import() {
|
||||
|
|
@ -620,9 +631,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct UniformPathsCanaryResult {
|
||||
module_scope: Option<Span>,
|
||||
block_scopes: Vec<Span>,
|
||||
struct UniformPathsCanaryResult<'a> {
|
||||
module_scope: Option<&'a NameBinding<'a>>,
|
||||
block_scopes: Vec<&'a NameBinding<'a>>,
|
||||
}
|
||||
// Collect all tripped `uniform_paths` canaries separately.
|
||||
let mut uniform_paths_canaries: BTreeMap<
|
||||
|
|
@ -632,6 +643,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
|
||||
let mut errors = false;
|
||||
let mut seen_spans = FxHashSet();
|
||||
let mut error_vec = Vec::new();
|
||||
let mut prev_root_id: NodeId = NodeId::new(0);
|
||||
for i in 0 .. self.determined_imports.len() {
|
||||
let import = self.determined_imports[i];
|
||||
let error = self.finalize_import(import);
|
||||
|
|
@ -661,20 +674,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
|
||||
self.per_ns(|_, ns| {
|
||||
if let Some(result) = result[ns].get().ok() {
|
||||
if let NameBindingKind::Import { directive, .. } = result.kind {
|
||||
// Skip canaries that resolve to the import itself.
|
||||
// These come from `use crate_name;`, which isn't really
|
||||
// ambiguous, as the import can't actually shadow itself.
|
||||
if directive.id == import.id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if has_explicit_self {
|
||||
// There should only be one `self::x` (module-scoped) canary.
|
||||
assert_eq!(canary_results[ns].module_scope, None);
|
||||
canary_results[ns].module_scope = Some(result.span);
|
||||
assert!(canary_results[ns].module_scope.is_none());
|
||||
canary_results[ns].module_scope = Some(result);
|
||||
} else {
|
||||
canary_results[ns].block_scopes.push(result.span);
|
||||
canary_results[ns].block_scopes.push(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -694,29 +699,59 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
// If the error is a single failed import then create a "fake" import
|
||||
// resolution for it so that later resolve stages won't complain.
|
||||
self.import_dummy_binding(import);
|
||||
if prev_root_id.as_u32() != 0 &&
|
||||
prev_root_id.as_u32() != import.root_id.as_u32() &&
|
||||
!error_vec.is_empty(){
|
||||
// in case of new import line, throw diagnostic message
|
||||
// for previous line.
|
||||
let mut empty_vec = vec![];
|
||||
mem::swap(&mut empty_vec, &mut error_vec);
|
||||
self.throw_unresolved_import_error(empty_vec, None);
|
||||
}
|
||||
if !seen_spans.contains(&span) {
|
||||
let path = import_path_to_string(&import.module_path[..],
|
||||
&import.subclass,
|
||||
span);
|
||||
let error = ResolutionError::UnresolvedImport(Some((span, &path, &err)));
|
||||
resolve_error(self.resolver, span, error);
|
||||
error_vec.push((span, path, err));
|
||||
seen_spans.insert(span);
|
||||
prev_root_id = import.root_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let uniform_paths_feature = self.session.features_untracked().uniform_paths;
|
||||
for ((span, _), (name, results)) in uniform_paths_canaries {
|
||||
self.per_ns(|this, ns| {
|
||||
let results = &results[ns];
|
||||
let external_crate = if ns == TypeNS && this.extern_prelude.contains(&name) {
|
||||
let crate_id =
|
||||
this.crate_loader.process_path_extern(name, span);
|
||||
Some(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let result_filter = |result: &&NameBinding| {
|
||||
// Ignore canaries that resolve to an import of the same crate.
|
||||
// That is, we allow `use crate_name; use crate_name::foo;`.
|
||||
if let Some(def_id) = external_crate {
|
||||
if let Some(module) = result.module() {
|
||||
if module.normal_ancestor_id == def_id {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let has_external_crate =
|
||||
ns == TypeNS && this.extern_prelude.contains(&name);
|
||||
true
|
||||
};
|
||||
let module_scope = results[ns].module_scope.filter(result_filter);
|
||||
let block_scopes = || {
|
||||
results[ns].block_scopes.iter().cloned().filter(result_filter)
|
||||
};
|
||||
|
||||
// An ambiguity requires more than one possible resolution.
|
||||
let possible_resultions =
|
||||
(has_external_crate as usize) +
|
||||
(results.module_scope.is_some() as usize) +
|
||||
(!results.block_scopes.is_empty() as usize);
|
||||
(external_crate.is_some() as usize) +
|
||||
(module_scope.is_some() as usize) +
|
||||
(block_scopes().next().is_some() as usize);
|
||||
if possible_resultions <= 1 {
|
||||
return;
|
||||
}
|
||||
|
|
@ -726,29 +761,42 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
let msg = format!("`{}` import is ambiguous", name);
|
||||
let mut err = this.session.struct_span_err(span, &msg);
|
||||
let mut suggestion_choices = String::new();
|
||||
if has_external_crate {
|
||||
if external_crate.is_some() {
|
||||
write!(suggestion_choices, "`::{}`", name);
|
||||
err.span_label(span,
|
||||
format!("can refer to external crate `::{}`", name));
|
||||
}
|
||||
if let Some(span) = results.module_scope {
|
||||
if let Some(result) = module_scope {
|
||||
if !suggestion_choices.is_empty() {
|
||||
suggestion_choices.push_str(" or ");
|
||||
}
|
||||
write!(suggestion_choices, "`self::{}`", name);
|
||||
err.span_label(span,
|
||||
format!("can refer to `self::{}`", name));
|
||||
if uniform_paths_feature {
|
||||
err.span_label(result.span,
|
||||
format!("can refer to `self::{}`", name));
|
||||
} else {
|
||||
err.span_label(result.span,
|
||||
format!("may refer to `self::{}` in the future", name));
|
||||
}
|
||||
}
|
||||
for &span in &results.block_scopes {
|
||||
err.span_label(span,
|
||||
for result in block_scopes() {
|
||||
err.span_label(result.span,
|
||||
format!("shadowed by block-scoped `{}`", name));
|
||||
}
|
||||
err.help(&format!("write {} explicitly instead", suggestion_choices));
|
||||
err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`");
|
||||
if uniform_paths_feature {
|
||||
err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`");
|
||||
} else {
|
||||
err.note("in the future, `#![feature(uniform_paths)]` may become the default");
|
||||
}
|
||||
err.emit();
|
||||
});
|
||||
}
|
||||
|
||||
if !error_vec.is_empty() {
|
||||
self.throw_unresolved_import_error(error_vec.clone(), None);
|
||||
}
|
||||
|
||||
// Report unresolved imports only if no hard error was already reported
|
||||
// to avoid generating multiple errors on the same import.
|
||||
if !errors {
|
||||
|
|
@ -756,14 +804,37 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
if import.is_uniform_paths_canary {
|
||||
continue;
|
||||
}
|
||||
|
||||
let error = ResolutionError::UnresolvedImport(None);
|
||||
resolve_error(self.resolver, import.span, error);
|
||||
self.throw_unresolved_import_error(error_vec, Some(MultiSpan::from(import.span)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
|
||||
span: Option<MultiSpan>) {
|
||||
let max_span_label_msg_count = 10; // upper limit on number of span_label message.
|
||||
let (span,msg) = match error_vec.is_empty() {
|
||||
true => (span.unwrap(), "unresolved import".to_string()),
|
||||
false => {
|
||||
let span = MultiSpan::from_spans(error_vec.clone().into_iter()
|
||||
.map(|elem: (Span, String, String)| { elem.0 }
|
||||
).collect());
|
||||
let path_vec: Vec<String> = error_vec.clone().into_iter()
|
||||
.map(|elem: (Span, String, String)| { format!("`{}`", elem.1) }
|
||||
).collect();
|
||||
let path = path_vec.join(", ");
|
||||
let msg = format!("unresolved import{} {}",
|
||||
if path_vec.len() > 1 { "s" } else { "" }, path);
|
||||
(span, msg)
|
||||
}
|
||||
};
|
||||
let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
|
||||
for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
|
||||
err.span_label(span_error.0, span_error.2);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Attempts to resolve the given import, returning true if its resolution is determined.
|
||||
/// If successful, the resolved bindings are written into the module.
|
||||
fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
|
||||
|
|
@ -930,11 +1001,15 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// Do not record uses from canaries, to avoid interfering with other
|
||||
// diagnostics or suggestions that rely on some items not being used.
|
||||
let record_used = !directive.is_uniform_paths_canary;
|
||||
|
||||
let mut all_ns_err = true;
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
if let Ok(binding) = result[ns].get() {
|
||||
all_ns_err = false;
|
||||
if this.record_use(ident, ns, binding) {
|
||||
if record_used && this.record_use(ident, ns, binding) {
|
||||
if let ModuleOrUniformRoot::Module(module) = module {
|
||||
this.resolution(module, ident, ns).borrow_mut().binding =
|
||||
Some(this.dummy_binding);
|
||||
|
|
@ -946,7 +1021,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
|||
if all_ns_err {
|
||||
let mut all_ns_failed = true;
|
||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||
match this.resolve_ident_in_module(module, ident, ns, true, span) {
|
||||
match this.resolve_ident_in_module(module, ident, ns, record_used, span) {
|
||||
Ok(_) => all_ns_failed = false,
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
42
src/librustc_target/abi/call/amdgpu.rs
Normal file
42
src/librustc_target/abi/call/amdgpu.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use abi::call::{ArgType, FnType, };
|
||||
use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
|
||||
|
||||
fn classify_ret_ty<'a, Ty, C>(_tuncx: C, ret: &mut ArgType<'a, Ty>)
|
||||
where Ty: TyLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
|
||||
{
|
||||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
fn classify_arg_ty<'a, Ty, C>(_cx: C, arg: &mut ArgType<'a, Ty>)
|
||||
where Ty: TyLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
|
||||
{
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>)
|
||||
where Ty: TyLayoutMethods<'a, C> + Copy,
|
||||
C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
|
||||
{
|
||||
if !fty.ret.is_ignore() {
|
||||
classify_ret_ty(cx, &mut fty.ret);
|
||||
}
|
||||
|
||||
for arg in &mut fty.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg_ty(cx, arg);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
|
|||
use spec::HasTargetSpec;
|
||||
|
||||
mod aarch64;
|
||||
mod amdgpu;
|
||||
mod arm;
|
||||
mod asmjs;
|
||||
mod hexagon;
|
||||
|
|
@ -503,6 +504,7 @@ impl<'a, Ty> FnType<'a, Ty> {
|
|||
x86_64::compute_abi_info(cx, self);
|
||||
},
|
||||
"aarch64" => aarch64::compute_abi_info(cx, self),
|
||||
"amdgpu" => amdgpu::compute_abi_info(cx, self),
|
||||
"arm" => arm::compute_abi_info(cx, self),
|
||||
"mips" => mips::compute_abi_info(cx, self),
|
||||
"mips64" => mips64::compute_abi_info(cx, self),
|
||||
|
|
|
|||
|
|
@ -1257,9 +1257,11 @@ impl DocFolder for Cache {
|
|||
// Collect all the implementors of traits.
|
||||
if let clean::ImplItem(ref i) = item.inner {
|
||||
if let Some(did) = i.trait_.def_id() {
|
||||
self.implementors.entry(did).or_default().push(Impl {
|
||||
impl_item: item.clone(),
|
||||
});
|
||||
if i.blanket_impl.is_none() {
|
||||
self.implementors.entry(did).or_default().push(Impl {
|
||||
impl_item: item.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2931,7 +2933,6 @@ fn item_trait(
|
|||
|
||||
|
||||
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
|
||||
.filter(|i| i.inner_impl().blanket_impl.is_none())
|
||||
.partition(|i| i.inner_impl().synthetic);
|
||||
|
||||
if !foreign.is_empty() {
|
||||
|
|
@ -2941,17 +2942,14 @@ fn item_trait(
|
|||
</h2>
|
||||
")?;
|
||||
|
||||
let mut foreign_cache = FxHashSet();
|
||||
for implementor in foreign {
|
||||
if foreign_cache.insert(implementor.inner_impl().to_string()) {
|
||||
let assoc_link = AssocItemLink::GotoSource(
|
||||
implementor.impl_item.def_id,
|
||||
&implementor.inner_impl().provided_trait_methods
|
||||
);
|
||||
render_impl(w, cx, &implementor, assoc_link,
|
||||
RenderMode::Normal, implementor.impl_item.stable_since(), false,
|
||||
None)?;
|
||||
}
|
||||
let assoc_link = AssocItemLink::GotoSource(
|
||||
implementor.impl_item.def_id,
|
||||
&implementor.inner_impl().provided_trait_methods
|
||||
);
|
||||
render_impl(w, cx, &implementor, assoc_link,
|
||||
RenderMode::Normal, implementor.impl_item.stable_since(), false,
|
||||
None)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,14 +166,14 @@ impl DefaultResizePolicy {
|
|||
// Our hash generation scheme consists of generating a 64-bit hash and
|
||||
// truncating the most significant bits. When moving to the new table, we
|
||||
// simply introduce a new bit to the front of the hash. Therefore, if an
|
||||
// elements has ideal index i in the old table, it can have one of two ideal
|
||||
// element has ideal index i in the old table, it can have one of two ideal
|
||||
// locations in the new table. If the new bit is 0, then the new ideal index
|
||||
// is i. If the new bit is 1, then the new ideal index is n + i. Intuitively,
|
||||
// we are producing two independent tables of size n, and for each element we
|
||||
// independently choose which table to insert it into with equal probability.
|
||||
// However the rather than wrapping around themselves on overflowing their
|
||||
// indexes, the first table overflows into the first, and the first into the
|
||||
// second. Visually, our new table will look something like:
|
||||
// However, rather than wrapping around themselves on overflowing their
|
||||
// indexes, the first table overflows into the second, and the second into the
|
||||
// first. Visually, our new table will look something like:
|
||||
//
|
||||
// [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy]
|
||||
//
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use sys;
|
|||
/// type is a static guarantee that the underlying bytes contain no interior 0
|
||||
/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
|
||||
///
|
||||
/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former
|
||||
/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former
|
||||
/// in each pair are owned strings; the latter are borrowed
|
||||
/// references.
|
||||
///
|
||||
|
|
@ -88,6 +88,7 @@ use sys;
|
|||
/// [slice.len]: ../primitive.slice.html#method.len
|
||||
/// [`Deref`]: ../ops/trait.Deref.html
|
||||
/// [`CStr`]: struct.CStr.html
|
||||
/// [`&CStr`]: struct.CStr.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -137,7 +138,7 @@ pub struct CString {
|
|||
/// converted to a Rust [`&str`] by performing UTF-8 validation, or
|
||||
/// into an owned [`CString`].
|
||||
///
|
||||
/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
|
||||
/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
|
||||
/// in each pair are borrowed references; the latter are owned
|
||||
/// strings.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1330,7 +1330,8 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
|
|||
///
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait BufRead: Read {
|
||||
/// Fills the internal buffer of this object, returning the buffer contents.
|
||||
/// Returns the contents of the internal buffer, filling it with more data
|
||||
/// from the inner reader if it is empty.
|
||||
///
|
||||
/// This function is a lower-level call. It needs to be paired with the
|
||||
/// [`consume`] method to function properly. When calling this
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@
|
|||
#![feature(doc_cfg)]
|
||||
#![feature(doc_masked)]
|
||||
#![feature(doc_spotlight)]
|
||||
#![cfg_attr(windows, feature(used))]
|
||||
#![cfg_attr(all(windows, stage0), feature(used))]
|
||||
#![feature(doc_alias)]
|
||||
#![feature(doc_keyword)]
|
||||
#![feature(panic_info_message)]
|
||||
|
|
|
|||
|
|
@ -721,17 +721,15 @@ pub trait Resolver {
|
|||
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
|
||||
derives: &[Mark]);
|
||||
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
|
||||
fn add_unshadowable_attr(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
|
||||
|
||||
fn resolve_imports(&mut self);
|
||||
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
|
||||
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>, allow_derive: bool)
|
||||
-> Option<Attribute>;
|
||||
|
||||
fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
|
||||
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
|
||||
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
|
||||
|
||||
fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
|
||||
fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
|
||||
derives_in_scope: &[ast::Path], force: bool)
|
||||
-> Result<Lrc<SyntaxExtension>, Determinacy>;
|
||||
|
||||
|
|
@ -761,16 +759,15 @@ impl Resolver for DummyResolver {
|
|||
fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
|
||||
_derives: &[Mark]) {}
|
||||
fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
|
||||
fn add_unshadowable_attr(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
|
||||
|
||||
fn resolve_imports(&mut self) {}
|
||||
fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool)
|
||||
-> Option<Attribute> { None }
|
||||
fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _scope: Mark, _force: bool)
|
||||
fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _invoc_id: Mark, _force: bool)
|
||||
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _scope: Mark,
|
||||
fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark,
|
||||
_derives_in_scope: &[ast::Path], _force: bool)
|
||||
-> Result<Lrc<SyntaxExtension>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
|
|
|
|||
|
|
@ -1074,6 +1074,21 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
self.collect(kind, InvocationKind::Attr { attr, traits, item })
|
||||
}
|
||||
|
||||
fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
|
||||
let attr = attrs.iter()
|
||||
.position(|a| !attr::is_known(a) && !is_builtin_attr(a))
|
||||
.map(|i| attrs.remove(i));
|
||||
if let Some(attr) = &attr {
|
||||
if !self.cx.ecfg.enable_custom_inner_attributes() &&
|
||||
attr.style == ast::AttrStyle::Inner && attr.path != "test" {
|
||||
emit_feature_err(&self.cx.parse_sess, "custom_inner_attributes",
|
||||
attr.span, GateIssue::Language,
|
||||
"non-builtin inner attributes are unstable");
|
||||
}
|
||||
}
|
||||
attr
|
||||
}
|
||||
|
||||
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
|
||||
fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T)
|
||||
where T: HasAttrs,
|
||||
|
|
@ -1087,7 +1102,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
return attrs;
|
||||
}
|
||||
|
||||
attr = find_attr_invoc(&mut attrs);
|
||||
attr = self.find_attr_invoc(&mut attrs);
|
||||
traits = collect_derives(&mut self.cx, &mut attrs);
|
||||
attrs
|
||||
});
|
||||
|
|
@ -1108,7 +1123,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
return attrs;
|
||||
}
|
||||
|
||||
attr = find_attr_invoc(&mut attrs);
|
||||
attr = self.find_attr_invoc(&mut attrs);
|
||||
attrs
|
||||
});
|
||||
|
||||
|
|
@ -1145,12 +1160,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
|
||||
attrs.iter()
|
||||
.position(|a| !attr::is_known(a) && !is_builtin_attr(a))
|
||||
.map(|i| attrs.remove(i))
|
||||
}
|
||||
|
||||
impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
|
||||
let mut expr = self.cfg.configure_expr(expr).into_inner();
|
||||
|
|
@ -1582,6 +1591,12 @@ impl<'feat> ExpansionConfig<'feat> {
|
|||
fn proc_macro_expr = proc_macro_expr,
|
||||
fn proc_macro_non_items = proc_macro_non_items,
|
||||
}
|
||||
|
||||
fn enable_custom_inner_attributes(&self) -> bool {
|
||||
self.features.map_or(false, |features| {
|
||||
features.custom_inner_attributes || features.custom_attribute || features.rustc_attrs
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A Marker adds the given mark to the syntax context.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ use visit::{self, FnKind, Visitor};
|
|||
use parse::ParseSess;
|
||||
use symbol::{keywords, Symbol};
|
||||
|
||||
use std::{env, path};
|
||||
use std::{env};
|
||||
|
||||
macro_rules! set {
|
||||
// The const_fn feature also enables the min_const_fn feature, because `min_const_fn` allows
|
||||
|
|
@ -349,9 +349,6 @@ declare_features! (
|
|||
// Allows the `try {...}` expression
|
||||
(active, try_blocks, "1.29.0", Some(31436), None),
|
||||
|
||||
// Used to preserve symbols (see llvm.used)
|
||||
(active, used, "1.18.0", Some(40289), None),
|
||||
|
||||
// Allows module-level inline assembly by way of global_asm!()
|
||||
(active, global_asm, "1.18.0", Some(35119), None),
|
||||
|
||||
|
|
@ -409,9 +406,6 @@ declare_features! (
|
|||
// Resolve absolute paths as paths from other crates
|
||||
(active, extern_absolute_paths, "1.24.0", Some(44660), Some(Edition::Edition2018)),
|
||||
|
||||
// `foo.rs` as an alternative to `foo/mod.rs`
|
||||
(active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
|
||||
|
||||
// `extern` in paths
|
||||
(active, extern_in_paths, "1.23.0", Some(44660), None),
|
||||
|
||||
|
|
@ -518,6 +512,9 @@ declare_features! (
|
|||
// #![test_runner]
|
||||
// #[test_case]
|
||||
(active, custom_test_frameworks, "1.30.0", Some(50297), None),
|
||||
|
||||
// Non-builtin attributes in inner attribute position
|
||||
(active, custom_inner_attributes, "1.30.0", Some(38356), None),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
|
@ -660,6 +657,8 @@ declare_features! (
|
|||
(accepted, repr_transparent, "1.28.0", Some(43036), None),
|
||||
// Defining procedural macros in `proc-macro` crates
|
||||
(accepted, proc_macro, "1.29.0", Some(38356), None),
|
||||
// `foo.rs` as an alternative to `foo/mod.rs`
|
||||
(accepted, non_modrs_mods, "1.30.0", Some(44660), None),
|
||||
// Allows use of the :vis macro fragment specifier
|
||||
(accepted, macro_vis_matcher, "1.30.0", Some(41022), None),
|
||||
// Allows importing and reexporting macros with `use`,
|
||||
|
|
@ -674,6 +673,9 @@ declare_features! (
|
|||
// Allows all literals in attribute lists and values of key-value pairs.
|
||||
(accepted, attr_literals, "1.30.0", Some(34981), None),
|
||||
(accepted, panic_handler, "1.30.0", Some(44489), None),
|
||||
// Used to preserve symbols (see llvm.used)
|
||||
(accepted, used, "1.30.0", Some(40289), None),
|
||||
|
||||
);
|
||||
|
||||
// If you change this, please modify src/doc/unstable-book as well. You must
|
||||
|
|
@ -1068,10 +1070,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
|
|||
"unwind_attributes",
|
||||
"#[unwind] is experimental",
|
||||
cfg_fn!(unwind_attributes))),
|
||||
("used", Whitelisted, Gated(
|
||||
Stability::Unstable, "used",
|
||||
"the `#[used]` attribute is an experimental feature",
|
||||
cfg_fn!(used))),
|
||||
("used", Whitelisted, Ungated),
|
||||
|
||||
// used in resolve
|
||||
("prelude_import", Whitelisted, Gated(Stability::Unstable,
|
||||
|
|
@ -1498,31 +1497,6 @@ impl<'a> PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> PostExpansionVisitor<'a> {
|
||||
fn whole_crate_feature_gates(&mut self, _krate: &ast::Crate) {
|
||||
for &(ident, span) in &*self.context.parse_sess.non_modrs_mods.borrow() {
|
||||
if !span.allows_unstable() {
|
||||
let cx = &self.context;
|
||||
let level = GateStrength::Hard;
|
||||
let has_feature = cx.features.non_modrs_mods;
|
||||
let name = "non_modrs_mods";
|
||||
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}",
|
||||
name, span, has_feature);
|
||||
|
||||
if !has_feature && !span.allows_unstable() {
|
||||
leveled_feature_err(
|
||||
cx.parse_sess, name, span, GateIssue::Language,
|
||||
"mod statements in non-mod.rs files are unstable", level
|
||||
)
|
||||
.help(&format!("on stable builds, rename this file to {}{}mod.rs",
|
||||
ident, path::MAIN_SEPARATOR))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
||||
if !attr.span.allows_unstable() {
|
||||
|
|
@ -2092,7 +2066,6 @@ pub fn check_crate(krate: &ast::Crate,
|
|||
};
|
||||
|
||||
let visitor = &mut PostExpansionVisitor { context: &ctx };
|
||||
visitor.whole_crate_feature_gates(krate);
|
||||
visit::walk_crate(visitor, krate);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,10 +66,10 @@ pub struct StringReader<'a> {
|
|||
/// The raw source span which *does not* take `override_span` into account
|
||||
span_src_raw: Span,
|
||||
open_braces: Vec<(token::DelimToken, Span)>,
|
||||
/// The type and spans for all braces that have different indentation.
|
||||
/// The type and spans for all braces
|
||||
///
|
||||
/// Used only for error recovery when arriving to EOF with mismatched braces.
|
||||
suspicious_open_spans: Vec<(token::DelimToken, Span, Span)>,
|
||||
matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
|
||||
crate override_span: Option<Span>,
|
||||
last_unclosed_found_span: Option<Span>,
|
||||
}
|
||||
|
|
@ -220,7 +220,7 @@ impl<'a> StringReader<'a> {
|
|||
span: syntax_pos::DUMMY_SP,
|
||||
span_src_raw: syntax_pos::DUMMY_SP,
|
||||
open_braces: Vec::new(),
|
||||
suspicious_open_spans: Vec::new(),
|
||||
matching_delim_spans: Vec::new(),
|
||||
override_span,
|
||||
last_unclosed_found_span: None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ impl<'a> StringReader<'a> {
|
|||
}
|
||||
|
||||
fn parse_token_tree(&mut self) -> PResult<'a, TokenStream> {
|
||||
let sm = self.sess.source_map();
|
||||
match self.token {
|
||||
token::Eof => {
|
||||
let msg = "this file contains an un-closed delimiter";
|
||||
|
|
@ -53,20 +54,25 @@ impl<'a> StringReader<'a> {
|
|||
}
|
||||
|
||||
if let Some((delim, _)) = self.open_braces.last() {
|
||||
if let Some((d, open_sp, close_sp)) = self.suspicious_open_spans.iter()
|
||||
.filter(|(d, _, _)| delim == d)
|
||||
.next() // these are in reverse order as they get inserted on close, but
|
||||
{ // we want the last open/first close
|
||||
if d == delim {
|
||||
err.span_label(
|
||||
*open_sp,
|
||||
"this delimiter might not be properly closed...",
|
||||
);
|
||||
err.span_label(
|
||||
*close_sp,
|
||||
"...as it matches this but it has different indentation",
|
||||
);
|
||||
if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter()
|
||||
.filter(|(d, open_sp, close_sp)| {
|
||||
|
||||
if let Some(close_padding) = sm.span_to_margin(*close_sp) {
|
||||
if let Some(open_padding) = sm.span_to_margin(*open_sp) {
|
||||
return delim == d && close_padding != open_padding;
|
||||
}
|
||||
}
|
||||
false
|
||||
}).next() // these are in reverse order as they get inserted on close, but
|
||||
{ // we want the last open/first close
|
||||
err.span_label(
|
||||
*open_sp,
|
||||
"this delimiter might not be properly closed...",
|
||||
);
|
||||
err.span_label(
|
||||
*close_sp,
|
||||
"...as it matches this but it has different indentation",
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err)
|
||||
|
|
@ -87,20 +93,11 @@ impl<'a> StringReader<'a> {
|
|||
// Expand to cover the entire delimited token tree
|
||||
let delim_span = DelimSpan::from_pair(pre_span, self.span);
|
||||
|
||||
let sm = self.sess.source_map();
|
||||
match self.token {
|
||||
// Correct delimiter.
|
||||
token::CloseDelim(d) if d == delim => {
|
||||
let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
|
||||
if let Some(current_padding) = sm.span_to_margin(self.span) {
|
||||
if let Some(padding) = sm.span_to_margin(open_brace_span) {
|
||||
if current_padding != padding {
|
||||
self.suspicious_open_spans.push(
|
||||
(open_brace, open_brace_span, self.span),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.matching_delim_spans.push((open_brace, open_brace_span, self.span));
|
||||
// Parse the close delimiter.
|
||||
self.real_token();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,18 +72,6 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
|
|||
enable_quotes: bool) {
|
||||
deriving::register_builtin_derives(resolver);
|
||||
|
||||
{
|
||||
let mut register_unshadowable = |name, ext| {
|
||||
resolver.add_unshadowable_attr(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
|
||||
};
|
||||
|
||||
register_unshadowable(Symbol::intern("test"),
|
||||
MultiModifier(Box::new(test::expand_test)));
|
||||
|
||||
register_unshadowable(Symbol::intern("bench"),
|
||||
MultiModifier(Box::new(test::expand_bench)));
|
||||
}
|
||||
|
||||
let mut register = |name, ext| {
|
||||
resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
|
||||
};
|
||||
|
|
@ -147,6 +135,8 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
|
|||
}
|
||||
|
||||
register(Symbol::intern("test_case"), MultiModifier(Box::new(test_case::expand)));
|
||||
register(Symbol::intern("test"), MultiModifier(Box::new(test::expand_test)));
|
||||
register(Symbol::intern("bench"), MultiModifier(Box::new(test::expand_bench)));
|
||||
|
||||
// format_args uses `unstable` things internally.
|
||||
register(Symbol::intern("format_args"),
|
||||
|
|
|
|||
2
src/llvm
2
src/llvm
|
|
@ -1 +1 @@
|
|||
Subproject commit 2a1cdeadd3ea8e1eba9cc681037b83f07332763b
|
||||
Subproject commit 5a081f0363340dd895d0958955d0c84661f60f05
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
|
||||
# The actual contents of this file do not matter, but to trigger a change on the
|
||||
# build bots then the contents should be changed so git updates the mtime.
|
||||
2018-08-22
|
||||
2018-09-11
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
// aux-build:attribute-with-error.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(custom_inner_attributes)]
|
||||
|
||||
extern crate attribute_with_error;
|
||||
|
||||
use attribute_with_error::foo;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
// FIXME: https://github.com/rust-lang/rust/issues/41430
|
||||
// This is a temporary regression test for the ICE reported in #41211
|
||||
|
||||
#![feature(custom_inner_attributes)]
|
||||
|
||||
#![emit_unchanged]
|
||||
//~^ ERROR attribute `emit_unchanged` is currently unknown to the compiler
|
||||
extern crate issue_41211;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ extern crate proc_macro_gates as foo;
|
|||
use foo::*;
|
||||
|
||||
fn _test_inner() {
|
||||
#![a] // OK
|
||||
#![a] //~ ERROR: non-builtin inner attributes are unstable
|
||||
}
|
||||
|
||||
#[a] //~ ERROR: custom attributes cannot be applied to modules
|
||||
|
|
@ -30,6 +30,7 @@ mod _test2 {}
|
|||
|
||||
mod _test2_inner {
|
||||
#![a] //~ ERROR: custom attributes cannot be applied to modules
|
||||
//~| ERROR: non-builtin inner attributes are unstable
|
||||
}
|
||||
|
||||
#[a = y] //~ ERROR: must only be followed by a delimiter token
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub fn add_type() {
|
|||
|
||||
#[cfg(not(cfail1))]
|
||||
#[rustc_clean(cfg="cfail2",
|
||||
except="HirBody,TypeckTables,MirValidated")]
|
||||
except="HirBody,TypeckTables,MirValidated,MirOptimized")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
pub fn add_type() {
|
||||
let _x: u32 = 2u32;
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// check that codegen of assignment expressions is sane. Assignments
|
||||
// tend to be absent in simple code, so subtle breakage in them can
|
||||
// leave a quite hard-to-find trail of destruction.
|
||||
// Check codegen for assignments (`a = b`) where the left-hand-side is
|
||||
// not yet initialized. Assignments tend to be absent in simple code,
|
||||
// so subtle breakage in them can leave a quite hard-to-find trail of
|
||||
// destruction.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
|
|
@ -29,60 +30,42 @@ fn main() {
|
|||
let nodrop_x = false;
|
||||
let nodrop_y;
|
||||
|
||||
// Since boolean does not require drop, this can be a simple
|
||||
// assignment:
|
||||
nodrop_y = nodrop_x;
|
||||
|
||||
let drop_x : Option<Box<u32>> = None;
|
||||
let drop_y;
|
||||
|
||||
// Since the type of `drop_y` has drop, we generate a `replace`
|
||||
// terminator:
|
||||
drop_y = drop_x;
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.SimplifyCfg-initial.after.mir
|
||||
// bb0: {
|
||||
// StorageLive(_1);
|
||||
// _1 = const false;
|
||||
// StorageLive(_2);
|
||||
// StorageLive(_3);
|
||||
// _3 = _1;
|
||||
// _2 = move _3;
|
||||
// StorageDead(_3);
|
||||
// StorageLive(_4);
|
||||
// UserAssertTy(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }, _4);
|
||||
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
|
||||
// StorageLive(_5);
|
||||
// StorageLive(_6);
|
||||
// _6 = move _4;
|
||||
// replace(_5 <-move _6) -> [return: bb2, unwind: bb5];
|
||||
// }
|
||||
// bb1: {
|
||||
// resume;
|
||||
// }
|
||||
// bb2: {
|
||||
// drop(_6) -> [return: bb6, unwind: bb4];
|
||||
// }
|
||||
// bb3: {
|
||||
// drop(_4) -> bb1;
|
||||
// }
|
||||
// bb4: {
|
||||
// drop(_5) -> bb3;
|
||||
// }
|
||||
// bb5: {
|
||||
// drop(_6) -> bb4;
|
||||
// }
|
||||
// bb6: {
|
||||
// StorageDead(_6);
|
||||
// _0 = ();
|
||||
// drop(_5) -> [return: bb7, unwind: bb3];
|
||||
// }
|
||||
// bb7: {
|
||||
// StorageDead(_5);
|
||||
// drop(_4) -> [return: bb8, unwind: bb1];
|
||||
// }
|
||||
// bb8: {
|
||||
// StorageDead(_4);
|
||||
// StorageDead(_2);
|
||||
// StorageDead(_1);
|
||||
// return;
|
||||
// }
|
||||
// bb0: {
|
||||
// StorageLive(_1);
|
||||
// _1 = const false;
|
||||
// StorageLive(_2);
|
||||
// StorageLive(_3);
|
||||
// _3 = _1;
|
||||
// _2 = move _3;
|
||||
// StorageDead(_3);
|
||||
// StorageLive(_4);
|
||||
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
|
||||
// AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
|
||||
// StorageLive(_5);
|
||||
// StorageLive(_6);
|
||||
// _6 = move _4;
|
||||
// replace(_5 <- move _6) -> [return: bb2, unwind: bb5];
|
||||
// }
|
||||
// ...
|
||||
// bb2: {
|
||||
// drop(_6) -> [return: bb6, unwind: bb4];
|
||||
// }
|
||||
// ...
|
||||
// bb5: {
|
||||
// drop(_6) -> bb4;
|
||||
// }
|
||||
// END rustc.main.SimplifyCfg-initial.after.mir
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Basic test for reborrow constraints: the region (`R5`) that appears
|
||||
// in the type of `r_a` must outlive the region (`R7`) that appears in
|
||||
// the type of `r_b`
|
||||
|
||||
// compile-flags:-Zborrowck=mir -Zverbose
|
||||
// ^^^^^^^^^ force compiler to dump more region information
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
fn use_x(_: &mut i32) -> bool { true }
|
||||
|
||||
fn main() {
|
||||
let mut foo: i32 = 22;
|
||||
let r_a: &mut i32 = &mut foo;
|
||||
let r_b: &mut i32 = &mut *r_a;
|
||||
use_x(r_b);
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#7r | U0 | {bb0[4], bb0[8..=17]}
|
||||
// ...
|
||||
// | '_#9r | U0 | {bb0[10], bb0[14..=17]}
|
||||
// ...
|
||||
// let _4: &'_#9r mut i32;
|
||||
// ...
|
||||
// let _2: &'_#7r mut i32;
|
||||
// END rustc.main.nll.0.mir
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(used)]
|
||||
|
||||
#[used]
|
||||
static FOO: u32 = 0;
|
||||
|
|
|
|||
1
src/test/run-pass/.gitattributes
vendored
1
src/test/run-pass/.gitattributes
vendored
|
|
@ -1,2 +1 @@
|
|||
lexer-crlf-line-endings-string-literal-doc-comment.rs -text
|
||||
issue-16278.rs -text
|
||||
|
|
|
|||
|
|
@ -67,6 +67,13 @@ fn async_block(x: u8) -> impl Future<Output = u8> {
|
|||
}
|
||||
}
|
||||
|
||||
fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
|
||||
async move {
|
||||
await!(wake_and_yield_once());
|
||||
*x
|
||||
}
|
||||
}
|
||||
|
||||
fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
|
||||
async move {
|
||||
let future = async {
|
||||
|
|
@ -94,6 +101,23 @@ async fn async_fn_with_borrow(x: &u8) -> u8 {
|
|||
*x
|
||||
}
|
||||
|
||||
async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
|
||||
await!(wake_and_yield_once());
|
||||
*x
|
||||
}
|
||||
|
||||
fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
|
||||
async move {
|
||||
await!(wake_and_yield_once());
|
||||
*x
|
||||
}
|
||||
}
|
||||
|
||||
async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 {
|
||||
await!(wake_and_yield_once());
|
||||
*x
|
||||
}
|
||||
|
||||
fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
|
||||
async move {
|
||||
await!(async_fn_with_borrow(&y))
|
||||
|
|
@ -138,16 +162,43 @@ where
|
|||
|
||||
fn main() {
|
||||
macro_rules! test {
|
||||
($($fn_name:ident,)*) => { $(
|
||||
($($fn_name:expr,)*) => { $(
|
||||
test_future_yields_once_then_returns($fn_name);
|
||||
)* }
|
||||
}
|
||||
|
||||
macro_rules! test_with_borrow {
|
||||
($($fn_name:expr,)*) => { $(
|
||||
test_future_yields_once_then_returns(|x| {
|
||||
async move {
|
||||
await!($fn_name(&x))
|
||||
}
|
||||
});
|
||||
)* }
|
||||
}
|
||||
|
||||
test! {
|
||||
async_block,
|
||||
async_nonmove_block,
|
||||
async_closure,
|
||||
async_fn,
|
||||
async_fn_with_internal_borrow,
|
||||
|x| {
|
||||
async move {
|
||||
unsafe { await!(unsafe_async_fn(x)) }
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
test_with_borrow! {
|
||||
async_block_with_borrow_named_lifetime,
|
||||
async_fn_with_borrow,
|
||||
async_fn_with_borrow_named_lifetime,
|
||||
async_fn_with_impl_future_named_lifetime,
|
||||
|x| {
|
||||
async move {
|
||||
await!(async_fn_with_named_lifetime_multiple_args(x, x))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
|
@ -8,8 +8,4 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[used]
|
||||
fn foo() {}
|
||||
//~^^ ERROR the `#[used]` attribute is an experimental feature
|
||||
|
||||
fn main() {}
|
||||
pub struct MyStruct;
|
||||
26
src/test/rustdoc/issue-53689.rs
Normal file
26
src/test/rustdoc/issue-53689.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:issue-53689.rs
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
extern crate issue_53689;
|
||||
|
||||
// @has foo/trait.MyTrait.html
|
||||
// @!has - 'MyStruct'
|
||||
// @count - '//*[code="impl<T> MyTrait for T"]' 1
|
||||
pub trait MyTrait {}
|
||||
|
||||
impl<T> MyTrait for T {}
|
||||
|
||||
mod a {
|
||||
pub use issue_53689::MyStruct;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// aux-build:builtin-attrs.rs
|
||||
// compile-flags:--test
|
||||
|
||||
#![feature(decl_macro, test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate builtin_attrs;
|
||||
use builtin_attrs::{test, bench};
|
||||
|
||||
#[test] // OK, shadowed
|
||||
fn test() {}
|
||||
|
||||
#[bench] // OK, shadowed
|
||||
fn bench(b: &mut test::Bencher) {}
|
||||
|
||||
fn not_main() {
|
||||
Test;
|
||||
Bench;
|
||||
NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
error[E0425]: cannot find value `NonExistent` in this scope
|
||||
--> $DIR/ambiguous-builtin-attrs-test.rs:19:5
|
||||
|
|
||||
LL | NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
31
src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs
Normal file
31
src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// aux-build:builtin-attrs.rs
|
||||
|
||||
#![feature(decl_macro)] //~ ERROR `feature` is ambiguous
|
||||
|
||||
extern crate builtin_attrs;
|
||||
use builtin_attrs::{test, bench};
|
||||
use builtin_attrs::*;
|
||||
|
||||
#[repr(C)] //~ ERROR `repr` is ambiguous
|
||||
struct S;
|
||||
#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
|
||||
struct SCond;
|
||||
|
||||
#[test] // OK, shadowed
|
||||
fn test() {}
|
||||
|
||||
#[bench] // OK, shadowed
|
||||
fn bench() {}
|
||||
|
||||
fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous
|
||||
match 0u8 {
|
||||
#[repr(C)] //~ ERROR `repr` is ambiguous
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Test;
|
||||
Bench;
|
||||
NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
|
||||
}
|
||||
100
src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr
Normal file
100
src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
error[E0659]: `repr` is ambiguous
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:9:3
|
||||
|
|
||||
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
|
||||
| ^^^^ ambiguous name
|
||||
|
|
||||
note: `repr` could refer to the name imported here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:7:5
|
||||
|
|
||||
LL | use builtin_attrs::*;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
note: `repr` could also refer to the name defined here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:9:3
|
||||
|
|
||||
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
|
||||
| ^^^^
|
||||
= note: consider adding an explicit import of `repr` to disambiguate
|
||||
|
||||
error[E0659]: `repr` is ambiguous
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:11:19
|
||||
|
|
||||
LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
|
||||
| ^^^^ ambiguous name
|
||||
|
|
||||
note: `repr` could refer to the name imported here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:7:5
|
||||
|
|
||||
LL | use builtin_attrs::*;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
note: `repr` could also refer to the name defined here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:11:19
|
||||
|
|
||||
LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
|
||||
| ^^^^
|
||||
= note: consider adding an explicit import of `repr` to disambiguate
|
||||
|
||||
error[E0659]: `repr` is ambiguous
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:20:34
|
||||
|
|
||||
LL | fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous
|
||||
| ^^^^ ambiguous name
|
||||
|
|
||||
note: `repr` could refer to the name imported here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:7:5
|
||||
|
|
||||
LL | use builtin_attrs::*;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
note: `repr` could also refer to the name defined here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:20:34
|
||||
|
|
||||
LL | fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous
|
||||
| ^^^^
|
||||
= note: consider adding an explicit import of `repr` to disambiguate
|
||||
|
||||
error[E0659]: `repr` is ambiguous
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:22:11
|
||||
|
|
||||
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
|
||||
| ^^^^ ambiguous name
|
||||
|
|
||||
note: `repr` could refer to the name imported here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:7:5
|
||||
|
|
||||
LL | use builtin_attrs::*;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
note: `repr` could also refer to the name defined here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:22:11
|
||||
|
|
||||
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
|
||||
| ^^^^
|
||||
= note: consider adding an explicit import of `repr` to disambiguate
|
||||
|
||||
error[E0659]: `feature` is ambiguous
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:3:4
|
||||
|
|
||||
LL | #![feature(decl_macro)] //~ ERROR `feature` is ambiguous
|
||||
| ^^^^^^^ ambiguous name
|
||||
|
|
||||
note: `feature` could refer to the name imported here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:7:5
|
||||
|
|
||||
LL | use builtin_attrs::*;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
note: `feature` could also refer to the name defined here
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:3:4
|
||||
|
|
||||
LL | #![feature(decl_macro)] //~ ERROR `feature` is ambiguous
|
||||
| ^^^^^^^
|
||||
= note: consider adding an explicit import of `feature` to disambiguate
|
||||
|
||||
error[E0425]: cannot find value `NonExistent` in this scope
|
||||
--> $DIR/ambiguous-builtin-attrs.rs:30:5
|
||||
|
|
||||
LL | NonExistent; //~ ERROR cannot find value `NonExistent` in this scope
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors occurred: E0425, E0659.
|
||||
For more information about an error, try `rustc --explain E0425`.
|
||||
36
src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs
Normal file
36
src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn feature(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn repr(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn test(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
"struct Test;".parse().unwrap()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn bench(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
"struct Bench;".parse().unwrap()
|
||||
}
|
||||
22
src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs
Normal file
22
src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn cfg(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
//~^ ERROR name `cfg` is reserved in macro namespace
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
//~^ ERROR name `cfg_attr` is reserved in macro namespace
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
//~^ ERROR name `derive` is reserved in macro namespace
|
||||
input
|
||||
}
|
||||
20
src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr
Normal file
20
src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
error: name `cfg` is reserved in macro namespace
|
||||
--> $DIR/reserved-macro-names.rs:7:8
|
||||
|
|
||||
LL | pub fn cfg(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
| ^^^
|
||||
|
||||
error: name `cfg_attr` is reserved in macro namespace
|
||||
--> $DIR/reserved-macro-names.rs:13:8
|
||||
|
|
||||
LL | pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
| ^^^^^^^^
|
||||
|
||||
error: name `derive` is reserved in macro namespace
|
||||
--> $DIR/reserved-macro-names.rs:19:8
|
||||
|
|
||||
LL | pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
error: `foo` is not yet stable as a const fn
|
||||
--> $DIR/dont_promote_unstable_const_fn.rs:25:25
|
||||
|
|
||||
LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
|
||||
| ^^^^^
|
||||
|
|
||||
= help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable
|
||||
|
||||
error[E0597]: borrowed value does not live long enough
|
||||
--> $DIR/dont_promote_unstable_const_fn.rs:33:26
|
||||
|
|
||||
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
|
||||
LL | //~^ does not live long enough
|
||||
LL | }
|
||||
| - temporary value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
error[E0597]: borrowed value does not live long enough
|
||||
--> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29
|
||||
|
|
||||
LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
|
||||
| ^^^^^ temporary value does not live long enough
|
||||
LL | }
|
||||
| - temporary value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for the static lifetime...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue