Merge branch 'master' into kenta7777#53719

This commit is contained in:
kenta7777 2018-09-12 21:36:31 +09:00
commit 26dbf56196
157 changed files with 3527 additions and 1898 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(..) =>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
::ty::ClosureKind,
::ty::IntVarValue,
::ty::ParamTy,
::ty::Variance,
::syntax_pos::Span,
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -304,7 +304,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
}
StatementKind::EndRegion(_) |
StatementKind::Validate(..) |
StatementKind::UserAssertTy(..) |
StatementKind::AscribeUserType(..) |
StatementKind::Nop => {}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -230,7 +230,7 @@ fn check_statement(
| StatementKind::StorageDead(_)
| StatementKind::Validate(..)
| StatementKind::EndRegion(_)
| StatementKind::UserAssertTy(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Nop => Ok(()),
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,
_ => {}
}

View 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);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

@ -1 +1 @@
Subproject commit 2a1cdeadd3ea8e1eba9cc681037b83f07332763b
Subproject commit 5a081f0363340dd895d0958955d0c84661f60f05

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,6 @@
// except according to those terms.
#![crate_type = "lib"]
#![feature(used)]
#[used]
static FOO: u32 = 0;

View file

@ -1,2 +1 @@
lexer-crlf-line-endings-string-literal-doc-comment.rs -text
issue-16278.rs -text

View file

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

View file

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

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

View file

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

View file

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

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

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

View 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()
}

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

View 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

View file

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

View file

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