diff options
| author | kenta7777 <k.hasegw7@gmail.com> | 2018-09-12 21:36:31 +0900 |
|---|---|---|
| committer | kenta7777 <k.hasegw7@gmail.com> | 2018-09-12 21:36:31 +0900 |
| commit | 26dbf56196ccd50a335f38755ea7546f6f1399bd (patch) | |
| tree | 6c099ff00be225c42e653384ca198cf457879cef /src | |
| parent | 8134ee25b88df98c79792d60cbf6745b6cb7ffc5 (diff) | |
| parent | 8586ec6980462c99a8926646201b2444d8938d29 (diff) | |
| download | rust-26dbf56196ccd50a335f38755ea7546f6f1399bd.tar.gz rust-26dbf56196ccd50a335f38755ea7546f6f1399bd.zip | |
Merge branch 'master' into kenta7777#53719
Diffstat (limited to 'src')
156 files changed, 3525 insertions, 1896 deletions
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 98c353eb6ec..1e01d68fb3a 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -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/ diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md index bf345a24389..49c0026ce1a 100644 --- a/src/doc/rustc/src/lints/index.md +++ b/src/doc/rustc/src/lints/index.md @@ -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 | diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 19bb6707d22..072c7585934 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -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() {} diff --git a/src/doc/unstable-book/src/language-features/used.md b/src/doc/unstable-book/src/language-features/used.md deleted file mode 100644 index d49271382b6..00000000000 --- a/src/doc/unstable-book/src/language-features/used.md +++ /dev/null @@ -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> -``` diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 5ae984a4b15..12da0455cc5 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -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 /// /// ``` diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c4b4a0fd72a..93ee11aac36 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -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. /// diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index d4737052875..1de9cd35442 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -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); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cab620aeec5..cf832aee534 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -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(..) => diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 8b7438cbe63..5f35c9fea0a 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -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 } => { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a092bac5187..e628a3458f9 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -10,41 +10,41 @@ //! See the Book for more information. +pub use self::freshen::TypeFreshener; pub use self::LateBoundRegionConversionTime::*; pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; pub use ty::IntVarValue; -pub use self::freshen::TypeFreshener; +use arena::SyncDroplessArena; +use errors::DiagnosticBuilder; use hir::def_id::DefId; use middle::free_region::RegionRelations; -use middle::region; use middle::lang_items; -use ty::subst::{Kind, Substs}; -use ty::{TyVid, IntVid, FloatVid}; -use ty::{self, Ty, TyCtxt, GenericParamDefKind}; -use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use ty::fold::TypeFoldable; -use ty::relate::RelateResult; -use traits::{self, ObligationCause, PredicateObligations, TraitEngine}; +use middle::region; use rustc_data_structures::unify as ut; -use std::cell::{Cell, RefCell, Ref, RefMut}; +use std::cell::{Cell, Ref, RefCell, RefMut}; use std::collections::BTreeMap; use std::fmt; use syntax::ast; -use errors::DiagnosticBuilder; -use syntax_pos::{self, Span}; use syntax_pos::symbol::InternedString; +use syntax_pos::{self, Span}; +use traits::{self, ObligationCause, PredicateObligations, TraitEngine}; +use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; +use ty::fold::TypeFoldable; +use ty::relate::RelateResult; +use ty::subst::{Kind, Substs}; +use ty::{self, GenericParamDefKind, Ty, TyCtxt}; +use ty::{FloatVid, IntVid, TyVid}; use util::nodemap::FxHashMap; -use arena::SyncDroplessArena; use self::combine::CombineFields; use self::higher_ranked::HrMatchResult; -use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; -use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarInfos}; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; +use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; +use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; @@ -54,16 +54,16 @@ pub mod canonical; mod combine; mod equate; pub mod error_reporting; +mod freshen; mod fudge; mod glb; mod higher_ranked; pub mod lattice; -mod lub; -pub mod region_constraints; mod lexical_region_resolve; +mod lub; pub mod outlives; +pub mod region_constraints; pub mod resolve; -mod freshen; mod sub; pub mod type_variable; pub mod unify_key; @@ -80,7 +80,7 @@ pub type Bound<T> = Option<T>; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type FixupResult<T> = Result<T, FixupError>; // "fixup result" -pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, /// During type-checking/inference of a body, `in_progress_tables` @@ -314,10 +314,10 @@ pub enum SubregionOrigin<'tcx> { /// Places that type/region parameters can appear. #[derive(Clone, Copy, Debug)] pub enum ParameterOrigin { - Path, // foo::bar - MethodCall, // foo.bar() <-- parameters on impl providing bar() + Path, // foo::bar + MethodCall, // foo.bar() <-- parameters on impl providing bar() OverloadedOperator, // a + b when overloaded - OverloadedDeref, // *a when overloaded + OverloadedDeref, // *a when overloaded } /// Times when we replace late-bound regions with variables: @@ -400,7 +400,7 @@ impl NLLRegionVariableOrigin { pub enum FixupError { UnresolvedIntTy(IntVid), UnresolvedFloatTy(FloatVid), - UnresolvedTy(TyVid) + UnresolvedTy(TyVid), } /// See the `region_obligations` field for more information. @@ -416,15 +416,17 @@ impl fmt::Display for FixupError { use self::FixupError::*; match *self { - UnresolvedIntTy(_) => { - write!(f, "cannot determine the type of this integer; \ - add a suffix to specify the type explicitly") - } - UnresolvedFloatTy(_) => { - write!(f, "cannot determine the type of this number; \ - add a suffix to specify the type explicitly") - } - UnresolvedTy(_) => write!(f, "unconstrained type") + UnresolvedIntTy(_) => write!( + f, + "cannot determine the type of this integer; \ + add a suffix to specify the type explicitly" + ), + UnresolvedFloatTy(_) => write!( + f, + "cannot determine the type of this number; \ + add a suffix to specify the type explicitly" + ), + UnresolvedTy(_) => write!(f, "unconstrained type"), } } } @@ -432,7 +434,7 @@ impl fmt::Display for FixupError { /// Helper type of a temporary returned by tcx.infer_ctxt(). /// Necessary because we can't write the following bound: /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>). -pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +pub struct InferCtxtBuilder<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { global_tcx: TyCtxt<'a, 'gcx, 'gcx>, arena: SyncDroplessArena, fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>, @@ -444,7 +446,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { global_tcx: self, arena: SyncDroplessArena::new(), fresh_tables: None, - } } } @@ -458,7 +459,8 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { } pub fn enter<F, R>(&'tcx mut self, f: F) -> R - where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R + where + F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R, { let InferCtxtBuilder { global_tcx, @@ -466,40 +468,51 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { ref fresh_tables, } = *self; let in_progress_tables = fresh_tables.as_ref(); - global_tcx.enter_local(arena, |tcx| f(InferCtxt { - tcx, - in_progress_tables, - projection_cache: RefCell::new(traits::ProjectionCache::new()), - type_variables: RefCell::new(type_variable::TypeVariableTable::new()), - int_unification_table: RefCell::new(ut::UnificationTable::new()), - float_unification_table: RefCell::new(ut::UnificationTable::new()), - region_constraints: RefCell::new(Some(RegionConstraintCollector::new())), - lexical_region_resolutions: RefCell::new(None), - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - reported_trait_errors: RefCell::new(FxHashMap()), - tainted_by_errors_flag: Cell::new(false), - err_count_on_creation: tcx.sess.err_count(), - in_snapshot: Cell::new(false), - region_obligations: RefCell::new(vec![]), - universe: Cell::new(ty::UniverseIndex::ROOT), - })) + global_tcx.enter_local(arena, |tcx| { + f(InferCtxt { + tcx, + in_progress_tables, + projection_cache: RefCell::new(traits::ProjectionCache::new()), + type_variables: RefCell::new(type_variable::TypeVariableTable::new()), + int_unification_table: RefCell::new(ut::UnificationTable::new()), + float_unification_table: RefCell::new(ut::UnificationTable::new()), + region_constraints: RefCell::new(Some(RegionConstraintCollector::new())), + lexical_region_resolutions: RefCell::new(None), + selection_cache: traits::SelectionCache::new(), + evaluation_cache: traits::EvaluationCache::new(), + reported_trait_errors: RefCell::new(FxHashMap()), + tainted_by_errors_flag: Cell::new(false), + err_count_on_creation: tcx.sess.err_count(), + in_snapshot: Cell::new(false), + region_obligations: RefCell::new(vec![]), + universe: Cell::new(ty::UniverseIndex::ROOT), + }) + }) } } impl<T> ExpectedFound<T> { pub fn new(a_is_expected: bool, a: T, b: T) -> Self { if a_is_expected { - ExpectedFound {expected: a, found: b} + ExpectedFound { + expected: a, + found: b, + } } else { - ExpectedFound {expected: b, found: a} + ExpectedFound { + expected: b, + found: a, + } } } } impl<'tcx, T> InferOk<'tcx, T> { pub fn unit(self) -> InferOk<'tcx, ()> { - InferOk { value: (), obligations: self.obligations } + InferOk { + value: (), + obligations: self.obligations, + } } /// Extract `value`, registering any obligations into `fulfill_cx` @@ -523,7 +536,7 @@ impl<'tcx> InferOk<'tcx, ()> { } #[must_use = "once you start a snapshot, you should always consume it"] -pub struct CombinedSnapshot<'a, 'tcx:'a> { +pub struct CombinedSnapshot<'a, 'tcx: 'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, type_snapshot: type_variable::Snapshot<'tcx>, int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>, @@ -540,14 +553,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.in_snapshot.get() } - pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T { + pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } pub fn type_var_diverges(&'a self, ty: Ty) -> bool { match ty.sty { ty::Infer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid), - _ => false + _ => false, } } @@ -557,22 +570,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric { use ty::error::UnconstrainedNumeric::Neither; - use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + use ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; match ty.sty { ty::Infer(ty::IntVar(vid)) => { - if self.int_unification_table.borrow_mut().probe_value(vid).is_some() { + if self.int_unification_table + .borrow_mut() + .probe_value(vid) + .is_some() + { Neither } else { UnconstrainedInt } - }, + } ty::Infer(ty::FloatVar(vid)) => { - if self.float_unification_table.borrow_mut().probe_value(vid).is_some() { + if self.float_unification_table + .borrow_mut() + .probe_value(vid) + .is_some() + { Neither } else { UnconstrainedFloat } - }, + } _ => Neither, } } @@ -590,17 +611,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { (0..int_unification_table.len()) .map(|i| ty::IntVid { index: i as u32 }) .filter(|&vid| int_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_int_var(v)) - ).chain( + .map(|v| self.tcx.mk_int_var(v)), + ) + .chain( (0..float_unification_table.len()) .map(|i| ty::FloatVid { index: i as u32 }) .filter(|&vid| float_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_float_var(v)) - ).collect() + .map(|v| self.tcx.mk_float_var(v)), + ) + .collect() } - fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>) - -> CombineFields<'a, 'gcx, 'tcx> { + fn combine_fields( + &'a self, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> CombineFields<'a, 'gcx, 'tcx> { CombineFields { infcx: self, trace, @@ -627,7 +653,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // escaping obligations in the main cx. In those cases, you can // use this function. pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R - where F: FnOnce(&Self) -> R + where + F: FnOnce(&Self) -> R, { let flag = self.in_snapshot.get(); self.in_snapshot.set(false); @@ -653,23 +680,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e. during typeck) // to ban writes from within a snapshot to them. - _in_progress_tables: self.in_progress_tables.map(|tables| { - tables.borrow() - }) + _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()), } } fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("rollback_to(cause={})", cause); - let CombinedSnapshot { projection_cache_snapshot, - type_snapshot, - int_snapshot, - float_snapshot, - region_constraints_snapshot, - region_obligations_snapshot, - universe, - was_in_snapshot, - _in_progress_tables } = snapshot; + let CombinedSnapshot { + projection_cache_snapshot, + type_snapshot, + int_snapshot, + float_snapshot, + region_constraints_snapshot, + region_obligations_snapshot, + universe, + was_in_snapshot, + _in_progress_tables, + } = snapshot; self.in_snapshot.set(was_in_snapshot); self.universe.set(universe); @@ -677,9 +704,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.projection_cache .borrow_mut() .rollback_to(projection_cache_snapshot); - self.type_variables - .borrow_mut() - .rollback_to(type_snapshot); + self.type_variables.borrow_mut().rollback_to(type_snapshot); self.int_unification_table .borrow_mut() .rollback_to(int_snapshot); @@ -695,27 +720,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("commit_from()"); - let CombinedSnapshot { projection_cache_snapshot, - type_snapshot, - int_snapshot, - float_snapshot, - region_constraints_snapshot, - region_obligations_snapshot: _, - universe: _, - was_in_snapshot, - _in_progress_tables } = snapshot; + let CombinedSnapshot { + projection_cache_snapshot, + type_snapshot, + int_snapshot, + float_snapshot, + region_constraints_snapshot, + region_obligations_snapshot: _, + universe: _, + was_in_snapshot, + _in_progress_tables, + } = snapshot; self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() .commit(&projection_cache_snapshot); - self.type_variables - .borrow_mut() - .commit(type_snapshot); - self.int_unification_table - .borrow_mut() - .commit(int_snapshot); + self.type_variables.borrow_mut().commit(type_snapshot); + self.int_unification_table.borrow_mut().commit(int_snapshot); self.float_unification_table .borrow_mut() .commit(float_snapshot); @@ -724,7 +747,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Execute `f` and commit the bindings - pub fn commit_unconditionally<R, F>(&self, f: F) -> R where + pub fn commit_unconditionally<R, F>(&self, f: F) -> R + where F: FnOnce() -> R, { debug!("commit()"); @@ -735,23 +759,29 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)` - pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E> + pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> + where + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>, { debug!("commit_if_ok()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); match r { - Ok(_) => { self.commit_from(snapshot); } - Err(_) => { self.rollback_to("commit_if_ok -- error", snapshot); } + Ok(_) => { + self.commit_from(snapshot); + } + Err(_) => { + self.rollback_to("commit_if_ok -- error", snapshot); + } } r } // Execute `f` in a snapshot, and commit the bindings it creates - pub fn in_snapshot<T, F>(&self, f: F) -> T where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T + pub fn in_snapshot<T, F>(&self, f: F) -> T + where + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T, { debug!("in_snapshot()"); let snapshot = self.start_snapshot(); @@ -761,7 +791,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Execute `f` then unroll any bindings it creates - pub fn probe<R, F>(&self, f: F) -> R where + pub fn probe<R, F>(&self, f: F) -> R + where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { debug!("probe()"); @@ -771,59 +802,57 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r } - pub fn add_given(&self, - sub: ty::Region<'tcx>, - sup: ty::RegionVid) - { + pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { self.borrow_region_constraints().add_given(sub, sup); } - pub fn can_sub<T>(&self, - param_env: ty::ParamEnv<'tcx>, - a: T, - b: T) - -> UnitResult<'tcx> - where T: at::ToTrace<'tcx> + pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx> + where + T: at::ToTrace<'tcx>, { let origin = &ObligationCause::dummy(); self.probe(|_| { - self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| { - // Ignore obligations, since we are unrolling - // everything anyway. - }) + self.at(origin, param_env) + .sub(a, b) + .map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. + }) }) } - pub fn can_eq<T>(&self, - param_env: ty::ParamEnv<'tcx>, - a: T, - b: T) - -> UnitResult<'tcx> - where T: at::ToTrace<'tcx> + pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx> + where + T: at::ToTrace<'tcx>, { let origin = &ObligationCause::dummy(); self.probe(|_| { - self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| { - // Ignore obligations, since we are unrolling - // everything anyway. - }) + self.at(origin, param_env) + .eq(a, b) + .map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. + }) }) } - pub fn sub_regions(&self, - origin: SubregionOrigin<'tcx>, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>) { + pub fn sub_regions( + &self, + origin: SubregionOrigin<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) { debug!("sub_regions({:?} <: {:?})", a, b); - self.borrow_region_constraints().make_subregion(origin, a, b); + self.borrow_region_constraints() + .make_subregion(origin, a, b); } - pub fn subtype_predicate(&self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - predicate: &ty::PolySubtypePredicate<'tcx>) - -> Option<InferResult<'tcx, ()>> - { + pub fn subtype_predicate( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: &ty::PolySubtypePredicate<'tcx>, + ) -> Option<InferResult<'tcx, ()>> { // Subtle: it's ok to skip the binder here and resolve because // `shallow_resolve` just ignores anything that is not a type // variable, and because type variable's can't (at present, at @@ -845,8 +874,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } Some(self.commit_if_ok(|snapshot| { - let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) = - self.skolemize_late_bound_regions(predicate); + let ( + ty::SubtypePredicate { + a_is_expected, + a, + b, + }, + skol_map, + ) = self.skolemize_late_bound_regions(predicate); let cause_span = cause.span; let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -856,17 +891,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { })) } - pub fn region_outlives_predicate(&self, - cause: &traits::ObligationCause<'tcx>, - predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) - -> UnitResult<'tcx> - { + pub fn region_outlives_predicate( + &self, + cause: &traits::ObligationCause<'tcx>, + predicate: &ty::PolyRegionOutlivesPredicate<'tcx>, + ) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), skol_map) = self.skolemize_late_bound_regions(predicate); - let origin = - SubregionOrigin::from_obligation_cause(cause, - || RelateRegionParamBound(cause.span)); + let origin = SubregionOrigin::from_obligation_cause(cause, || { + RelateRegionParamBound(cause.span) + }); self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` self.leak_check(false, cause.span, &skol_map, snapshot)?; Ok(self.pop_skolemized(skol_map, snapshot)) @@ -888,27 +923,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn next_int_var_id(&self) -> IntVid { - self.int_unification_table - .borrow_mut() - .new_key(None) + self.int_unification_table.borrow_mut().new_key(None) } pub fn next_float_var_id(&self) -> FloatVid { - self.float_unification_table - .borrow_mut() - .new_key(None) + self.float_unification_table.borrow_mut().new_key(None) } /// Create a fresh region variable with the next available index. - /// - /// # Parameters - /// - /// - `origin`: information about why we created this variable, for use - /// during diagnostics / error-reporting. - pub fn next_region_var(&self, origin: RegionVariableOrigin) - -> ty::Region<'tcx> { + /// The variable will be created in the maximum universe created + /// thus far, allowing it to name any region created thus far. + pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> { + self.next_region_var_in_universe(origin, self.universe()) + } + + /// Create a fresh region variable with the next available index + /// in the given universe; typically, you can use + /// `next_region_var` and just use the maximal universe. + pub fn next_region_var_in_universe( + &self, + origin: RegionVariableOrigin, + universe: ty::UniverseIndex, + ) -> ty::Region<'tcx> { let region_var = self.borrow_region_constraints() - .new_region_var(self.universe(), origin); + .new_region_var(universe, origin); self.tcx.mk_region(ty::ReVar(region_var)) } @@ -918,22 +956,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Just a convenient wrapper of `next_region_var` for using during NLL. - pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) - -> ty::Region<'tcx> { + pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> { self.next_region_var(RegionVariableOrigin::NLL(origin)) } - pub fn var_for_def(&self, - span: Span, - param: &ty::GenericParamDef) - -> Kind<'tcx> { + /// Just a convenient wrapper of `next_region_var` for using during NLL. + pub fn next_nll_region_var_in_universe( + &self, + origin: NLLRegionVariableOrigin, + universe: ty::UniverseIndex, + ) -> ty::Region<'tcx> { + self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe) + } + + pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> Kind<'tcx> { match param.kind { GenericParamDefKind::Lifetime => { // Create a region inference variable for the given // region parameter definition. - self.next_region_var(EarlyBoundRegion(span, param.name)).into() + self.next_region_var(EarlyBoundRegion(span, param.name)) + .into() } - GenericParamDefKind::Type {..} => { + GenericParamDefKind::Type { .. } => { // Create a type inference variable for the given // type parameter definition. The substitutions are // for actual parameters that may be referred to by @@ -942,12 +986,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // used in a path such as `Foo::<T, U>::new()` will // use an inference variable for `C` with `[T, U]` // as the substitutions for the default, `(T, U)`. - let ty_var_id = - self.type_variables - .borrow_mut() - .new_var(self.universe(), - false, - TypeVariableOrigin::TypeParameterDefinition(span, param.name)); + let ty_var_id = self.type_variables.borrow_mut().new_var( + self.universe(), + false, + TypeVariableOrigin::TypeParameterDefinition(span, param.name), + ); self.tcx.mk_var(ty_var_id).into() } @@ -956,13 +999,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Given a set of generics defined on a type or impl, returns a substitution mapping each /// type/region parameter to a fresh inference variable. - pub fn fresh_substs_for_item(&self, - span: Span, - def_id: DefId) - -> &'tcx Substs<'tcx> { - Substs::for_item(self.tcx, def_id, |param, _| { - self.var_for_def(span, param) - }) + pub fn fresh_substs_for_item(&self, span: Span, def_id: DefId) -> &'tcx Substs<'tcx> { + Substs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) } /// True if errors have been reported since this infcx was @@ -971,11 +1009,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// errors, but where it's hard to be 100% sure (e.g., unresolved /// inference variables, regionck errors). pub fn is_tainted_by_errors(&self) -> bool { - debug!("is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors_flag={})", - self.tcx.sess.err_count(), - self.err_count_on_creation, - self.tainted_by_errors_flag.get()); + debug!( + "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ + tainted_by_errors_flag={})", + self.tcx.sess.err_count(), + self.err_count_on_creation, + self.tainted_by_errors_flag.get() + ); if self.tcx.sess.err_count() > self.err_count_on_creation { return true; // errors reported since this infcx was made @@ -1018,12 +1058,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { region_map: ®ion::ScopeTree, outlives_env: &OutlivesEnvironment<'tcx>, ) { - self.resolve_regions_and_report_errors_inner( - region_context, - region_map, - outlives_env, - true, - ) + self.resolve_regions_and_report_errors_inner(region_context, region_map, outlives_env, true) } fn resolve_regions_and_report_errors_inner( @@ -1033,22 +1068,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { outlives_env: &OutlivesEnvironment<'tcx>, will_later_be_reported_by_nll: bool, ) { - assert!(self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(), - "region_obligations not empty: {:#?}", - self.region_obligations.borrow()); - - let region_rels = &RegionRelations::new(self.tcx, - region_context, - region_map, - outlives_env.free_region_map()); - let (var_infos, data) = self.region_constraints.borrow_mut() - .take() - .expect("regions already resolved") - .into_infos_and_data(); + assert!( + self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(), + "region_obligations not empty: {:#?}", + self.region_obligations.borrow() + ); + + let region_rels = &RegionRelations::new( + self.tcx, + region_context, + region_map, + outlives_env.free_region_map(), + ); + let (var_infos, data) = self.region_constraints + .borrow_mut() + .take() + .expect("regions already resolved") + .into_infos_and_data(); let (lexical_region_resolutions, errors) = lexical_region_resolve::resolve(region_rels, var_infos, data); - let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); + let old_value = self.lexical_region_resolutions + .replace(Some(lexical_region_resolutions)); assert!(old_value.is_none()); if !self.is_tainted_by_errors() { @@ -1072,9 +1113,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// translate them into the form that the NLL solver /// understands. See the NLL module for mode details. pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> { - assert!(self.region_obligations.borrow().is_empty(), - "region_obligations not empty: {:#?}", - self.region_obligations.borrow()); + assert!( + self.region_obligations.borrow().is_empty(), + "region_obligations not empty: {:#?}", + self.region_obligations.borrow() + ); self.borrow_region_constraints().take_and_reset_data() } @@ -1095,10 +1138,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// called. This is used only during NLL processing to "hand off" ownership /// of the set of region vairables into the NLL region context. pub fn take_region_var_origins(&self) -> VarInfos { - let (var_infos, data) = self.region_constraints.borrow_mut() - .take() - .expect("regions already resolved") - .into_infos_and_data(); + let (var_infos, data) = self.region_constraints + .borrow_mut() + .take() + .expect("regions already resolved") + .into_infos_and_data(); assert!(data.is_empty()); var_infos } @@ -1132,32 +1176,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // structurally), and we prevent cycles in any case, // so this recursion should always be of very limited // depth. - self.type_variables.borrow_mut() - .probe(v) - .known() - .map(|t| self.shallow_resolve(t)) - .unwrap_or(typ) - } - - ty::Infer(ty::IntVar(v)) => { - self.int_unification_table + self.type_variables .borrow_mut() - .probe_value(v) - .map(|v| v.to_type(self.tcx)) + .probe(v) + .known() + .map(|t| self.shallow_resolve(t)) .unwrap_or(typ) } - ty::Infer(ty::FloatVar(v)) => { - self.float_unification_table - .borrow_mut() - .probe_value(v) - .map(|v| v.to_type(self.tcx)) - .unwrap_or(typ) - } + ty::Infer(ty::IntVar(v)) => self.int_unification_table + .borrow_mut() + .probe_value(v) + .map(|v| v.to_type(self.tcx)) + .unwrap_or(typ), - _ => { - typ - } + ty::Infer(ty::FloatVar(v)) => self.float_unification_table + .borrow_mut() + .probe_value(v) + .map(|v| v.to_type(self.tcx)) + .unwrap_or(typ), + + _ => typ, } } @@ -1166,7 +1205,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T - where T: TypeFoldable<'tcx> + where + T: TypeFoldable<'tcx>, { /*! * Where possible, replaces type/int/float variables in @@ -1190,20 +1230,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// resolved type, so it's more efficient than /// `resolve_type_vars_if_possible()`. pub fn any_unresolved_type_vars<T>(&self, value: &T) -> bool - where T: TypeFoldable<'tcx> + where + T: TypeFoldable<'tcx>, { let mut r = resolve::UnresolvedTypeFinder::new(self); value.visit_with(&mut r) } pub fn resolve_type_and_region_vars_if_possible<T>(&self, value: &T) -> T - where T: TypeFoldable<'tcx> + where + T: TypeFoldable<'tcx>, { let mut r = resolve::OpportunisticTypeAndRegionResolver::new(self); value.fold_with(&mut r) } - pub fn fully_resolve<T:TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> { + pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> { /*! * Attempts to resolve all type/region variables in * `value`. Region inference must have been run already (e.g., @@ -1228,12 +1270,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // types using one of these methods, and should not call span_err directly for such // errors. - pub fn type_error_struct_with_diag<M>(&self, - sp: Span, - mk_diag: M, - actual_ty: Ty<'tcx>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(String) -> DiagnosticBuilder<'tcx>, + pub fn type_error_struct_with_diag<M>( + &self, + sp: Span, + mk_diag: M, + actual_ty: Ty<'tcx>, + ) -> DiagnosticBuilder<'tcx> + where + M: FnOnce(String) -> DiagnosticBuilder<'tcx>, { let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); @@ -1246,12 +1290,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { mk_diag(self.ty_to_string(actual_ty)) } - pub fn report_mismatched_types(&self, - cause: &ObligationCause<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>, - err: TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { + pub fn report_mismatched_types( + &self, + cause: &ObligationCause<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + err: TypeError<'tcx>, + ) -> DiagnosticBuilder<'tcx> { let trace = TypeTrace::types(cause, true, expected, actual); self.report_and_explain_type_error(trace, &err) } @@ -1260,13 +1305,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &self, span: Span, lbrct: LateBoundRegionConversionTime, - value: &ty::Binder<T>) - -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) - where T : TypeFoldable<'tcx> + value: &ty::Binder<T>, + ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + where + T: TypeFoldable<'tcx>, { - self.tcx.replace_late_bound_regions( - value, - |br| self.next_region_var(LateBoundRegion(span, br, lbrct))) + self.tcx.replace_late_bound_regions(value, |br| { + self.next_region_var(LateBoundRegion(span, br, lbrct)) + }) } /// Given a higher-ranked projection predicate like: @@ -1284,43 +1330,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more /// details. - pub fn match_poly_projection_predicate(&self, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - match_a: ty::PolyProjectionPredicate<'tcx>, - match_b: ty::TraitRef<'tcx>) - -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> - { + pub fn match_poly_projection_predicate( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + match_a: ty::PolyProjectionPredicate<'tcx>, + match_b: ty::TraitRef<'tcx>, + ) -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> { let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty)); let trace = TypeTrace { cause, - values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b)) + values: TraitRefs(ExpectedFound::new( + true, + match_pair.skip_binder().0, + match_b, + )), }; let mut combine = self.combine_fields(trace, param_env); let result = combine.higher_ranked_match(&match_pair, &match_b, true)?; - Ok(InferOk { value: result, obligations: combine.obligations }) + Ok(InferOk { + value: result, + obligations: combine.obligations, + }) } /// See `verify_generic_bound` method in `region_constraints` - pub fn verify_generic_bound(&self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - a: ty::Region<'tcx>, - bound: VerifyBound<'tcx>) { - debug!("verify_generic_bound({:?}, {:?} <: {:?})", - kind, - a, - bound); - - self.borrow_region_constraints().verify_generic_bound(origin, kind, a, bound); - } - - pub fn type_moves_by_default(&self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span) - -> bool { + pub fn verify_generic_bound( + &self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, + ) { + debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, bound); + + self.borrow_region_constraints() + .verify_generic_bound(origin, kind, a, bound); + } + + pub fn type_moves_by_default( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool { let ty = self.resolve_type_vars_if_possible(&ty); // Even if the type may have no inference variables, during // type-checking closure types are in local tables only. @@ -1342,11 +1396,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Obtains the latest type of the given closure; this may be a /// closure in the current function, in which case its /// `ClosureKind` may not yet be known. - pub fn closure_kind(&self, - closure_def_id: DefId, - closure_substs: ty::ClosureSubsts<'tcx>) - -> Option<ty::ClosureKind> - { + pub fn closure_kind( + &self, + closure_def_id: DefId, + closure_substs: ty::ClosureSubsts<'tcx>, + ) -> Option<ty::ClosureKind> { let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx); let closure_kind_ty = self.shallow_resolve(&closure_kind_ty); closure_kind_ty.to_opt_closure_kind() @@ -1359,7 +1413,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn closure_sig( &self, def_id: DefId, - substs: ty::ClosureSubsts<'tcx> + substs: ty::ClosureSubsts<'tcx>, ) -> ty::PolyFnSig<'tcx> { let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx); let closure_sig_ty = self.shallow_resolve(&closure_sig_ty); @@ -1368,29 +1422,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Normalizes associated types in `value`, potentially returning /// new obligations that must further be processed. - pub fn partially_normalize_associated_types_in<T>(&self, - span: Span, - body_id: ast::NodeId, - param_env: ty::ParamEnv<'tcx>, - value: &T) - -> InferOk<'tcx, T> - where T : TypeFoldable<'tcx> + pub fn partially_normalize_associated_types_in<T>( + &self, + span: Span, + body_id: ast::NodeId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> InferOk<'tcx, T> + where + T: TypeFoldable<'tcx>, { debug!("partially_normalize_associated_types_in(value={:?})", value); let mut selcx = traits::SelectionContext::new(self); let cause = ObligationCause::misc(span, body_id); let traits::Normalized { value, obligations } = traits::normalize(&mut selcx, param_env, cause, value); - debug!("partially_normalize_associated_types_in: result={:?} predicates={:?}", - value, - obligations); + debug!( + "partially_normalize_associated_types_in: result={:?} predicates={:?}", + value, obligations + ); InferOk { value, obligations } } pub fn borrow_region_constraints(&self) -> RefMut<'_, RegionConstraintCollector<'tcx>> { - RefMut::map( - self.region_constraints.borrow_mut(), - |c| c.as_mut().expect("region constraints already solved")) + RefMut::map(self.region_constraints.borrow_mut(), |c| { + c.as_mut().expect("region constraints already solved") + }) } /// Clears the selection, evaluation, and projection cachesThis is useful when @@ -1423,14 +1480,15 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { self.cause.span } - pub fn types(cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> TypeTrace<'tcx> { + pub fn types( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Ty<'tcx>, + b: Ty<'tcx>, + ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Types(ExpectedFound::new(a_is_expected, a, b)) + values: Types(ExpectedFound::new(a_is_expected, a, b)), } } @@ -1440,7 +1498,7 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err, - }) + }), } } } @@ -1482,24 +1540,25 @@ impl<'tcx> SubregionOrigin<'tcx> { } } - pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, - default: F) - -> Self - where F: FnOnce() -> Self + pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default: F) -> Self + where + F: FnOnce() -> Self, { match cause.code { - traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => - SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span), - - traits::ObligationCauseCode::CompareImplMethodObligation { item_name, - impl_item_def_id, - trait_item_def_id, } => - SubregionOrigin::CompareImplMethodObligation { - span: cause.span, - item_name, - impl_item_def_id, - trait_item_def_id, - }, + traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => { + SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) + } + + traits::ObligationCauseCode::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CompareImplMethodObligation { + span: cause.span, + item_name, + impl_item_def_id, + trait_item_def_id, + }, _ => default(), } @@ -1534,8 +1593,10 @@ EnumTypeFoldableImpl! { impl<'tcx> fmt::Debug for RegionObligation<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})", - self.sub_region, - self.sup_type) + write!( + f, + "RegionObligation(sub_region={:?}, sup_type={:?})", + self.sub_region, self.sup_type + ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index b823545aa91..e22792305a0 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -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); } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index cc0548c0dff..8d2851d1b77 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -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. diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 708ce8e2031..3450eec8082 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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: - /// - /// let (a, b): (T, U) = y; - /// - /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y` - /// is the right thing. + /// Encodes a user's type ascription. These need to be preserved + /// intact so that NLL can respect them. For example: /// - /// `CanonicalTy` is used to capture "inference variables" from the user's types. For example: + /// let a: T = y; /// - /// let x: Vec<_> = ...; - /// let y: &u32 = ...; + /// 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: /// - /// 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), } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index c7723fdf191..0beb5ac0a3c 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -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); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ddaa0444cc7..6cc648b572c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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 diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 955f2740b92..bd9dfc6b855 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! { ::ty::ClosureKind, ::ty::IntVarValue, ::ty::ParamTy, + ::ty::Variance, ::syntax_pos::Span, } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index b6ffcd55d91..696c4d0043c 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -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()) } } diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index c8a2b47e98d..51380db5b23 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -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: // diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index cfbc2ab9007..e3526a5a2ee 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -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 = [ diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 2e90f95fa8e..4b4ccb3b600 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -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())); diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs index dd62a12553c..0cb8f99efc3 100644 --- a/src/librustc_codegen_llvm/mir/statement.rs +++ b/src/librustc_codegen_llvm/mir/statement.rs @@ -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, } } diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 7f25911abec..a8502e92447 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -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())); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 2c32cbdd00f..681cf0d5fc9 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -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); )*} ) } diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 4e24a26983d..7d01ed556c8 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -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); diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 76f6bcb5e56..60aeb92d91a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -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) => { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 457499ded56..7e8e1b32d4d 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -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, ) { } diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index f233a17597a..71345f22e44 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -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) => { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index cb15c88bb3e..214628600b3 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -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: diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index e1bd8530629..d77863d598f 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -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. diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 82158acc9e6..de96539ec30 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -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, - } + }, } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 8ffce9c9492..06cb44ac971 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -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); - - // 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; - } + 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 + } + }; - // 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] - ); + // 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![]); + + // Relate the generalized kind to the original one. + let result = self.relate(&generalized_kind, &b_kind); + + // Restore the old scopes now. + self.a_scopes = old_a_scopes; + + debug!("equate_var: complete, result = {:?}", result); + return result; + } - // 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) + 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)) + } +} diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 50d4944d7c2..c4cb7958fd3 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -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); }) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 59ebb7703ff..5708ac4e6b5 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -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, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index d3e67ea7b7d..cef1fb77e5c 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -13,16 +13,16 @@ //! includes the high-level algorithm, the submodules contain the //! details. +use build::scope::{CachedBlock, DropKind}; +use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard}; use build::{BlockAnd, BlockAndExtension, Builder}; use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; -use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard}; -use build::scope::{CachedBlock, DropKind}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::bitvec::BitArray; -use rustc::ty::{self, Ty}; -use rustc::mir::*; -use rustc::hir; use hair::*; +use rustc::hir; +use rustc::mir::*; +use rustc::ty::{self, CanonicalTy, Ty}; +use rustc_data_structures::bitvec::BitArray; +use rustc_data_structures::fx::FxHashMap; use syntax::ast::{Name, NodeId}; use syntax_pos::Span; @@ -37,13 +37,14 @@ mod util; pub(crate) struct ArmHasGuard(pub bool); impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - pub fn match_expr(&mut self, - destination: &Place<'tcx>, - span: Span, - mut block: BasicBlock, - discriminant: ExprRef<'tcx>, - arms: Vec<Arm<'tcx>>) - -> BlockAnd<()> { + pub fn match_expr( + &mut self, + destination: &Place<'tcx>, + span: Span, + mut block: BasicBlock, + discriminant: ExprRef<'tcx>, + arms: Vec<Arm<'tcx>>, + ) -> BlockAnd<()> { let tcx = self.hir.tcx(); let discriminant_span = discriminant.span(); let discriminant_place = unpack!(block = self.as_place(block, discriminant)); @@ -67,7 +68,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let dummy_access = Rvalue::Discriminant(discriminant_place.clone()); let dummy_ty = dummy_access.ty(&self.local_decls, tcx); let dummy_temp = self.temp(dummy_ty, dummy_source_info.span); - self.cfg.push_assign(block, dummy_source_info, &dummy_temp, dummy_access); + self.cfg + .push_assign(block, dummy_source_info, &dummy_temp, dummy_access); let source_info = self.source_info(discriminant_span); let borrowed_input_temp = if tcx.generate_borrow_of_any_match_input() { @@ -75,38 +77,46 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // inference to find an appropriate one. Therefore you can // only use this when NLL is turned on. assert!(tcx.use_mir_borrowck()); - let borrowed_input = - Rvalue::Ref(tcx.types.re_empty, BorrowKind::Shared, discriminant_place.clone()); + let borrowed_input = Rvalue::Ref( + tcx.types.re_empty, + BorrowKind::Shared, + discriminant_place.clone(), + ); let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx); let borrowed_input_temp = self.temp(borrowed_input_ty, span); - self.cfg.push_assign(block, source_info, &borrowed_input_temp, borrowed_input); + self.cfg + .push_assign(block, source_info, &borrowed_input_temp, borrowed_input); Some(borrowed_input_temp) } else { None }; let mut arm_blocks = ArmBlocks { - blocks: arms.iter() - .map(|_| self.cfg.start_new_block()) - .collect(), + blocks: arms.iter().map(|_| self.cfg.start_new_block()).collect(), }; // Get the arm bodies and their scopes, while declaring bindings. - let arm_bodies: Vec<_> = arms.iter().map(|arm| { - // BUG: use arm lint level - let body = self.hir.mirror(arm.body.clone()); - let scope = self.declare_bindings(None, body.span, - LintLevel::Inherited, - &arm.patterns[..], - ArmHasGuard(arm.guard.is_some()), - Some((Some(&discriminant_place), discriminant_span))); - (body, scope.unwrap_or(self.source_scope)) - }).collect(); + let arm_bodies: Vec<_> = arms.iter() + .map(|arm| { + // BUG: use arm lint level + let body = self.hir.mirror(arm.body.clone()); + let scope = self.declare_bindings( + None, + body.span, + LintLevel::Inherited, + &arm.patterns[..], + ArmHasGuard(arm.guard.is_some()), + Some((Some(&discriminant_place), discriminant_span)), + ); + (body, scope.unwrap_or(self.source_scope)) + }) + .collect(); // create binding start block for link them by false edges let candidate_count = arms.iter().fold(0, |ac, c| ac + c.patterns.len()); let pre_binding_blocks: Vec<_> = (0..candidate_count + 1) - .map(|_| self.cfg.start_new_block()).collect(); + .map(|_| self.cfg.start_new_block()) + .collect(); // assemble a list of candidates: there is one candidate per // pattern, which means there may be more than one candidate @@ -114,21 +124,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // highest priority candidate comes first in the list. // (i.e. same order as in source) - let candidates: Vec<_> = - arms.iter() - .enumerate() - .flat_map(|(arm_index, arm)| { - arm.patterns.iter().enumerate() - .map(move |(pat_index, pat)| { - (arm_index, pat_index, pat, arm.guard.clone()) - }) - }) - .zip(pre_binding_blocks.iter().zip(pre_binding_blocks.iter().skip(1))) - .map(|((arm_index, pat_index, pattern, guard), - (pre_binding_block, next_candidate_pre_binding_block))| { - - if let (true, Some(borrow_temp)) = (tcx.emit_read_for_match(), - borrowed_input_temp.clone()) { + let candidates: Vec<_> = arms.iter() + .enumerate() + .flat_map(|(arm_index, arm)| { + arm.patterns + .iter() + .enumerate() + .map(move |(pat_index, pat)| (arm_index, pat_index, pat, arm.guard.clone())) + }) + .zip( + pre_binding_blocks + .iter() + .zip(pre_binding_blocks.iter().skip(1)), + ) + .map( + |( + (arm_index, pat_index, pattern, guard), + (pre_binding_block, next_candidate_pre_binding_block), + )| { + if let (true, Some(borrow_temp)) = + (tcx.emit_read_for_match(), borrowed_input_temp.clone()) + { // inject a fake read of the borrowed input at // the start of each arm's pattern testing // code. @@ -137,10 +153,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // the variant for an enum while you are in // the midst of matching on it. let pattern_source_info = self.source_info(pattern.span); - self.cfg.push(*pre_binding_block, Statement { - source_info: pattern_source_info, - kind: StatementKind::ReadForMatch(borrow_temp.clone()), - }); + self.cfg.push( + *pre_binding_block, + Statement { + source_info: pattern_source_info, + kind: StatementKind::ReadForMatch(borrow_temp.clone()), + }, + ); } // One might ask: why not build up the match pair such that it @@ -168,18 +187,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: pattern.span, match_pairs: vec![MatchPair::new(discriminant_place.clone(), pattern)], bindings: vec![], + ascriptions: vec![], guard, arm_index, pat_index, pre_binding_block: *pre_binding_block, next_candidate_pre_binding_block: *next_candidate_pre_binding_block, } - }) - .collect(); + }, + ) + .collect(); let outer_source_info = self.source_info(span); - self.cfg.terminate(*pre_binding_blocks.last().unwrap(), - outer_source_info, TerminatorKind::Unreachable); + self.cfg.terminate( + *pre_binding_blocks.last().unwrap(), + outer_source_info, + TerminatorKind::Unreachable, + ); // this will generate code to test discriminant_place and // branch to the appropriate arm block @@ -198,7 +222,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { otherwise.sort(); otherwise.dedup(); // variant switches can introduce duplicate target blocks for block in otherwise { - self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + self.cfg + .terminate(block, source_info, TerminatorKind::Unreachable); } } @@ -211,50 +236,75 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Re-enter the source scope we created the bindings in. self.source_scope = source_scope; unpack!(arm_block = self.into(destination, arm_block, body)); - self.cfg.terminate(arm_block, outer_source_info, - TerminatorKind::Goto { target: end_block }); + self.cfg.terminate( + arm_block, + outer_source_info, + TerminatorKind::Goto { target: end_block }, + ); } self.source_scope = outer_source_info.scope; end_block.unit() } - pub fn user_assert_ty(&mut self, block: BasicBlock, hir_id: hir::HirId, - var: NodeId, span: Span) { - if self.hir.tcx().sess.opts.debugging_opts.disable_nll_user_type_assert { return; } - - let local_id = self.var_local_id(var, OutsideGuard); - let source_info = self.source_info(span); - - debug!("user_assert_ty: local_id={:?}", hir_id.local_id); - if let Some(c_ty) = self.hir.tables.user_provided_tys().get(hir_id) { - debug!("user_assert_ty: c_ty={:?}", c_ty); - self.cfg.push(block, Statement { - source_info, - kind: StatementKind::UserAssertTy(*c_ty, local_id), - }); - } - } - - pub fn expr_into_pattern(&mut self, - mut block: BasicBlock, - ty: Option<hir::HirId>, - irrefutable_pat: Pattern<'tcx>, - initializer: ExprRef<'tcx>) - -> BlockAnd<()> { - // optimize the case of `let x = ...` + pub fn expr_into_pattern( + &mut self, + mut block: BasicBlock, + irrefutable_pat: Pattern<'tcx>, + initializer: ExprRef<'tcx>, + ) -> BlockAnd<()> { match *irrefutable_pat.kind { - PatternKind::Binding { mode: BindingMode::ByValue, - var, - subpattern: None, .. } => { - let place = self.storage_live_binding(block, var, irrefutable_pat.span, - OutsideGuard); - - if let Some(ty) = ty { - self.user_assert_ty(block, ty, var, irrefutable_pat.span); - } + // Optimize the case of `let x = ...` to write directly into `x` + PatternKind::Binding { + mode: BindingMode::ByValue, + var, + subpattern: None, + .. + } => { + let place = + self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard); + unpack!(block = self.into(&place, block, initializer)); + self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); + block.unit() + } + // Optimize the case of `let x: T = ...` to write directly + // into `x` and then require that `T == typeof(x)`. + // + // Weirdly, this is needed to prevent the + // `intrinsic-move-val.rs` test case from crashing. That + // test works with uninitialized values in a rather + // dubious way, so it may be that the test is kind of + // broken. + PatternKind::AscribeUserType { + subpattern: Pattern { + kind: box PatternKind::Binding { + mode: BindingMode::ByValue, + var, + subpattern: None, + .. + }, + .. + }, + user_ty: ascription_user_ty, + } => { + let place = + self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard); unpack!(block = self.into(&place, block, initializer)); + + let source_info = self.source_info(irrefutable_pat.span); + self.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::AscribeUserType( + place.clone(), + ty::Variance::Invariant, + ascription_user_ty, + ), + }, + ); + self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -265,24 +315,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - pub fn place_into_pattern(&mut self, - mut block: BasicBlock, - irrefutable_pat: Pattern<'tcx>, - initializer: &Place<'tcx>, - set_match_place: bool) - -> BlockAnd<()> { + pub fn place_into_pattern( + &mut self, + mut block: BasicBlock, + irrefutable_pat: Pattern<'tcx>, + initializer: &Place<'tcx>, + set_match_place: bool, + ) -> BlockAnd<()> { // create a dummy candidate let mut candidate = Candidate { span: irrefutable_pat.span, match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)], bindings: vec![], + ascriptions: vec![], guard: None, // since we don't call `match_candidates`, next fields is unused arm_index: 0, pat_index: 0, pre_binding_block: block, - next_candidate_pre_binding_block: block + next_candidate_pre_binding_block: block, }; // Simplify the candidate. Since the pattern is irrefutable, this should @@ -290,10 +342,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { unpack!(block = self.simplify_candidate(block, &mut candidate)); if !candidate.match_pairs.is_empty() { - span_bug!(candidate.match_pairs[0].pattern.span, - "match pairs {:?} remaining after simplifying \ - irrefutable pattern", - candidate.match_pairs); + span_bug!( + candidate.match_pairs[0].pattern.span, + "match pairs {:?} remaining after simplifying \ + irrefutable pattern", + candidate.match_pairs + ); } // for matches and function arguments, the place that is being matched @@ -304,9 +358,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for binding in &candidate.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); - if let Some(ClearCrossCrate::Set(BindingForm::Var( - VarBindingForm {opt_match_place: Some((ref mut match_place, _)), .. } - ))) = self.local_decls[local].is_user_variable + if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + opt_match_place: Some((ref mut match_place, _)), + .. + }))) = self.local_decls[local].is_user_variable { *match_place = Some(initializer.clone()); } else { @@ -315,6 +370,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + self.ascribe_types(block, &candidate.ascriptions); + // now apply the bindings, which will also declare the variables self.bind_matched_candidate_for_arm_body(block, &candidate.bindings); @@ -325,116 +382,183 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// scope for the bindings in these patterns, if such a scope had to be /// created. NOTE: Declaring the bindings should always be done in their /// drop scope. - pub fn declare_bindings(&mut self, - mut visibility_scope: Option<SourceScope>, - scope_span: Span, - lint_level: LintLevel, - patterns: &[Pattern<'tcx>], - has_guard: ArmHasGuard, - opt_match_place: Option<(Option<&Place<'tcx>>, Span)>) - -> Option<SourceScope> { - assert!(!(visibility_scope.is_some() && lint_level.is_explicit()), - "can't have both a visibility and a lint scope at the same time"); + pub fn declare_bindings( + &mut self, + mut visibility_scope: Option<SourceScope>, + scope_span: Span, + lint_level: LintLevel, + patterns: &[Pattern<'tcx>], + has_guard: ArmHasGuard, + opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, + ) -> Option<SourceScope> { + assert!( + !(visibility_scope.is_some() && lint_level.is_explicit()), + "can't have both a visibility and a lint scope at the same time" + ); let mut scope = self.source_scope; let num_patterns = patterns.len(); - self.visit_bindings(&patterns[0], &mut |this, mutability, name, mode, var, span, ty| { - if visibility_scope.is_none() { - visibility_scope = Some(this.new_source_scope(scope_span, - LintLevel::Inherited, - None)); - // If we have lints, create a new source scope - // that marks the lints for the locals. See the comment - // on the `source_info` field for why this is needed. - if lint_level.is_explicit() { - scope = - this.new_source_scope(scope_span, lint_level, None); + self.visit_bindings( + &patterns[0], + None, + &mut |this, mutability, name, mode, var, span, ty, user_ty| { + if visibility_scope.is_none() { + visibility_scope = + Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); + // If we have lints, create a new source scope + // that marks the lints for the locals. See the comment + // on the `source_info` field for why this is needed. + if lint_level.is_explicit() { + scope = this.new_source_scope(scope_span, lint_level, None); + } } - } - let source_info = SourceInfo { - span, - scope, - }; - let visibility_scope = visibility_scope.unwrap(); - this.declare_binding(source_info, visibility_scope, mutability, name, mode, - num_patterns, var, ty, has_guard, - opt_match_place.map(|(x, y)| (x.cloned(), y)), - patterns[0].span); - }); + let source_info = SourceInfo { span, scope }; + let visibility_scope = visibility_scope.unwrap(); + this.declare_binding( + source_info, + visibility_scope, + mutability, + name, + mode, + num_patterns, + var, + ty, + user_ty, + has_guard, + opt_match_place.map(|(x, y)| (x.cloned(), y)), + patterns[0].span, + ); + }, + ); visibility_scope } - pub fn storage_live_binding(&mut self, - block: BasicBlock, - var: NodeId, - span: Span, - for_guard: ForGuard) - -> Place<'tcx> - { + pub fn storage_live_binding( + &mut self, + block: BasicBlock, + var: NodeId, + span: Span, + for_guard: ForGuard, + ) -> Place<'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); - self.cfg.push(block, Statement { - source_info, - kind: StatementKind::StorageLive(local_id) - }); + self.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::StorageLive(local_id), + }, + ); let place = Place::Local(local_id); let var_ty = self.local_decls[local_id].ty; let hir_id = self.hir.tcx().hir.node_to_hir_id(var); let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id); - self.schedule_drop( - span, region_scope, &place, var_ty, - DropKind::Storage, - ); + self.schedule_drop(span, region_scope, &place, var_ty, DropKind::Storage); place } - pub fn schedule_drop_for_binding(&mut self, - var: NodeId, - span: Span, - for_guard: ForGuard) { + pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span, for_guard: ForGuard) { let local_id = self.var_local_id(var, for_guard); let var_ty = self.local_decls[local_id].ty; let hir_id = self.hir.tcx().hir.node_to_hir_id(var); let region_scope = self.hir.region_scope_tree.var_scope(hir_id.local_id); self.schedule_drop( - span, region_scope, &Place::Local(local_id), var_ty, + span, + region_scope, + &Place::Local(local_id), + var_ty, DropKind::Value { cached_block: CachedBlock::default(), }, ); } - pub fn visit_bindings<F>(&mut self, pattern: &Pattern<'tcx>, f: &mut F) - where F: FnMut(&mut Self, Mutability, Name, BindingMode, NodeId, Span, Ty<'tcx>) - { + pub fn visit_bindings( + &mut self, + pattern: &Pattern<'tcx>, + mut pattern_user_ty: Option<CanonicalTy<'tcx>>, + f: &mut impl FnMut( + &mut Self, + Mutability, + Name, + BindingMode, + NodeId, + Span, + Ty<'tcx>, + Option<CanonicalTy<'tcx>>, + ), + ) { match *pattern.kind { - PatternKind::Binding { mutability, name, mode, var, ty, ref subpattern, .. } => { - f(self, mutability, name, mode, var, pattern.span, ty); + PatternKind::Binding { + mutability, + name, + mode, + var, + ty, + ref subpattern, + .. + } => { + match mode { + BindingMode::ByValue => { } + BindingMode::ByRef(..) => { + // If this is a `ref` binding (e.g., `let ref + // x: T = ..`), then the type of `x` is not + // `T` but rather `&T`, so ignore + // `pattern_user_ty` for now. + // + // FIXME(#47184): extract or handle `pattern_user_ty` somehow + pattern_user_ty = None; + } + } + + f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty); if let Some(subpattern) = subpattern.as_ref() { - self.visit_bindings(subpattern, f); + self.visit_bindings(subpattern, pattern_user_ty, f); } } - PatternKind::Array { ref prefix, ref slice, ref suffix } | - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + PatternKind::Array { + ref prefix, + ref slice, + ref suffix, + } + | PatternKind::Slice { + ref prefix, + ref slice, + ref suffix, + } => { + // FIXME(#47184): extract or handle `pattern_user_ty` somehow for subpattern in prefix.iter().chain(slice).chain(suffix) { - self.visit_bindings(subpattern, f); + self.visit_bindings(subpattern, None, f); } } - PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { - } + PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {} PatternKind::Deref { ref subpattern } => { - self.visit_bindings(subpattern, f); + // FIXME(#47184): extract or handle `pattern_user_ty` somehow + self.visit_bindings(subpattern, None, f); } - PatternKind::Leaf { ref subpatterns } | - PatternKind::Variant { ref subpatterns, .. } => { + PatternKind::AscribeUserType { ref subpattern, user_ty } => { + // This corresponds to something like + // + // ``` + // let (p1: T1): T2 = ...; + // ``` + // + // Not presently possible, though maybe someday. + assert!(pattern_user_ty.is_none()); + self.visit_bindings(subpattern, Some(user_ty), f) + } + PatternKind::Leaf { ref subpatterns } + | PatternKind::Variant { + ref subpatterns, .. + } => { + // FIXME(#47184): extract or handle `pattern_user_ty` somehow for subpattern in subpatterns { - self.visit_bindings(&subpattern.pattern, f); + self.visit_bindings(&subpattern.pattern, None, f); } } } } } - /// List of blocks for each arm (and potentially other metadata in the /// future). struct ArmBlocks { @@ -442,7 +566,7 @@ struct ArmBlocks { } #[derive(Clone, Debug)] -pub struct Candidate<'pat, 'tcx:'pat> { +pub struct Candidate<'pat, 'tcx: 'pat> { // span of the original pattern that gave rise to this candidate span: Span, @@ -452,6 +576,9 @@ pub struct Candidate<'pat, 'tcx:'pat> { // ...these bindings established... bindings: Vec<Binding<'tcx>>, + // ...these types asserted... + ascriptions: Vec<Ascription<'tcx>>, + // ...and the guard must be evaluated... guard: Option<Guard<'tcx>>, @@ -477,8 +604,18 @@ struct Binding<'tcx> { binding_mode: BindingMode<'tcx>, } +/// Indicates that the type of `source` must be a subtype of the +/// user-given type `user_ty`; this is basically a no-op but can +/// influence region inference. +#[derive(Clone, Debug)] +struct Ascription<'tcx> { + span: Span, + source: Place<'tcx>, + user_ty: CanonicalTy<'tcx>, +} + #[derive(Clone, Debug)] -pub struct MatchPair<'pat, 'tcx:'pat> { +pub struct MatchPair<'pat, 'tcx: 'pat> { // this place... place: Place<'tcx>, @@ -490,7 +627,7 @@ pub struct MatchPair<'pat, 'tcx:'pat> { // the "rest" part of the pattern right now has type &[T] and // as such, it requires an Rvalue::Slice to be generated. // See RFC 495 / issue #23121 for the eventual (proper) solution. - slice_len_checked: bool + slice_len_checked: bool, } #[derive(Clone, Debug, PartialEq)] @@ -559,15 +696,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// up the list of candidates and recurse with a non-exhaustive /// list. This is important to keep the size of the generated code /// under control. See `test_candidates` for more details. - fn match_candidates<'pat>(&mut self, - span: Span, - arm_blocks: &mut ArmBlocks, - mut candidates: Vec<Candidate<'pat, 'tcx>>, - mut block: BasicBlock) - -> Vec<BasicBlock> - { - debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})", - span, block, candidates); + fn match_candidates<'pat>( + &mut self, + span: Span, + arm_blocks: &mut ArmBlocks, + mut candidates: Vec<Candidate<'pat, 'tcx>>, + mut block: BasicBlock, + ) -> Vec<BasicBlock> { + debug!( + "matched_candidate(span={:?}, block={:?}, candidates={:?})", + span, block, candidates + ); // Start by simplifying candidates. Once this process is // complete, all the match pairs which remain require some @@ -580,13 +719,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // whether the higher priority candidates (and hence at // the front of the vec) have satisfied all their match // pairs. - let fully_matched = - candidates.iter().take_while(|c| c.match_pairs.is_empty()).count(); - debug!("match_candidates: {:?} candidates fully matched", fully_matched); + let fully_matched = candidates + .iter() + .take_while(|c| c.match_pairs.is_empty()) + .count(); + debug!( + "match_candidates: {:?} candidates fully matched", + fully_matched + ); let mut unmatched_candidates = candidates.split_off(fully_matched); - let fully_matched_with_guard = - candidates.iter().take_while(|c| c.guard.is_some()).count(); + let fully_matched_with_guard = candidates.iter().take_while(|c| c.guard.is_some()).count(); let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() { candidates.split_off(fully_matched_with_guard + 1) @@ -603,20 +746,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // if None is returned, then any remaining candidates // are unreachable (at least not through this path). // Link them with false edges. - debug!("match_candidates: add false edges for unreachable {:?} and unmatched {:?}", - unreachable_candidates, unmatched_candidates); + debug!( + "match_candidates: add false edges for unreachable {:?} and unmatched {:?}", + unreachable_candidates, unmatched_candidates + ); for candidate in unreachable_candidates { let source_info = self.source_info(candidate.span); let target = self.cfg.start_new_block(); - if let Some(otherwise) = self.bind_and_guard_matched_candidate(target, - arm_blocks, - candidate) { - self.cfg.terminate(otherwise, source_info, TerminatorKind::Unreachable); + if let Some(otherwise) = + self.bind_and_guard_matched_candidate(target, arm_blocks, candidate) + { + self.cfg + .terminate(otherwise, source_info, TerminatorKind::Unreachable); } } if unmatched_candidates.is_empty() { - return vec![] + return vec![]; } else { let target = self.cfg.start_new_block(); return self.match_candidates(span, arm_blocks, unmatched_candidates, target); @@ -649,11 +795,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.match_candidates(span, arm_blocks, untested_candidates, join_block) } - fn join_otherwise_blocks(&mut self, - span: Span, - mut otherwise: Vec<BasicBlock>) - -> BasicBlock - { + fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec<BasicBlock>) -> BasicBlock { let source_info = self.source_info(span); otherwise.sort(); otherwise.dedup(); // variant switches can introduce duplicate target blocks @@ -662,8 +804,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { let join_block = self.cfg.start_new_block(); for block in otherwise { - self.cfg.terminate(block, source_info, - TerminatorKind::Goto { target: join_block }); + self.cfg.terminate( + block, + source_info, + TerminatorKind::Goto { target: join_block }, + ); } join_block } @@ -781,13 +926,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// In addition to avoiding exponential-time blowups, this algorithm /// also has nice property that each guard and arm is only generated /// once. - fn test_candidates<'pat>(&mut self, - span: Span, - arm_blocks: &mut ArmBlocks, - candidates: &[Candidate<'pat, 'tcx>], - block: BasicBlock) - -> (Vec<BasicBlock>, usize) - { + fn test_candidates<'pat>( + &mut self, + span: Span, + arm_blocks: &mut ArmBlocks, + candidates: &[Candidate<'pat, 'tcx>], + block: BasicBlock, + ) -> (Vec<BasicBlock>, usize) { // extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; let mut test = self.test(match_pair); @@ -797,34 +942,44 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // may want to add cases based on the candidates that are // available match test.kind { - TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => { + TestKind::SwitchInt { + switch_ty, + ref mut options, + ref mut indices, + } => { for candidate in candidates.iter() { - if !self.add_cases_to_switch(&match_pair.place, - candidate, - switch_ty, - options, - indices) { + if !self.add_cases_to_switch( + &match_pair.place, + candidate, + switch_ty, + options, + indices, + ) { break; } } } - TestKind::Switch { adt_def: _, ref mut variants} => { + TestKind::Switch { + adt_def: _, + ref mut variants, + } => { for candidate in candidates.iter() { - if !self.add_variants_to_switch(&match_pair.place, - candidate, - variants) { + if !self.add_variants_to_switch(&match_pair.place, candidate, variants) { break; } } } - _ => { } + _ => {} } // perform the test, branching to one of N blocks. For each of // those N possible outcomes, create a (initially empty) // vector of candidates. Those are the candidates that still // apply if the test has that particular outcome. - debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair); + debug!( + "match_candidates: test={:?} match_pair={:?}", + test, match_pair + ); let target_blocks = self.perform_test(block, &match_pair.place, &test); let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect(); @@ -832,31 +987,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // `target_candidates`. Note that at some point we may // encounter a candidate where the test is not relevant; at // that point, we stop sorting. - let tested_candidates = - candidates.iter() - .take_while(|c| self.sort_candidate(&match_pair.place, - &test, - c, - &mut target_candidates)) - .count(); + let tested_candidates = candidates + .iter() + .take_while(|c| { + self.sort_candidate(&match_pair.place, &test, c, &mut target_candidates) + }) + .count(); assert!(tested_candidates > 0); // at least the last candidate ought to be tested debug!("tested_candidates: {}", tested_candidates); - debug!("untested_candidates: {}", candidates.len() - tested_candidates); + debug!( + "untested_candidates: {}", + candidates.len() - tested_candidates + ); // For each outcome of test, process the candidates that still // apply. Collect a list of blocks where control flow will // branch if one of the `target_candidate` sets is not // exhaustive. - let otherwise: Vec<_> = - target_blocks.into_iter() - .zip(target_candidates) - .flat_map(|(target_block, target_candidates)| { - self.match_candidates(span, - arm_blocks, - target_candidates, - target_block) - }) - .collect(); + let otherwise: Vec<_> = target_blocks + .into_iter() + .zip(target_candidates) + .flat_map(|(target_block, target_candidates)| { + self.match_candidates(span, arm_blocks, target_candidates, target_block) + }) + .collect(); (otherwise, tested_candidates) } @@ -873,30 +1027,41 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// bindings, further tests would be a use-after-move (which would /// in turn be detected by the borrowck code that runs on the /// MIR). - fn bind_and_guard_matched_candidate<'pat>(&mut self, - mut block: BasicBlock, - arm_blocks: &mut ArmBlocks, - candidate: Candidate<'pat, 'tcx>) - -> Option<BasicBlock> { - debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})", - block, candidate); + fn bind_and_guard_matched_candidate<'pat>( + &mut self, + mut block: BasicBlock, + arm_blocks: &mut ArmBlocks, + candidate: Candidate<'pat, 'tcx>, + ) -> Option<BasicBlock> { + debug!( + "bind_and_guard_matched_candidate(block={:?}, candidate={:?})", + block, candidate + ); debug_assert!(candidate.match_pairs.is_empty()); + self.ascribe_types(block, &candidate.ascriptions); + let arm_block = arm_blocks.blocks[candidate.arm_index]; let candidate_source_info = self.source_info(candidate.span); - self.cfg.terminate(block, candidate_source_info, - TerminatorKind::Goto { target: candidate.pre_binding_block }); + self.cfg.terminate( + block, + candidate_source_info, + TerminatorKind::Goto { + target: candidate.pre_binding_block, + }, + ); block = self.cfg.start_new_block(); - self.cfg.terminate(candidate.pre_binding_block, candidate_source_info, - TerminatorKind::FalseEdges { - real_target: block, - imaginary_targets: - vec![candidate.next_candidate_pre_binding_block], - }); - + self.cfg.terminate( + candidate.pre_binding_block, + candidate_source_info, + TerminatorKind::FalseEdges { + real_target: block, + imaginary_targets: vec![candidate.next_candidate_pre_binding_block], + }, + ); // rust-lang/rust#27282: The `autoref` business deserves some // explanation here. @@ -980,13 +1145,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // match input itself; it is up to us to create a place // holding a `&` or `&mut` that we can then borrow). - let autoref = self.hir.tcx().all_pat_vars_are_implicit_refs_within_guards(); + let autoref = self.hir + .tcx() + .all_pat_vars_are_implicit_refs_within_guards(); if let Some(guard) = candidate.guard { if autoref { self.bind_matched_candidate_for_guard( - block, candidate.pat_index, &candidate.bindings); + block, + candidate.pat_index, + &candidate.bindings, + ); let guard_frame = GuardFrame { - locals: candidate.bindings.iter() + locals: candidate + .bindings + .iter() .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)) .collect(), }; @@ -1005,7 +1177,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let cond = unpack!(block = self.as_local_operand(block, guard)); if autoref { let guard_frame = self.guard_context.pop().unwrap(); - debug!("Exiting guard building context with locals: {:?}", guard_frame); + debug!( + "Exiting guard building context with locals: {:?}", + guard_frame + ); } let false_edge_block = self.cfg.start_new_block(); @@ -1037,45 +1212,82 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // // and that is clearly not correct. let post_guard_block = self.cfg.start_new_block(); - self.cfg.terminate(block, source_info, - TerminatorKind::if_(self.hir.tcx(), cond, post_guard_block, - false_edge_block)); + self.cfg.terminate( + block, + source_info, + TerminatorKind::if_(self.hir.tcx(), cond, post_guard_block, false_edge_block), + ); if autoref { self.bind_matched_candidate_for_arm_body(post_guard_block, &candidate.bindings); } - self.cfg.terminate(post_guard_block, source_info, - TerminatorKind::Goto { target: arm_block }); + self.cfg.terminate( + post_guard_block, + source_info, + TerminatorKind::Goto { target: arm_block }, + ); let otherwise = self.cfg.start_new_block(); - self.cfg.terminate(false_edge_block, source_info, - TerminatorKind::FalseEdges { - real_target: otherwise, - imaginary_targets: - vec![candidate.next_candidate_pre_binding_block], - }); + self.cfg.terminate( + false_edge_block, + source_info, + TerminatorKind::FalseEdges { + real_target: otherwise, + imaginary_targets: vec![candidate.next_candidate_pre_binding_block], + }, + ); Some(otherwise) } else { // (Here, it is not too early to bind the matched // candidate on `block`, because there is no guard result // that we have to inspect before we bind them.) self.bind_matched_candidate_for_arm_body(block, &candidate.bindings); - self.cfg.terminate(block, candidate_source_info, - TerminatorKind::Goto { target: arm_block }); + self.cfg.terminate( + block, + candidate_source_info, + TerminatorKind::Goto { target: arm_block }, + ); None } } + /// Append `AscribeUserType` statements onto the end of `block` + /// for each ascription + fn ascribe_types<'pat>( + &mut self, + block: BasicBlock, + ascriptions: &[Ascription<'tcx>], + ) { + for ascription in ascriptions { + let source_info = self.source_info(ascription.span); + self.cfg.push( + block, + Statement { + source_info, + kind: StatementKind::AscribeUserType( + ascription.source.clone(), + ty::Variance::Covariant, + ascription.user_ty, + ), + }, + ); + } + } + // Only called when all_pat_vars_are_implicit_refs_within_guards, // and thus all code/comments assume we are in that context. - fn bind_matched_candidate_for_guard(&mut self, - block: BasicBlock, - pat_index: usize, - bindings: &[Binding<'tcx>]) { - debug!("bind_matched_candidate_for_guard(block={:?}, pat_index={:?}, bindings={:?})", - block, pat_index, bindings); + fn bind_matched_candidate_for_guard( + &mut self, + block: BasicBlock, + pat_index: usize, + bindings: &[Binding<'tcx>], + ) { + debug!( + "bind_matched_candidate_for_guard(block={:?}, pat_index={:?}, bindings={:?})", + block, pat_index, bindings + ); // Assign each of the bindings. Since we are binding for a // guard expression, this will never trigger moves out of the @@ -1088,8 +1300,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // a reference R: &T pointing to the location matched by // the pattern, and every occurrence of P within a guard // denotes *R. - let ref_for_guard = self.storage_live_binding( - block, binding.var_id, binding.span, RefWithinGuard); + let ref_for_guard = + self.storage_live_binding(block, binding.var_id, binding.span, RefWithinGuard); // Question: Why schedule drops if bindings are all // shared-&'s? Answer: Because schedule_drop_for_binding // also emits StorageDead's for those locals. @@ -1097,7 +1309,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match binding.binding_mode { BindingMode::ByValue => { let rvalue = Rvalue::Ref(re_empty, BorrowKind::Shared, binding.source.clone()); - self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue); + self.cfg + .push_assign(block, source_info, &ref_for_guard, rvalue); } BindingMode::ByRef(region, borrow_kind) => { // Tricky business: For `ref id` and `ref mut id` @@ -1114,9 +1327,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // used by the arm body itself. This eases // observing two-phase borrow restrictions. let val_for_guard = self.storage_live_binding( - block, binding.var_id, binding.span, ValWithinGuard(pat_index)); + block, + binding.var_id, + binding.span, + ValWithinGuard(pat_index), + ); self.schedule_drop_for_binding( - binding.var_id, binding.span, ValWithinGuard(pat_index)); + binding.var_id, + binding.span, + ValWithinGuard(pat_index), + ); // rust-lang/rust#27282: We reuse the two-phase // borrow infrastructure so that the mutable @@ -1126,27 +1346,36 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // discussion on rust-lang/rust#49870. let borrow_kind = match borrow_kind { BorrowKind::Shared | BorrowKind::Unique => borrow_kind, - BorrowKind::Mut { .. } => BorrowKind::Mut { allow_two_phase_borrow: true }, + BorrowKind::Mut { .. } => BorrowKind::Mut { + allow_two_phase_borrow: true, + }, }; let rvalue = Rvalue::Ref(region, borrow_kind, binding.source.clone()); - self.cfg.push_assign(block, source_info, &val_for_guard, rvalue); + self.cfg + .push_assign(block, source_info, &val_for_guard, rvalue); let rvalue = Rvalue::Ref(region, BorrowKind::Shared, val_for_guard); - self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue); + self.cfg + .push_assign(block, source_info, &ref_for_guard, rvalue); } } } } - fn bind_matched_candidate_for_arm_body(&mut self, - block: BasicBlock, - bindings: &[Binding<'tcx>]) { - debug!("bind_matched_candidate_for_arm_body(block={:?}, bindings={:?}", block, bindings); + fn bind_matched_candidate_for_arm_body( + &mut self, + block: BasicBlock, + bindings: &[Binding<'tcx>], + ) { + debug!( + "bind_matched_candidate_for_arm_body(block={:?}, bindings={:?}", + block, bindings + ); // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); - let local = self.storage_live_binding(block, binding.var_id, binding.span, - OutsideGuard); + let local = + self.storage_live_binding(block, binding.var_id, binding.span, OutsideGuard); self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); let rvalue = match binding.binding_mode { BindingMode::ByValue => { @@ -1175,22 +1404,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// parts of the matched data, and we want them to be distinct /// temps in order to simplify checks performed by our internal /// leveraging of two-phase borrows). - fn declare_binding(&mut self, - source_info: SourceInfo, - visibility_scope: SourceScope, - mutability: Mutability, - name: Name, - mode: BindingMode, - num_patterns: usize, - var_id: NodeId, - var_ty: Ty<'tcx>, - has_guard: ArmHasGuard, - opt_match_place: Option<(Option<Place<'tcx>>, Span)>, - pat_span: Span) - { - debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \ - visibility_scope={:?}, source_info={:?})", - var_id, name, mode, var_ty, visibility_scope, source_info); + fn declare_binding( + &mut self, + source_info: SourceInfo, + visibility_scope: SourceScope, + mutability: Mutability, + name: Name, + mode: BindingMode, + num_patterns: usize, + var_id: NodeId, + var_ty: Ty<'tcx>, + user_var_ty: Option<CanonicalTy<'tcx>>, + has_guard: ArmHasGuard, + opt_match_place: Option<(Option<Place<'tcx>>, Span)>, + pat_span: Span, + ) { + debug!( + "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \ + visibility_scope={:?}, source_info={:?})", + var_id, name, mode, var_ty, visibility_scope, source_info + ); let tcx = self.hir.tcx(); let binding_mode = match mode { @@ -1199,7 +1432,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; let local = LocalDecl::<'tcx> { mutability, - ty: var_ty.clone(), + ty: var_ty, + user_ty: user_var_ty, name: Some(name), source_info, visibility_scope, @@ -1231,6 +1465,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // See previous comment. mutability: Mutability::Not, ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty), + user_ty: None, name: Some(name), source_info, visibility_scope, @@ -1238,7 +1473,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { internal: false, is_user_variable: Some(ClearCrossCrate::Set(BindingForm::RefForGuard)), }); - LocalsForNode::ForGuard { vals_for_guard, ref_for_guard, for_arm_body } + LocalsForNode::ForGuard { + vals_for_guard, + ref_for_guard, + for_arm_body, + } } else { LocalsForNode::One(for_arm_body) }; diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 147b8cc2175..14da8e90838 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -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(()) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 4a0b4b0c885..373c8e039f8 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -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, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 322a6977bed..576c91a02b0 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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, diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index f42612b4b7a..cc92cdecc60 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -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 => {} } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index dde2e819fd2..5451d27082d 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -304,7 +304,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { } StatementKind::EndRegion(_) | StatementKind::Validate(..) | - StatementKind::UserAssertTy(..) | + StatementKind::AscribeUserType(..) | StatementKind::Nop => {} } } diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 6c8b5d97b6f..85a9734a601 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -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), }, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 2ddb810f491..d86aee54312 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -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>>, diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index d7fbbc88cc1..aa1c6902dce 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -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()) } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 384ee0079dc..ee50322fbb3 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -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 { diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 545333e8791..cb8e1284d09 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -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. diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index d4024981c37..f2c011ccee6 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -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"] diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 7e7e7cfade6..a6c03975685 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index ec7fd371a44..6fbc2f85c08 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -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) } diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 256b1fd66e9..9edb1a1f76a 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -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); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 1ad713b4b7d..01edfd2bfc9 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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, diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 1e05b07030e..19fb35be9d4 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -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, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 81fc235c233..a2175dce33a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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 => {} } }); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index eacc23c9c4f..f7e44dde186 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -230,7 +230,7 @@ fn check_statement( | StatementKind::StorageDead(_) | StatementKind::Validate(..) | StatementKind::EndRegion(_) - | StatementKind::UserAssertTy(..) + | StatementKind::AscribeUserType(..) | StatementKind::Nop => Ok(()), } } diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 04a7a81eb12..a2561d3d793 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -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 diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 9faaeea3f5b..f3e0f557363 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -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, diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 9f5b5040b09..710ccb2053b 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -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}", diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bca119660aa..2ee5415018f 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -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| diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 3c5a0590c20..b65a2e3f0e5 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -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) diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 44030c284fd..61c2ac161bb 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -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") diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 3206fa6e172..0120b5bc532 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -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); } diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index ea4fba3e124..74b010f57b0 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -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; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 63f643d7a29..d1a05964c8f 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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); + } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5cb615554ee..8c769094f52 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 = diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 93874ee0e85..7733ce475e3 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -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 { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f8767fa553f..dfbea0ffe22 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -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, _ => {} } diff --git a/src/librustc_target/abi/call/amdgpu.rs b/src/librustc_target/abi/call/amdgpu.rs new file mode 100644 index 00000000000..62462f04d8f --- /dev/null +++ b/src/librustc_target/abi/call/amdgpu.rs @@ -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); + } +} diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 78ed4b2d615..788497a378f 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -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), diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 972c2f0e15c..45a5e5115a3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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)?; } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 3e54b502234..804d43f4fc6 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -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] // diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2b87094926c..372f3e83e3d 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -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. /// diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b83f3fbe7a5..278ee7951b3 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -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 diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4278926b042..5c9e88dc57c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -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)] diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 0e059bc4a6c..07c3e578e5b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 3bb19121ee3..7b4e1814a33 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e912482cf58..2b4daa6440c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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); } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b7e8a880e7e..aa47d5bf669 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -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, } diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 9e08fa232f1..8047ab01465 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -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(); } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index e16f3b1ccb3..88af4a73a15 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -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"), diff --git a/src/llvm b/src/llvm -Subproject 2a1cdeadd3ea8e1eba9cc681037b83f07332763 +Subproject 5a081f0363340dd895d0958955d0c84661f60f0 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 24a384fceb8..29b7d508f1c 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -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 diff --git a/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs b/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs index 3cb565c1ede..cf2522be922 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs @@ -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; diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs index 52d7afb26ad..e0922c452b5 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs @@ -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; diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs index 5cf65103ba3..c07e6e31d62 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs @@ -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 diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 957cb336d9e..097cd665375 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -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; diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index 54b7a3821ca..f04d4328929 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -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 diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs deleted file mode 100644 index 8a7ea8962fc..00000000000 --- a/src/test/mir-opt/nll/reborrow-basic.rs +++ /dev/null @@ -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 diff --git a/src/test/run-make-fulldeps/used/used.rs b/src/test/run-make-fulldeps/used/used.rs index 186cd0fdf5e..6992dd94af3 100644 --- a/src/test/run-make-fulldeps/used/used.rs +++ b/src/test/run-make-fulldeps/used/used.rs @@ -9,7 +9,6 @@ // except according to those terms. #![crate_type = "lib"] -#![feature(used)] #[used] static FOO: u32 = 0; diff --git a/src/test/run-pass/.gitattributes b/src/test/run-pass/.gitattributes index 46db548a8c4..c6a6f23074d 100644 --- a/src/test/run-pass/.gitattributes +++ b/src/test/run-pass/.gitattributes @@ -1,2 +1 @@ lexer-crlf-line-endings-string-literal-doc-comment.rs -text -issue-16278.rs -text diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 46f22845907..f692f57abb9 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -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)) + } + }, } } diff --git a/src/test/ui/feature-gates/feature-gate-used.rs b/src/test/rustdoc/auxiliary/issue-53689.rs index 68679d7dac8..7b7f9013ca3 100644 --- a/src/test/ui/feature-gates/feature-gate-used.rs +++ b/src/test/rustdoc/auxiliary/issue-53689.rs @@ -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; diff --git a/src/test/rustdoc/issue-53689.rs b/src/test/rustdoc/issue-53689.rs new file mode 100644 index 00000000000..bfe5adf8888 --- /dev/null +++ b/src/test/rustdoc/issue-53689.rs @@ -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; +} diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs new file mode 100644 index 00000000000..6a47e50f62d --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs @@ -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 +} diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr new file mode 100644 index 00000000000..db07055b6a1 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr @@ -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`. diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs new file mode 100644 index 00000000000..9f4f0abf324 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs @@ -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 +} diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr new file mode 100644 index 00000000000..ea867faf47b --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr @@ -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`. diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs new file mode 100644 index 00000000000..e18ca57aab1 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs @@ -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() +} diff --git a/src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs new file mode 100644 index 00000000000..ff5984aa67c --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.rs @@ -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 +} diff --git a/src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr new file mode 100644 index 00000000000..be6e80c3878 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/reserved-macro-names.stderr @@ -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 + diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr deleted file mode 100644 index ed3e38486ba..00000000000 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr deleted file mode 100644 index 4c8f2f47d1e..00000000000 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/directory_ownership/mod_file_not_owning.stderr b/src/test/ui/directory_ownership/mod_file_not_owning.stderr deleted file mode 100644 index e2937573997..00000000000 --- a/src/test/ui/directory_ownership/mod_file_not_owning.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660) - --> $DIR/mod_file_not_owning_aux1.rs:14:17 - | -LL | () => { mod mod_file_not_owning_aux2; } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -LL | } -LL | m!(); - | ----- in this macro invocation - | - = help: add #![feature(non_modrs_mods)] to the crate attributes to enable - = help: on stable builds, rename this file to mod_file_not_owning_aux1/mod.rs - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/directory_ownership/unowned_mod_with_path.stderr b/src/test/ui/directory_ownership/unowned_mod_with_path.stderr deleted file mode 100644 index 0c0b4281434..00000000000 --- a/src/test/ui/directory_ownership/unowned_mod_with_path.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660) - --> $DIR/mod_file_not_owning_aux1.rs:14:17 - | -LL | () => { mod mod_file_not_owning_aux2; } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -LL | } -LL | m!(); - | ----- in this macro invocation - | - = help: add #![feature(non_modrs_mods)] to the crate attributes to enable - = help: on stable builds, rename this file to foo/mod.rs - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr b/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr index c9b4f894ff6..0a0b1d573dd 100644 --- a/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr +++ b/src/test/ui/dollar-crate/dollar-crate-is-keyword-2.stderr @@ -1,17 +1,17 @@ -error[E0432]: unresolved import `a::$crate` - --> $DIR/dollar-crate-is-keyword-2.rs:15:13 +error[E0433]: failed to resolve. `$crate` in paths can only be used in start position + --> $DIR/dollar-crate-is-keyword-2.rs:16:16 | -LL | use a::$crate; //~ ERROR unresolved import `a::$crate` - | ^^^^^^^^^ no `$crate` in `a` +LL | use a::$crate::b; //~ ERROR `$crate` in paths can only be used in start position + | ^^^^^^ `$crate` in paths can only be used in start position ... LL | m!(); | ----- in this macro invocation -error[E0433]: failed to resolve. `$crate` in paths can only be used in start position - --> $DIR/dollar-crate-is-keyword-2.rs:16:16 +error[E0432]: unresolved import `a::$crate` + --> $DIR/dollar-crate-is-keyword-2.rs:15:13 | -LL | use a::$crate::b; //~ ERROR `$crate` in paths can only be used in start position - | ^^^^^^ `$crate` in paths can only be used in start position +LL | use a::$crate; //~ ERROR unresolved import `a::$crate` + | ^^^^^^^^^ no `$crate` in `a` ... LL | m!(); | ----- in this macro invocation diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs b/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs index 6c226799338..d0adcf4025f 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-bench.rs @@ -20,6 +20,8 @@ // See issue-12997-1.rs and issue-12997-2.rs to see how `#[bench]` is // handled in "weird places" when `--test` is passed. +#![feature(custom_inner_attributes)] + #![bench = "4100"] fn main() { } diff --git a/src/test/ui/feature-gates/feature-gate-linker-flavor.rs b/src/test/ui/feature-gates/feature-gate-linker-flavor.rs index 955ec39cda1..711159647b7 100644 --- a/src/test/ui/feature-gates/feature-gate-linker-flavor.rs +++ b/src/test/ui/feature-gates/feature-gate-linker-flavor.rs @@ -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. // @@ -15,6 +15,5 @@ #[used] fn foo() {} -//~^^ ERROR the `#[used]` attribute is an experimental feature fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr b/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr index b8bccece292..7019a666548 100644 --- a/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr +++ b/src/test/ui/feature-gates/feature-gate-linker-flavor.stderr @@ -1,11 +1,8 @@ -error[E0658]: the `#[used]` attribute is an experimental feature (see issue #40289) +error: attribute must be applied to a `static` variable --> $DIR/feature-gate-linker-flavor.rs:16:1 | LL | #[used] | ^^^^^^^ - | - = help: add #![feature(used)] to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-used.stderr b/src/test/ui/feature-gates/feature-gate-used.stderr deleted file mode 100644 index d650b5ebb3b..00000000000 --- a/src/test/ui/feature-gates/feature-gate-used.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: the `#[used]` attribute is an experimental feature (see issue #40289) - --> $DIR/feature-gate-used.rs:11:1 - | -LL | #[used] - | ^^^^^^^ - | - = help: add #![feature(used)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issue-53565.rs b/src/test/ui/issue-53565.rs new file mode 100644 index 00000000000..2bf38296f26 --- /dev/null +++ b/src/test/ui/issue-53565.rs @@ -0,0 +1,14 @@ +// 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 std::time::{foo, bar, buzz}; +use std::time::{abc, def}; +fn main(){ + println!("Hello World!"); +} diff --git a/src/test/ui/issue-53565.stderr b/src/test/ui/issue-53565.stderr new file mode 100644 index 00000000000..945f5efe4a8 --- /dev/null +++ b/src/test/ui/issue-53565.stderr @@ -0,0 +1,20 @@ +error[E0432]: unresolved imports `std::time::foo`, `std::time::bar`, `std::time::buzz` + --> $DIR/issue-53565.rs:10:17 + | +LL | use std::time::{foo, bar, buzz}; + | ^^^ ^^^ ^^^^ no `buzz` in `time` + | | | + | | no `bar` in `time` + | no `foo` in `time` + +error[E0432]: unresolved imports `std::time::abc`, `std::time::def` + --> $DIR/issue-53565.rs:11:17 + | +LL | use std::time::{abc, def}; + | ^^^ ^^^ no `def` in `time` + | | + | no `abc` in `time` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/issues/issue-11692-2.rs b/src/test/ui/issues/issue-11692-2.rs index 424cbd981c8..2e94a27838e 100644 --- a/src/test/ui/issues/issue-11692-2.rs +++ b/src/test/ui/issues/issue-11692-2.rs @@ -9,6 +9,5 @@ // except according to those terms. fn main() { - concat!(test!()); - //~^ error: cannot find macro `test!` in this scope + concat!(test!()); //~ ERROR `test` can only be used in attributes } diff --git a/src/test/ui/issues/issue-11692-2.stderr b/src/test/ui/issues/issue-11692-2.stderr index 51d6041e922..186c59a6149 100644 --- a/src/test/ui/issues/issue-11692-2.stderr +++ b/src/test/ui/issues/issue-11692-2.stderr @@ -1,7 +1,7 @@ -error: cannot find macro `test!` in this scope +error: `test` can only be used in attributes --> $DIR/issue-11692-2.rs:12:13 | -LL | concat!(test!()); +LL | concat!(test!()); //~ ERROR `test` can only be used in attributes | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs index 84c305f5907..dd1c2a44730 100644 --- a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs +++ b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.rs @@ -20,8 +20,17 @@ fn make_it() -> for<'a> fn(&'a u32, &'a u32) -> &'a u32 { panic!() } -fn main() { +fn foo() { let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it(); //~^ ERROR higher-ranked subtype error drop(a); } + +fn bar() { + // The code path for patterns is mildly different, so go ahead and + // test that too: + let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it(); + //~^ ERROR higher-ranked subtype error +} + +fn main() { } diff --git a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr index e08d848b471..c9195395b87 100644 --- a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr +++ b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr @@ -4,5 +4,11 @@ error: higher-ranked subtype error LL | let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it(); | ^^^^^^^^^ -error: aborting due to previous error +error: higher-ranked subtype error + --> $DIR/hr-fn-aaa-as-aba.rs:32:58 + | +LL | let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it(); + | ^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs b/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs index 9b8268d9736..bc7b031f72c 100644 --- a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs +++ b/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.rs @@ -16,9 +16,7 @@ // another -- effectively, the single lifetime `'a` is just inferred // to be the intersection of the two distinct lifetimes. // -// FIXME: However, we currently reject this example with an error, -// because of how we handle binders and equality in `relate_tys`. -// +// compile-pass // compile-flags:-Zno-leak-check #![feature(nll)] @@ -31,7 +29,6 @@ fn make_cell_aa() -> Cell<for<'a> fn(&'a u32, &'a u32)> { fn aa_eq_ab() { let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa(); - //~^ ERROR higher-ranked subtype error drop(a); } diff --git a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr b/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr deleted file mode 100644 index 17e8a32cb2a..00000000000 --- a/src/test/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: higher-ranked subtype error - --> $DIR/hr-fn-aau-eq-abu.rs:33:53 - | -LL | let a: Cell<for<'a, 'b> fn(&'a u32, &'b u32)> = make_cell_aa(); - | ^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/nll/relate_tys/universe-violation.rs b/src/test/ui/nll/relate_tys/universe-violation.rs new file mode 100644 index 00000000000..cc86c8d02d3 --- /dev/null +++ b/src/test/ui/nll/relate_tys/universe-violation.rs @@ -0,0 +1,17 @@ +// Test that the NLL `relate_tys` code correctly deduces that a +// function returning either argument CANNOT be upcast to one +// that returns always its first argument. +// +// compile-flags:-Zno-leak-check + +#![feature(nll)] + +fn make_it() -> fn(&'static u32) -> &'static u32 { + panic!() +} + +fn main() { + let a: fn(_) -> _ = make_it(); + let b: fn(&u32) -> &u32 = a; + drop(a); +} diff --git a/src/test/ui/nll/relate_tys/universe-violation.stderr b/src/test/ui/nll/relate_tys/universe-violation.stderr new file mode 100644 index 00000000000..6dc78789564 --- /dev/null +++ b/src/test/ui/nll/relate_tys/universe-violation.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/universe-violation.rs:15:31 + | +LL | let b: fn(&u32) -> &u32 = a; + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.rs b/src/test/ui/nll/relate_tys/var-appears-twice.rs new file mode 100644 index 00000000000..02b3006c531 --- /dev/null +++ b/src/test/ui/nll/relate_tys/var-appears-twice.rs @@ -0,0 +1,38 @@ +// Copyright 2017 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. + +// Test that the NLL `relate_tys` code correctly deduces that a +// function returning always its first argument can be upcast to one +// that returns either first or second argument. + +#![feature(nll)] +#![allow(warnings)] + +use std::cell::Cell; + +type DoubleCell<A> = Cell<(A, A)>; +type DoublePair<A> = (A, A); + +fn make_cell<'b>(x: &'b u32) -> Cell<(&'static u32, &'b u32)> { + panic!() +} + +fn main() { + let a: &'static u32 = &22; + let b = 44; + + // Here we get an error because `DoubleCell<_>` requires the same type + // on both parts of the `Cell`, and we can't have that. + let x: DoubleCell<_> = make_cell(&b); //~ ERROR + + // Here we do not get an error because `DoublePair<_>` permits + // variance on the lifetimes involved. + let y: DoublePair<_> = make_cell(&b).get(); +} diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.stderr b/src/test/ui/nll/relate_tys/var-appears-twice.stderr new file mode 100644 index 00000000000..15c4cc2e100 --- /dev/null +++ b/src/test/ui/nll/relate_tys/var-appears-twice.stderr @@ -0,0 +1,14 @@ +error[E0597]: `b` does not live long enough + --> $DIR/var-appears-twice.rs:33:38 + | +LL | let x: DoubleCell<_> = make_cell(&b); //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | } + | - `b` dropped here while still borrowed + | + = 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`. diff --git a/src/test/ui/nll/user-annotations/patterns.rs b/src/test/ui/nll/user-annotations/patterns.rs new file mode 100644 index 00000000000..53d97360c86 --- /dev/null +++ b/src/test/ui/nll/user-annotations/patterns.rs @@ -0,0 +1,121 @@ +// Test that various patterns also enforce types. + +#![feature(nll)] + +fn variable_no_initializer() { + let x = 22; + let y: &'static u32; + y = &x; //~ ERROR +} + +fn tuple_no_initializer() { + // FIXME(#47187): We are not propagating ascribed type through tuples. + + let x = 22; + let (y, z): (&'static u32, &'static u32); + y = &x; +} + +fn ref_with_ascribed_static_type() -> u32 { + // Check the behavior in some wacky cases. + let x = 22; + let y = &x; //~ ERROR + let ref z: &'static u32 = y; + **z +} + +fn ref_with_ascribed_any_type() -> u32 { + let x = 22; + let y = &x; + let ref z: &u32 = y; + **z +} + +struct Single<T> { value: T } + +fn struct_no_initializer() { + // FIXME(#47187): We are not propagating ascribed type through patterns. + + let x = 22; + let Single { value: y }: Single<&'static u32>; + y = &x; +} + +fn variable_with_initializer() { + let x = 22; + let y: &'static u32 = &x; //~ ERROR +} + +fn underscore_with_initializer() { + let x = 22; + let _: &'static u32 = &x; //~ ERROR + + let _: Vec<&'static String> = vec![&String::new()]; + //~^ ERROR borrowed value does not live long enough [E0597] + + let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); + //~^ ERROR borrowed value does not live long enough [E0597] + + let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); + //~^ ERROR borrowed value does not live long enough [E0597] +} + +fn pair_underscores_with_initializer() { + let x = 22; + let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR +} + +fn pair_variable_with_initializer() { + let x = 22; + let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR +} + +fn struct_single_field_variable_with_initializer() { + let x = 22; + let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR +} + +fn struct_single_field_underscore_with_initializer() { + let x = 22; + let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR +} + +struct Double<T> { value1: T, value2: T } + +fn struct_double_field_underscore_with_initializer() { + let x = 22; + let Double { value1: _, value2: _ }: Double<&'static u32> = Double { + value1: &x, //~ ERROR + value2: &44, + }; +} + +fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { + // The error in this test is inconsistency with + // `static_to_a_to_static_through_tuple`, but "feels right" to + // me. It occurs because we special case the single binding case + // and force the type of `y` to be `&'a u32`, even though the + // right-hand side has type `&'static u32`. + + let y: &'a u32 = &22; + y //~ ERROR +} + +fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 { + // FIXME(#47187): The fact that this type-checks is perhaps surprising. + // What happens is that the right-hand side is constrained to have + // type `&'a u32`, which is possible, because it has type + // `&'static u32`. The variable `y` is then forced to have type + // `&'static u32`, but it is constrained only by the right-hand + // side, not the ascribed type, and hence it passes. + + let (y, _z): (&'a u32, u32) = (&22, 44); + y +} + +fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { + let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR + y +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr new file mode 100644 index 00000000000..563de1a9e02 --- /dev/null +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -0,0 +1,143 @@ +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:8:9 + | +LL | y = &x; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:22:13 + | +LL | let y = &x; //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:46:27 + | +LL | let y: &'static u32 = &x; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:51:27 + | +LL | let _: &'static u32 = &x; //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/patterns.rs:53:41 + | +LL | let _: Vec<&'static String> = vec![&String::new()]; + | ^^^^^^^^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/patterns.rs:56:52 + | +LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); + | ^^^^^^^^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: borrowed value does not live long enough + --> $DIR/patterns.rs:59:53 + | +LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); + | ^^^^^^^^^^^^^ - temporary value only lives until here + | | + | temporary value does not live long enough + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:65:40 + | +LL | let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:70:40 + | +LL | let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:75:69 + | +LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:80:69 + | +LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:88:17 + | +LL | value1: &x, //~ ERROR + | ^^ borrowed value does not live long enough +... +LL | } + | - `x` dropped here while still borrowed + | + = note: borrowed value must be valid for the static lifetime... + +error: unsatisfied lifetime constraints + --> $DIR/patterns.rs:101:5 + | +LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y //~ ERROR + | ^ returning this value requires that `'a` must outlive `'static` + +error: unsatisfied lifetime constraints + --> $DIR/patterns.rs:117:40 + | +LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR + | ^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/non_modrs_mods/non_modrs_mods.rs b/src/test/ui/non_modrs_mods/non_modrs_mods.rs deleted file mode 100644 index 9dc85f4d3f9..00000000000 --- a/src/test/ui/non_modrs_mods/non_modrs_mods.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 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. -// -// Tests the formatting of the feature-gate errors for non_modrs_mods -// -// gate-test-non_modrs_mods -// ignore-windows -// ignore-pretty issue #37195 -pub mod modrs_mod; -pub mod foors_mod; - -#[path = "some_crazy_attr_mod_dir/arbitrary_name.rs"] -pub mod attr_mod; - -pub fn main() { - modrs_mod::inner_modrs_mod::innest::foo(); - modrs_mod::inner_foors_mod::innest::foo(); - foors_mod::inner_modrs_mod::innest::foo(); - foors_mod::inner_foors_mod::innest::foo(); - attr_mod::inner_modrs_mod::innest::foo(); -} diff --git a/src/test/ui/non_modrs_mods/non_modrs_mods.stderr b/src/test/ui/non_modrs_mods/non_modrs_mods.stderr deleted file mode 100644 index c45ab734fd5..00000000000 --- a/src/test/ui/non_modrs_mods/non_modrs_mods.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660) - --> $DIR/modrs_mod/inner_foors_mod.rs:11:9 - | -LL | pub mod innest; - | ^^^^^^ - | - = help: add #![feature(non_modrs_mods)] to the crate attributes to enable - = help: on stable builds, rename this file to inner_foors_mod/mod.rs - -error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660) - --> $DIR/foors_mod.rs:13:9 - | -LL | pub mod inner_modrs_mod; - | ^^^^^^^^^^^^^^^ - | - = help: add #![feature(non_modrs_mods)] to the crate attributes to enable - = help: on stable builds, rename this file to foors_mod/mod.rs - -error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660) - --> $DIR/foors_mod.rs:14:9 - | -LL | pub mod inner_foors_mod; - | ^^^^^^^^^^^^^^^ - | - = help: add #![feature(non_modrs_mods)] to the crate attributes to enable - = help: on stable builds, rename this file to foors_mod/mod.rs - -error[E0658]: mod statements in non-mod.rs files are unstable (see issue #44660) - --> $DIR/foors_mod/inner_foors_mod.rs:11:9 - | -LL | pub mod innest; - | ^^^^^^ - | - = help: add #![feature(non_modrs_mods)] to the crate attributes to enable - = help: on stable builds, rename this file to inner_foors_mod/mod.rs - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs new file mode 100644 index 00000000000..339d49104b0 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs @@ -0,0 +1,49 @@ +// 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. + +// edition:2015 + +// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up +// with examples easier. +#![feature(irrefutable_let_patterns)] + +#[allow(irrefutable_let_patterns)] +fn main() { + use std::ops::Range; + + if let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + if let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + while let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + while let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + if let true = false && false { } + //~^ ERROR ambigious use of `&&` + + while let true = (1 == 2) && false { } + //~^ ERROR ambigious use of `&&` + + // The following cases are not an error as parenthesis are used to + // clarify intent: + + if let Range { start: _, end: _ } = true..(true || false) { } + + if let Range { start: _, end: _ } = true..(true && false) { } + + while let Range { start: _, end: _ } = true..(true || false) { } + + while let Range { start: _, end: _ } = true..(true && false) { } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr new file mode 100644 index 00000000000..8597294913f --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr @@ -0,0 +1,56 @@ +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:21:47 + | +LL | if let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2015.rs:24:47 + | +LL | if let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:27:50 + | +LL | while let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2015.rs:30:50 + | +LL | while let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:33:19 + | +LL | if let true = false && false { } + | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:36:22 + | +LL | while let true = (1 == 2) && false { } + | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs new file mode 100644 index 00000000000..baa90bcf8e9 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs @@ -0,0 +1,49 @@ +// 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. + +// edition:2018 + +// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up +// with examples easier. +#![feature(irrefutable_let_patterns)] + +#[allow(irrefutable_let_patterns)] +fn main() { + use std::ops::Range; + + if let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + if let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + while let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + while let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + if let true = false && false { } + //~^ ERROR ambigious use of `&&` + + while let true = (1 == 2) && false { } + //~^ ERROR ambigious use of `&&` + + // The following cases are not an error as parenthesis are used to + // clarify intent: + + if let Range { start: _, end: _ } = true..(true || false) { } + + if let Range { start: _, end: _ } = true..(true && false) { } + + while let Range { start: _, end: _ } = true..(true || false) { } + + while let Range { start: _, end: _ } = true..(true && false) { } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr new file mode 100644 index 00000000000..86ee04747b2 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr @@ -0,0 +1,56 @@ +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:21:47 + | +LL | if let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2018.rs:24:47 + | +LL | if let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:27:50 + | +LL | while let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2018.rs:30:50 + | +LL | while let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:33:19 + | +LL | if let true = false && false { } + | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:36:22 + | +LL | while let true = (1 == 2) && false { } + | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/run-pass/issues/.gitattributes b/src/test/ui/run-pass/issues/.gitattributes new file mode 100644 index 00000000000..4517a4a2f1e --- /dev/null +++ b/src/test/ui/run-pass/issues/.gitattributes @@ -0,0 +1 @@ +issue-16278.rs -text diff --git a/src/test/ui/run-pass/issues/issue-16278.rs b/src/test/ui/run-pass/issues/issue-16278.rs index 831e83c8c4b..c3b6c5a38ba 100644 --- a/src/test/ui/run-pass/issues/issue-16278.rs +++ b/src/test/ui/run-pass/issues/issue-16278.rs @@ -13,8 +13,9 @@ // this file has some special \r\n endings (use xxd to see them) -fn main() {assert_eq!(b"", b"\ +fn main() {assert_eq!(b"", b"\ "); -assert_eq!(b"\n", b" +assert_eq!(b"\n", b" "); } + diff --git a/src/test/ui/run-pass/issues/issue-41628.rs b/src/test/ui/run-pass/issues/issue-41628.rs index 75924274f1c..f4b9588ff05 100644 --- a/src/test/ui/run-pass/issues/issue-41628.rs +++ b/src/test/ui/run-pass/issues/issue-41628.rs @@ -10,7 +10,6 @@ // run-pass #![deny(dead_code)] -#![feature(used)] #[used] static FOO: u32 = 0; diff --git a/src/test/ui/run-pass/non_modrs_mods/non_modrs_mods.rs b/src/test/ui/run-pass/non_modrs_mods/non_modrs_mods.rs deleted file mode 100644 index a9b240be804..00000000000 --- a/src/test/ui/run-pass/non_modrs_mods/non_modrs_mods.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 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. - -// run-pass -// -// ignore-pretty issue #37195 -#![feature(non_modrs_mods)] - -pub mod modrs_mod; -pub mod foors_mod; - -#[path = "some_crazy_attr_mod_dir/arbitrary_name.rs"] -pub mod attr_mod; - -pub fn main() { - modrs_mod::inner_modrs_mod::innest::foo(); - modrs_mod::inner_foors_mod::innest::foo(); - foors_mod::inner_modrs_mod::innest::foo(); - foors_mod::inner_foors_mod::innest::foo(); - attr_mod::inner_modrs_mod::innest::foo(); -} diff --git a/src/test/ui/rust-2018/async-ident.fixed b/src/test/ui/rust-2018/async-ident.fixed index ef88f835fc8..125e7c3773a 100644 --- a/src/test/ui/rust-2018/async-ident.fixed +++ b/src/test/ui/rust-2018/async-ident.fixed @@ -26,7 +26,9 @@ macro_rules! foo { //~| WARN hard error in the 2018 edition } -foo!(async); +foo!(r#async); + //~^ ERROR async + //~| WARN hard error in the 2018 edition mod dont_lint_raw { fn r#async() {} diff --git a/src/test/ui/rust-2018/async-ident.rs b/src/test/ui/rust-2018/async-ident.rs index 069da7ffcdd..01b974bcbfb 100644 --- a/src/test/ui/rust-2018/async-ident.rs +++ b/src/test/ui/rust-2018/async-ident.rs @@ -27,6 +27,8 @@ macro_rules! foo { } foo!(async); + //~^ ERROR async + //~| WARN hard error in the 2018 edition mod dont_lint_raw { fn r#async() {} diff --git a/src/test/ui/rust-2018/async-ident.stderr b/src/test/ui/rust-2018/async-ident.stderr index b9bb2e254b4..46e6af84ab8 100644 --- a/src/test/ui/rust-2018/async-ident.stderr +++ b/src/test/ui/rust-2018/async-ident.stderr @@ -31,7 +31,16 @@ LL | ($async:expr, async) => {}; = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:36:11 + --> $DIR/async-ident.rs:29:6 + | +LL | foo!(async); + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + +error: `async` is a keyword in the 2018 edition + --> $DIR/async-ident.rs:38:11 | LL | trait async {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -40,7 +49,7 @@ LL | trait async {} = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:40:10 + --> $DIR/async-ident.rs:42:10 | LL | impl async for MyStruct {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -49,7 +58,7 @@ LL | impl async for MyStruct {} = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:46:12 + --> $DIR/async-ident.rs:48:12 | LL | static async: u32 = 0; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -58,7 +67,7 @@ LL | static async: u32 = 0; = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:52:11 + --> $DIR/async-ident.rs:54:11 | LL | const async: u32 = 0; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -67,7 +76,7 @@ LL | const async: u32 = 0; = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:58:15 + --> $DIR/async-ident.rs:60:15 | LL | impl Foo { fn async() {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -76,7 +85,7 @@ LL | impl Foo { fn async() {} } = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:63:12 + --> $DIR/async-ident.rs:65:12 | LL | struct async {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -85,7 +94,7 @@ LL | struct async {} = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:66:9 + --> $DIR/async-ident.rs:68:9 | LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -94,7 +103,7 @@ LL | let async: async = async {}; = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:66:16 + --> $DIR/async-ident.rs:68:16 | LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -103,7 +112,7 @@ LL | let async: async = async {}; = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:66:24 + --> $DIR/async-ident.rs:68:24 | LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -112,7 +121,7 @@ LL | let async: async = async {}; = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:77:19 + --> $DIR/async-ident.rs:79:19 | LL | () => (pub fn async() {}) | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -121,7 +130,7 @@ LL | () => (pub fn async() {}) = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:84:6 + --> $DIR/async-ident.rs:86:6 | LL | (async) => (1) | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -129,5 +138,5 @@ LL | (async) => (1) = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/src/test/ui/rust-2018/try-macro.fixed b/src/test/ui/rust-2018/try-macro.fixed new file mode 100644 index 00000000000..c65f0fc30ef --- /dev/null +++ b/src/test/ui/rust-2018/try-macro.fixed @@ -0,0 +1,16 @@ +// Test that `try!` macros are rewritten. + +// run-rustfix +// compile-pass + +#![warn(rust_2018_compatibility)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn foo() -> Result<usize, ()> { + let x: Result<usize, ()> = Ok(22); + r#try!(x); + Ok(44) +} + +fn main() { } diff --git a/src/test/ui/rust-2018/try-macro.rs b/src/test/ui/rust-2018/try-macro.rs new file mode 100644 index 00000000000..f435890a61d --- /dev/null +++ b/src/test/ui/rust-2018/try-macro.rs @@ -0,0 +1,16 @@ +// Test that `try!` macros are rewritten. + +// run-rustfix +// compile-pass + +#![warn(rust_2018_compatibility)] +#![allow(unused_variables)] +#![allow(dead_code)] + +fn foo() -> Result<usize, ()> { + let x: Result<usize, ()> = Ok(22); + try!(x); + Ok(44) +} + +fn main() { } diff --git a/src/test/ui/rust-2018/try-macro.stderr b/src/test/ui/rust-2018/try-macro.stderr new file mode 100644 index 00000000000..40a4564cc3d --- /dev/null +++ b/src/test/ui/rust-2018/try-macro.stderr @@ -0,0 +1,15 @@ +warning: `try` is a keyword in the 2018 edition + --> $DIR/try-macro.rs:12:5 + | +LL | try!(x); + | ^^^ help: you can use a raw identifier to stay compatible: `r#try` + | +note: lint level defined here + --> $DIR/try-macro.rs:6:9 + | +LL | #![warn(rust_2018_compatibility)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[warn(keyword_idents)] implied by #[warn(rust_2018_compatibility)] + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs new file mode 100644 index 00000000000..590e83b0781 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.rs @@ -0,0 +1,29 @@ +// 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. + +// edition:2018 + +// This test is similar to `ambiguity-macros.rs`, but nested in a module. + +mod foo { + pub use std::io; + //~^ ERROR `std` import is ambiguous + + macro_rules! m { + () => { + mod std { + pub struct io; + } + } + } + m!(); +} + +fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr new file mode 100644 index 00000000000..948043cff76 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros-nested.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity-macros-nested.rs:16:13 + | +LL | pub use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_____________- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs new file mode 100644 index 00000000000..861efba14f8 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.rs @@ -0,0 +1,27 @@ +// 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. + +// edition:2018 + +// This test is similar to `ambiguity.rs`, but with macros defining local items. + +use std::io; +//~^ ERROR `std` import is ambiguous + +macro_rules! m { + () => { + mod std { + pub struct io; + } + } +} +m!(); + +fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr new file mode 100644 index 00000000000..40cceea2440 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-macros.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity-macros.rs:15:5 + | +LL | use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_________- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs new file mode 100644 index 00000000000..a69eb101917 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.rs @@ -0,0 +1,24 @@ +// 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. + +// edition:2018 + +// This test is similar to `ambiguity.rs`, but nested in a module. + +mod foo { + pub use std::io; + //~^ ERROR `std` import is ambiguous + + mod std { + pub struct io; + } +} + +fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr new file mode 100644 index 00000000000..7538d3d2d91 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity-nested.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity-nested.rs:16:13 + | +LL | pub use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_____- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/directory_ownership/mod_file_not_owning.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs index ff93fddf9b3..500e9f6c63f 100644 --- a/src/test/ui/directory_ownership/mod_file_not_owning.rs +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.rs @@ -1,4 +1,4 @@ -// Copyright 2014 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,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: mod statements in non-mod.rs files are unstable +// edition:2018 -mod mod_file_not_owning_aux1; +use std::io; +//~^ ERROR `std` import is ambiguous + +mod std { + pub struct io; +} fn main() {} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr new file mode 100644 index 00000000000..7b64b8f0246 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/ambiguity.stderr @@ -0,0 +1,16 @@ +error: `std` import is ambiguous + --> $DIR/ambiguity.rs:13:5 + | +LL | use std::io; + | ^^^ can refer to external crate `::std` +... +LL | / mod std { +LL | | pub struct io; +LL | | } + | |_- may refer to `self::std` in the future + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to previous error + diff --git a/src/test/ui/directory_ownership/unowned_mod_with_path.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs index 0cffb7cc9e5..ca488fec516 100644 --- a/src/test/ui/directory_ownership/unowned_mod_with_path.rs +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs @@ -1,4 +1,4 @@ -// Copyright 2016 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,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: mod statements in non-mod.rs files are unstable +// edition:2018 -// This is not a directory owner since the file name is not "mod.rs". -#[path = "mod_file_not_owning_aux1.rs"] -mod foo; +struct std; + +fn main() { + fn std() {} + enum std {} + use std as foo; + //~^ ERROR `std` import is ambiguous + //~| ERROR `std` import is ambiguous +} diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr new file mode 100644 index 00000000000..27e0e883691 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr @@ -0,0 +1,31 @@ +error: `std` import is ambiguous + --> $DIR/block-scoped-shadow.rs:18:9 + | +LL | struct std; + | ----------- may refer to `self::std` in the future +... +LL | enum std {} + | ----------- shadowed by block-scoped `std` +LL | use std as foo; + | ^^^ can refer to external crate `::std` + | + = help: write `::std` or `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: `std` import is ambiguous + --> $DIR/block-scoped-shadow.rs:18:9 + | +LL | struct std; + | ----------- may refer to `self::std` in the future +... +LL | fn std() {} + | ----------- shadowed by block-scoped `std` +LL | enum std {} +LL | use std as foo; + | ^^^ + | + = help: write `self::std` explicitly instead + = note: in the future, `#![feature(uniform_paths)]` may become the default + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/redundant.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/redundant.rs new file mode 100644 index 00000000000..05048cfd451 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/redundant.rs @@ -0,0 +1,30 @@ +// 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. + +// run-pass +// edition:2018 + +use std; +use std::io; + +mod foo { + pub use std as my_std; +} + +mod bar { + pub use std::{self}; +} + +fn main() { + io::stdout(); + self::std::io::stdout(); + foo::my_std::io::stdout(); + bar::std::io::stdout(); +} diff --git a/src/test/run-pass/redundant.rs b/src/test/ui/rust-2018/uniform-paths/redundant.rs index 39bd3160695..745ac18e059 100644 --- a/src/test/run-pass/redundant.rs +++ b/src/test/ui/rust-2018/uniform-paths/redundant.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// run-pass // edition:2018 #![feature(uniform_paths)] use std; +use std::io; mod foo { pub use std as my_std; @@ -23,6 +25,7 @@ mod bar { } fn main() { + io::stdout(); self::std::io::stdout(); foo::my_std::io::stdout(); bar::std::io::stdout(); diff --git a/src/test/ui/span/issue-36530.rs b/src/test/ui/span/issue-36530.rs index c6cdb8b6db7..fbe1535caae 100644 --- a/src/test/ui/span/issue-36530.rs +++ b/src/test/ui/span/issue-36530.rs @@ -8,7 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// gate-test-custom_inner_attributes + #[foo] //~ ERROR is currently unknown to the compiler mod foo { #![foo] //~ ERROR is currently unknown to the compiler + //~| ERROR non-builtin inner attributes are unstable } diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr index e7dd8e7aa8f..78d81ad0493 100644 --- a/src/test/ui/span/issue-36530.stderr +++ b/src/test/ui/span/issue-36530.stderr @@ -1,19 +1,27 @@ error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/issue-36530.rs:11:3 + --> $DIR/issue-36530.rs:13:3 | LL | #[foo] //~ ERROR is currently unknown to the compiler | ^^^ | = help: add #![feature(custom_attribute)] to the crate attributes to enable +error[E0658]: non-builtin inner attributes are unstable (see issue #38356) + --> $DIR/issue-36530.rs:15:5 + | +LL | #![foo] //~ ERROR is currently unknown to the compiler + | ^^^^^^^ + | + = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable + error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/issue-36530.rs:13:8 + --> $DIR/issue-36530.rs:15:8 | LL | #![foo] //~ ERROR is currently unknown to the compiler | ^^^ | = help: add #![feature(custom_attribute)] to the crate attributes to enable -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/test-shadowing/test-cant-be-shadowed.rs b/src/test/ui/test-shadowing/test-cant-be-shadowed.rs index 4b1a437818f..4e24b17bdd5 100644 --- a/src/test/ui/test-shadowing/test-cant-be-shadowed.rs +++ b/src/test/ui/test-shadowing/test-cant-be-shadowed.rs @@ -16,3 +16,8 @@ #[test] fn foo(){} + +macro_rules! test { () => () } + +#[test] +fn bar() {} diff --git a/src/test/ui/try-block/try-block-bad-lifetime.stderr b/src/test/ui/try-block/try-block-bad-lifetime.stderr index 36c89faf5a2..ebf56dc9835 100644 --- a/src/test/ui/try-block/try-block-bad-lifetime.stderr +++ b/src/test/ui/try-block/try-block-bad-lifetime.stderr @@ -1,13 +1,14 @@ error[E0597]: `my_string` does not live long enough --> $DIR/try-block-bad-lifetime.rs:25:33 | +LL | let result: Result<(), &str> = try { + | ------ borrow later used here +LL | let my_string = String::from(""); LL | let my_str: & str = & my_string; | ^^^^^^^^^^^ borrowed value does not live long enough ... LL | }; | - `my_string` dropped here while still borrowed -LL | do_something_with(result); - | ------ borrow later used here error[E0506]: cannot assign to `i` because it is borrowed --> $DIR/try-block-bad-lifetime.rs:39:13 diff --git a/src/test/ui/used.rs b/src/test/ui/used.rs index f170d9c25f5..b3ed8601988 100644 --- a/src/test/ui/used.rs +++ b/src/test/ui/used.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(used)] - #[used] static FOO: u32 = 0; // OK diff --git a/src/test/ui/used.stderr b/src/test/ui/used.stderr index b8d0f42c3a3..351fb940426 100644 --- a/src/test/ui/used.stderr +++ b/src/test/ui/used.stderr @@ -1,23 +1,23 @@ error: attribute must be applied to a `static` variable - --> $DIR/used.rs:16:1 + --> $DIR/used.rs:14:1 | LL | #[used] //~ ERROR attribute must be applied to a `static` variable | ^^^^^^^ error: attribute must be applied to a `static` variable - --> $DIR/used.rs:19:1 + --> $DIR/used.rs:17:1 | LL | #[used] //~ ERROR attribute must be applied to a `static` variable | ^^^^^^^ error: attribute must be applied to a `static` variable - --> $DIR/used.rs:22:1 + --> $DIR/used.rs:20:1 | LL | #[used] //~ ERROR attribute must be applied to a `static` variable | ^^^^^^^ error: attribute must be applied to a `static` variable - --> $DIR/used.rs:25:1 + --> $DIR/used.rs:23:1 | LL | #[used] //~ ERROR attribute must be applied to a `static` variable | ^^^^^^^ diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 2fb77a49b43bf7266793c07a19a06749e6a8ad5 +Subproject b917e35248fe57d11765c5a835de33e335babb7 diff --git a/src/tools/rls b/src/tools/rls -Subproject 5b5cd9d45719414196e254ec17baa598acc8cd2 +Subproject fa922de1e5e1f02b576b7a5aa6ded16935693ec |
