Auto merge of #57752 - Centril:rollup, r=Centril

Rollup of 10 pull requests

Successful merges:

 - #57268 (Add a target option "merge-functions", and a corresponding -Z flag (works around #57356))
 - #57476 (Move glob map use to query and get rid of CrateAnalysis)
 - #57501 (High priority resolutions for associated variants)
 - #57573 (Querify `entry_fn`)
 - #57610 (Fix nested `?` matchers)
 - #57634 (Remove an unused function argument)
 - #57653 (Make the contribution doc reference the guide more)
 - #57666 (Generalize `huge-enum.rs` test and expected stderr for more cross platform cases)
 - #57698 (Fix typo bug in DepGraph::try_mark_green().)
 - #57746 (Update README.md)

Failed merges:

r? @ghost
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 65cdfe6..9924055 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,9 +19,16 @@
 
 As a reminder, all contributors are expected to follow our [Code of Conduct][coc].
 
+The [rustc-guide] is your friend! It describes how the compiler works and how
+to contribute to it in more detail than this document.
+
+If this is your first time contributing, the [walkthrough] chapter of the guide
+can give you a good example of how a typical contribution would go.
+
 [pound-rust-internals]: https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals
 [internals]: https://internals.rust-lang.org
 [coc]: https://www.rust-lang.org/conduct.html
+[walkthrough]: https://rust-lang.github.io/rustc-guide/walkthrough.html
 
 ## Feature Requests
 [feature-requests]: #feature-requests
@@ -89,222 +96,14 @@
 ```
 
 ## The Build System
-[the-build-system]: #the-build-system
 
-Rust's build system allows you to bootstrap the compiler, run tests &
-benchmarks, generate documentation, install a fresh build of Rust, and more.
-It's your best friend when working on Rust, allowing you to compile & test
-your contributions before submission.
+For info on how to configure and build the compiler, please see [this
+chapter][rustcguidebuild] of the rustc-guide. This chapter contains info for
+contributions to the compiler and the standard library. It also lists some
+really useful commands to the build system (`./x.py`), which could save you a
+lot of time.
 
-The build system lives in [the `src/bootstrap` directory][bootstrap] in the
-project root. Our build system is itself written in Rust and is based on Cargo
-to actually build all the compiler's crates. If you have questions on the build
-system internals, try asking in [`#rust-internals`][pound-rust-internals].
-
-[bootstrap]: https://github.com/rust-lang/rust/tree/master/src/bootstrap/
-
-### Configuration
-[configuration]: #configuration
-
-Before you can start building the compiler you need to configure the build for
-your system. In most cases, that will just mean using the defaults provided
-for Rust.
-
-To change configuration, you must copy the file `config.toml.example`
-to `config.toml` in the directory from which you will be running the build, and
-change the settings provided.
-
-There are large number of options provided in this config file that will alter the
-configuration used in the build process. Some options to note:
-
-#### `[llvm]`:
-- `assertions = true` = This enables LLVM assertions, which makes LLVM misuse cause an assertion failure instead of weird misbehavior. This also slows down the compiler's runtime by ~20%.
-- `ccache = true` - Use ccache when building llvm
-
-#### `[build]`:
-- `compiler-docs = true` - Build compiler documentation
-
-#### `[rust]`:
-- `debuginfo = true` - Build a compiler with debuginfo. Makes building rustc slower, but then you can use a debugger to debug `rustc`.
-- `debuginfo-lines = true` - An alternative to `debuginfo = true` that doesn't let you use a debugger, but doesn't make building rustc slower and still gives you line numbers in backtraces.
-- `debuginfo-tools = true` - Build the extended tools with debuginfo.
-- `debug-assertions = true` - Makes the log output of `debug!` work.
-- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust, but makes the stage1 compiler x100 slower.
-
-For more options, the `config.toml` file contains commented out defaults, with
-descriptions of what each option will do.
-
-Note: Previously the `./configure` script was used to configure this
-project. It can still be used, but it's recommended to use a `config.toml`
-file. If you still have a `config.mk` file in your directory - from
-`./configure` - you may need to delete it for `config.toml` to work.
-
-### Building
-[building]: #building
-
-A default configuration requires around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB.
-
-Dependencies
-- [build dependencies](README.md#building-from-source)
-- `gdb` 6.2.0 minimum, 7.1 or later recommended for test builds
-
-The build system uses the `x.py` script to control the build process. This script
-is used to build, test, and document various parts of the compiler. You can
-execute it as:
-
-```sh
-python x.py build
-```
-
-On some systems you can also use the shorter version:
-
-```sh
-./x.py build
-```
-
-To learn more about the driver and top-level targets, you can execute:
-
-```sh
-python x.py --help
-```
-
-The general format for the driver script is:
-
-```sh
-python x.py <command> [<directory>]
-```
-
-Some example commands are `build`, `test`, and `doc`. These will build, test,
-and document the specified directory. The second argument, `<directory>`, is
-optional and defaults to working over the entire compiler. If specified,
-however, only that specific directory will be built. For example:
-
-```sh
-# build the entire compiler
-python x.py build
-
-# build all documentation
-python x.py doc
-
-# run all test suites
-python x.py test
-
-# build only the standard library
-python x.py build src/libstd
-
-# test only one particular test suite
-python x.py test src/test/rustdoc
-
-# build only the stage0 libcore library
-python x.py build src/libcore --stage 0
-```
-
-You can explore the build system through the various `--help` pages for each
-subcommand. For example to learn more about a command you can run:
-
-```
-python x.py build --help
-```
-
-To learn about all possible rules you can execute, run:
-
-```
-python x.py build --help --verbose
-```
-
-Note: Previously `./configure` and `make` were used to build this project.
-They are still available, but `x.py` is the recommended build system.
-
-### Useful commands
-[useful-commands]: #useful-commands
-
-Some common invocations of `x.py` are:
-
-- `x.py build --help` - show the help message and explain the subcommand
-- `x.py build src/libtest --stage 1` - build up to (and including) the first
-  stage. For most cases we don't need to build the stage2 compiler, so we can
-  save time by not building it. The stage1 compiler is a fully functioning
-  compiler and (probably) will be enough to determine if your change works as
-  expected.
-- `x.py build src/rustc --stage 1` - This will build just rustc, without libstd.
-  This is the fastest way to recompile after you changed only rustc source code.
-  Note however that the resulting rustc binary won't have a stdlib to link
-  against by default. You can build libstd once with `x.py build src/libstd`,
-  but it is only guaranteed to work if recompiled, so if there are any issues
-  recompile it.
-- `x.py test` - build the full compiler & run all tests (takes a while). This
-  is what gets run by the continuous integration system against your pull
-  request. You should run this before submitting to make sure your tests pass
-  & everything builds in the correct manner.
-- `x.py test src/libstd --stage 1` - test the standard library without
-  recompiling stage 2.
-- `x.py test src/test/run-pass --test-args TESTNAME` - Run a matching set of
-  tests.
-  - `TESTNAME` should be a substring of the tests to match against e.g. it could
-    be the fully qualified test name, or just a part of it.
-    `TESTNAME=collections::hash::map::test_map::test_capacity_not_less_than_len`
-    or `TESTNAME=test_capacity_not_less_than_len`.
-- `x.py test src/test/run-pass --stage 1 --test-args <substring-of-test-name>` -
-  Run a single rpass test with the stage1 compiler (this will be quicker than
-  running the command above as we only build the stage1 compiler, not the entire
-  thing).  You can also leave off the directory argument to run all stage1 test
-  types.
-- `x.py test src/libcore --stage 1` - Run stage1 tests in `libcore`.
-- `x.py test src/tools/tidy` - Check that the source code is in compliance with
-  Rust's style guidelines. There is no official document describing Rust's full
-  guidelines as of yet, but basic rules like 4 spaces for indentation and no
-  more than 99 characters in a single line should be kept in mind when writing
-  code.
-
-### Using your local build
-[using-local-build]: #using-local-build
-
-If you use Rustup to manage your rust install, it has a feature called ["custom
-toolchains"][toolchain-link] that you can use to access your newly-built compiler
-without having to install it to your system or user PATH. If you've run `python
-x.py build`, then you can add your custom rustc to a new toolchain like this:
-
-[toolchain-link]: https://github.com/rust-lang-nursery/rustup.rs#working-with-custom-toolchains-and-local-builds
-
-```
-rustup toolchain link <name> build/<host-triple>/stage2
-```
-
-Where `<host-triple>` is the build triple for the host (the triple of your
-computer, by default), and `<name>` is the name for your custom toolchain. (If you
-added `--stage 1` to your build command, the compiler will be in the `stage1`
-folder instead.) You'll only need to do this once - it will automatically point
-to the latest build you've done.
-
-Once this is set up, you can use your custom toolchain just like any other. For
-example, if you've named your toolchain `local`, running `cargo +local build` will
-compile a project with your custom rustc, setting `rustup override set local` will
-override the toolchain for your current directory, and `cargo +local doc` will use
-your custom rustc and rustdoc to generate docs. (If you do this with a `--stage 1`
-build, you'll need to build rustdoc specially, since it's not normally built in
-stage 1. `python x.py build --stage 1 src/libstd src/tools/rustdoc` will build
-rustdoc and libstd, which will allow rustdoc to be run with that toolchain.)
-
-### Out-of-tree builds
-[out-of-tree-builds]: #out-of-tree-builds
-
-Rust's `x.py` script fully supports out-of-tree builds - it looks for
-the Rust source code from the directory `x.py` was found in, but it
-reads the `config.toml` configuration file from the directory it's
-run in, and places all build artifacts within a subdirectory named `build`.
-
-This means that if you want to do an out-of-tree build, you can just do it:
-```
-$ cd my/build/dir
-$ cp ~/my-config.toml config.toml # Or fill in config.toml otherwise
-$ path/to/rust/x.py build
-...
-$ # This will use the Rust source code in `path/to/rust`, but build
-$ # artifacts will now be in ./build
-```
-
-It's absolutely fine to have multiple build directories with different
-`config.toml` configurations using the same code.
+[rustcguidebuild]: https://rust-lang.github.io/rustc-guide/how-to-build-and-run.html
 
 ## Pull Requests
 [pull-requests]: #pull-requests
@@ -320,26 +119,13 @@
 
 Please make pull requests against the `master` branch.
 
-Compiling all of `./x.py test` can take a while. When testing your pull request,
-consider using one of the more specialized `./x.py` targets to cut down on the
-amount of time you have to wait. You need to have built the compiler at least
-once before running these will work, but that’s only one full build rather than
-one each time.
-
-    $ python x.py test --stage 1
-
-is one such example, which builds just `rustc`, and then runs the tests. If
-you’re adding something to the standard library, try
-
-    $ python x.py test src/libstd --stage 1
-
 Please make sure your pull request is in compliance with Rust's style
 guidelines by running
 
     $ python x.py test src/tools/tidy
 
 Make this check before every pull request (and every new commit in a pull
-request) ; you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
+request); you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
 before every push to make sure you never forget to make this check.
 
 All pull requests are reviewed by another person. We have a bot,
@@ -532,6 +318,12 @@
 reference to `doc/reference.html`. The CSS might be messed up, but you can
 verify that the HTML is right.
 
+Additionally, contributions to the [rustc-guide] are always welcome. Contributions
+can be made directly at [the
+rust-lang/rustc-guide](https://github.com/rust-lang/rustc-guide) repo. The issue
+tracker in that repo is also a great way to find things that need doing. There
+are issues for beginners and advanced compiler devs alike!
+
 ## Issue Triage
 [issue-triage]: #issue-triage
 
@@ -627,7 +419,7 @@
 more seasoned developers, some useful places to look for information
 are:
 
-* The [rustc guide] contains information about how various parts of the compiler work
+* The [rustc guide] contains information about how various parts of the compiler work and how to contribute to the compiler
 * [Rust Forge][rustforge] contains additional documentation, including write-ups of how to achieve common tasks
 * The [Rust Internals forum][rif], a place to ask questions and
   discuss Rust's internals
diff --git a/README.md b/README.md
index cb1f062..514e420 100644
--- a/README.md
+++ b/README.md
@@ -13,9 +13,13 @@
 ["Installation"]: https://doc.rust-lang.org/book/ch01-01-installation.html
 [The Book]: https://doc.rust-lang.org/book/index.html
 
-## Building from Source
+## Installing from Source
 [building-from-source]: #building-from-source
 
+_Note: If you wish to contribute to the compiler, you should read
+[this chapter](https://rust-lang.github.io/rustc-guide/how-to-build-and-run.html)
+of the rustc-guide instead._
+
 ### Building on *nix
 1. Make sure you have installed the dependencies:
 
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index d1067b7..4cfebaa 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -586,6 +586,7 @@
     [] CheckImplItemWellFormed(DefId),
     [] ReachableNonGenerics(CrateNum),
     [] NativeLibraries(CrateNum),
+    [] EntryFn(CrateNum),
     [] PluginRegistrarFn(CrateNum),
     [] ProcMacroDeclsStatic(CrateNum),
     [input] CrateDisambiguator(CrateNum),
@@ -633,6 +634,7 @@
     [input] Freevars(DefId),
     [input] MaybeUnusedTraitImport(DefId),
     [input] MaybeUnusedExternCrates,
+    [input] NamesImportedByGlobUse(DefId),
     [eval_always] StabilityIndex,
     [eval_always] AllTraits,
     [input] AllCrateNums,
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 0a0dff0..a9e80dd 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -638,7 +638,7 @@
                             DepKind::Hir |
                             DepKind::HirBody |
                             DepKind::CrateMetadata => {
-                                if dep_node.extract_def_id(tcx).is_none() {
+                                if dep_dep_node.extract_def_id(tcx).is_none() {
                                     // If the node does not exist anymore, we
                                     // just fail to mark green.
                                     return None
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index f633703..041291e 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -35,11 +35,9 @@
 use syntax_pos::Span;
 use hir::*;
 use hir::def::Def;
-use hir::map::{self, Map};
+use hir::map::Map;
 use super::itemlikevisit::DeepVisitor;
 
-use std::cmp;
-
 #[derive(Copy, Clone)]
 pub enum FnKind<'a> {
     /// `#[xxx] pub async/const/extern "Abi" fn foo()`
@@ -1133,57 +1131,3 @@
     // the right thing to do, should content be added in the future,
     // would be to walk it.
 }
-
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct IdRange {
-    pub min: NodeId,
-    pub max: NodeId,
-}
-
-impl IdRange {
-    pub fn max() -> IdRange {
-        IdRange {
-            min: NodeId::MAX,
-            max: NodeId::from_u32(0),
-        }
-    }
-
-    pub fn empty(&self) -> bool {
-        self.min >= self.max
-    }
-
-    pub fn contains(&self, id: NodeId) -> bool {
-        id >= self.min && id < self.max
-    }
-
-    pub fn add(&mut self, id: NodeId) {
-        self.min = cmp::min(self.min, id);
-        self.max = cmp::max(self.max, NodeId::from_u32(id.as_u32() + 1));
-    }
-}
-
-
-pub struct IdRangeComputingVisitor<'a, 'hir: 'a> {
-    result: IdRange,
-    map: &'a map::Map<'hir>,
-}
-
-impl<'a, 'hir> IdRangeComputingVisitor<'a, 'hir> {
-    pub fn new(map: &'a map::Map<'hir>) -> IdRangeComputingVisitor<'a, 'hir> {
-        IdRangeComputingVisitor { result: IdRange::max(), map: map }
-    }
-
-    pub fn result(&self) -> IdRange {
-        self.result
-    }
-}
-
-impl<'a, 'hir> Visitor<'hir> for IdRangeComputingVisitor<'a, 'hir> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> {
-        NestedVisitorMap::OnlyBodies(&self.map)
-    }
-
-    fn visit_id(&mut self, id: NodeId) {
-        self.result.add(id);
-    }
-}
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index c8d137a..a0bd4f0 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -368,6 +368,12 @@
     report_in_external_macro: true
 }
 
+declare_lint! {
+    pub AMBIGUOUS_ASSOCIATED_ITEMS,
+    Warn,
+    "ambiguous associated items"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// that are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -433,6 +439,7 @@
             parser::QUESTION_MARK_MACRO_SEP,
             parser::ILL_FORMED_ATTRIBUTE_INPUT,
             DEPRECATED_IN_FUTURE,
+            AMBIGUOUS_ASSOCIATED_ITEMS,
         )
     }
 }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 0c769c9..abbf0ae 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -409,7 +409,7 @@
         }
     }).chain(
         // Seed entry point
-        tcx.sess.entry_fn.borrow().map(|(id, _, _)| id)
+        tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().as_local_node_id(def_id).unwrap())
     ).collect::<Vec<_>>();
 
     // Seed implemented trait items
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 6b593a1..218ca3b 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -1,5 +1,5 @@
 use hir::map as hir_map;
-use hir::def_id::{CRATE_DEF_INDEX};
+use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
 use session::{config, Session};
 use session::config::EntryFnType;
 use syntax::ast::NodeId;
@@ -8,6 +8,8 @@
 use syntax_pos::Span;
 use hir::{Item, ItemKind, ImplItem, TraitItem};
 use hir::itemlikevisit::ItemLikeVisitor;
+use ty::TyCtxt;
+use ty::query::Providers;
 
 struct EntryContext<'a, 'tcx: 'a> {
     session: &'a Session,
@@ -45,36 +47,34 @@
     }
 }
 
-pub fn find_entry_point(session: &Session,
-                        hir_map: &hir_map::Map<'_>,
-                        crate_name: &str) {
-    let any_exe = session.crate_types.borrow().iter().any(|ty| {
+fn entry_fn(tcx: TyCtxt<'_, '_, '_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> {
+    assert_eq!(cnum, LOCAL_CRATE);
+
+    let any_exe = tcx.sess.crate_types.borrow().iter().any(|ty| {
         *ty == config::CrateType::Executable
     });
     if !any_exe {
         // No need to find a main function
-        session.entry_fn.set(None);
-        return
+        return None;
     }
 
     // If the user wants no main function at all, then stop here.
-    if attr::contains_name(&hir_map.krate().attrs, "no_main") {
-        session.entry_fn.set(None);
-        return
+    if attr::contains_name(&tcx.hir().krate().attrs, "no_main") {
+        return None;
     }
 
     let mut ctxt = EntryContext {
-        session,
-        map: hir_map,
+        session: tcx.sess,
+        map: tcx.hir(),
         main_fn: None,
         attr_main_fn: None,
         start_fn: None,
         non_main_fns: Vec::new(),
     };
 
-    hir_map.krate().visit_all_item_likes(&mut ctxt);
+    tcx.hir().krate().visit_all_item_likes(&mut ctxt);
 
-    configure_main(&mut ctxt, crate_name);
+    configure_main(tcx, &ctxt)
 }
 
 // Beware, this is duplicated in `libsyntax/entry.rs`, so make sure to keep
@@ -135,43 +135,58 @@
                     .span_label(item.span, "multiple `start` functions")
                     .emit();
             }
-        },
-        EntryPointType::None => ()
+        }
+        EntryPointType::None => (),
     }
 }
 
-fn configure_main(this: &mut EntryContext<'_, '_>, crate_name: &str) {
-    if let Some((node_id, span)) = this.start_fn {
-        this.session.entry_fn.set(Some((node_id, span, EntryFnType::Start)));
-    } else if let Some((node_id, span)) = this.attr_main_fn {
-        this.session.entry_fn.set(Some((node_id, span, EntryFnType::Main)));
-    } else if let Some((node_id, span)) = this.main_fn {
-        this.session.entry_fn.set(Some((node_id, span, EntryFnType::Main)));
+fn configure_main(
+    tcx: TyCtxt<'_, '_, '_>,
+    visitor: &EntryContext<'_, '_>,
+) -> Option<(DefId, EntryFnType)> {
+    if let Some((node_id, _)) = visitor.start_fn {
+        Some((tcx.hir().local_def_id(node_id), EntryFnType::Start))
+    } else if let Some((node_id, _)) = visitor.attr_main_fn {
+        Some((tcx.hir().local_def_id(node_id), EntryFnType::Main))
+    } else if let Some((node_id, _)) = visitor.main_fn {
+        Some((tcx.hir().local_def_id(node_id), EntryFnType::Main))
     } else {
         // No main function
-        this.session.entry_fn.set(None);
-        let mut err = struct_err!(this.session, E0601,
-            "`main` function not found in crate `{}`", crate_name);
-        if !this.non_main_fns.is_empty() {
+        let mut err = struct_err!(tcx.sess, E0601,
+            "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
+        if !visitor.non_main_fns.is_empty() {
             // There were some functions named 'main' though. Try to give the user a hint.
             err.note("the main function must be defined at the crate level \
                       but you have one or more functions named 'main' that are not \
                       defined at the crate level. Either move the definition or \
                       attach the `#[main]` attribute to override this behavior.");
-            for &(_, span) in &this.non_main_fns {
+            for &(_, span) in &visitor.non_main_fns {
                 err.span_note(span, "here is a function named 'main'");
             }
             err.emit();
-            this.session.abort_if_errors();
+            tcx.sess.abort_if_errors();
         } else {
-            if let Some(ref filename) = this.session.local_crate_source_file {
+            if let Some(ref filename) = tcx.sess.local_crate_source_file {
                 err.note(&format!("consider adding a `main` function to `{}`", filename.display()));
             }
-            if this.session.teach(&err.get_code().unwrap()) {
+            if tcx.sess.teach(&err.get_code().unwrap()) {
                 err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
                           to get started: https://doc.rust-lang.org/book/");
             }
             err.emit();
         }
+
+        None
     }
 }
+
+pub fn find_entry_point(tcx: TyCtxt<'_, '_, '_>) -> Option<(DefId, EntryFnType)> {
+    tcx.entry_fn(LOCAL_CRATE)
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        entry_fn,
+        ..*providers
+    };
+}
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 42adc6a..0f14049 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -6,7 +6,7 @@
 use session::{early_error, early_warn, Session};
 use session::search_paths::SearchPath;
 
-use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
+use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
 use rustc_target::spec::{Target, TargetTriple};
 use lint;
 use middle::cstore;
@@ -649,15 +649,15 @@
     }
 }
 
-// The type of entry function, so
-// users can have their own entry
-// functions
-#[derive(Copy, Clone, PartialEq)]
+// The type of entry function, so users can have their own entry functions
+#[derive(Copy, Clone, PartialEq, Hash, Debug)]
 pub enum EntryFnType {
     Main,
     Start,
 }
 
+impl_stable_hash_via_hash!(EntryFnType);
+
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
 pub enum CrateType {
     Executable,
@@ -808,13 +808,16 @@
         pub const parse_cross_lang_lto: Option<&str> =
             Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
                   or the path to the linker plugin");
+        pub const parse_merge_functions: Option<&str> =
+            Some("one of: `disabled`, `trampolines`, or `aliases`");
     }
 
     #[allow(dead_code)]
     mod $mod_set {
         use super::{$struct_name, Passes, Sanitizer, LtoCli, CrossLangLto};
-        use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
+        use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
         use std::path::PathBuf;
+        use std::str::FromStr;
 
         $(
             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
@@ -1046,6 +1049,14 @@
             };
             true
         }
+
+        fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
+            match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
+                Some(mergefunc) => *slot = Some(mergefunc),
+                _ => return false,
+            }
+            true
+        }
     }
 ) }
 
@@ -1376,6 +1387,9 @@
           "whether to use the PLT when calling into shared libraries;
           only has effect for PIC code on systems with ELF binaries
           (default: PLT is disabled if full relro is enabled)"),
+    merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
+        "control the operation of the MergeFunctions LLVM pass, taking
+         the same values as the target option of the same name"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -2394,7 +2408,7 @@
     use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
                 Passes, Sanitizer, LtoCli, CrossLangLto};
     use syntax::feature_gate::UnstableFeatures;
-    use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
+    use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
     use syntax::edition::Edition;
 
     pub trait DepTrackingHash {
@@ -2437,12 +2451,14 @@
     impl_dep_tracking_hash_via_hash!(Option<usize>);
     impl_dep_tracking_hash_via_hash!(Option<String>);
     impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
+    impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
     impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
     impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
     impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
     impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
     impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
     impl_dep_tracking_hash_via_hash!(CrateType);
+    impl_dep_tracking_hash_via_hash!(MergeFunctions);
     impl_dep_tracking_hash_via_hash!(PanicStrategy);
     impl_dep_tracking_hash_via_hash!(RelroLevel);
     impl_dep_tracking_hash_via_hash!(Passes);
@@ -2528,7 +2544,7 @@
     use std::iter::FromIterator;
     use std::path::PathBuf;
     use super::{Externs, OutputType, OutputTypes};
-    use rustc_target::spec::{PanicStrategy, RelroLevel};
+    use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
     use syntax::symbol::Symbol;
     use syntax::edition::{Edition, DEFAULT_EDITION};
     use syntax;
@@ -3183,6 +3199,10 @@
         opts = reference.clone();
         opts.debugging_opts.cross_lang_lto = CrossLangLto::LinkerPluginAuto;
         assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+        opts = reference.clone();
+        opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
+        assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
     }
 
     #[test]
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 7363b8b..cf00bf3 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -67,8 +67,6 @@
     /// This is `None` if the host and target are the same.
     pub target_tlib_path: Option<SearchPath>,
     pub parse_sess: ParseSess,
-    /// For a library crate, this is always none
-    pub entry_fn: Once<Option<(NodeId, Span, config::EntryFnType)>>,
     pub sysroot: PathBuf,
     /// The name of the root source file of the crate, in the local file system.
     /// `None` means that there is no source file.
@@ -1173,8 +1171,6 @@
         host_tlib_path,
         target_tlib_path,
         parse_sess: p_s,
-        // For a library crate, this is always none
-        entry_fn: Once::new(),
         sysroot,
         local_crate_source_file,
         working_dir,
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index d69219e..e37eab6 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -983,6 +983,9 @@
 
     maybe_unused_trait_imports: FxHashSet<DefId>,
     maybe_unused_extern_crates: Vec<(DefId, Span)>,
+    /// A map of glob use to a set of names it actually imports. Currently only
+    /// used in save-analysis.
+    glob_map: FxHashMap<DefId, FxHashSet<ast::Name>>,
     /// Extern prelude entries. The value is `true` if the entry was introduced
     /// via `extern crate` item and not `--extern` option or compiler built-in.
     pub extern_prelude: FxHashMap<ast::Name, bool>,
@@ -1232,6 +1235,9 @@
                     .into_iter()
                     .map(|(id, sp)| (hir.local_def_id(id), sp))
                     .collect(),
+            glob_map: resolutions.glob_map.into_iter().map(|(id, names)| {
+                (hir.local_def_id(id), names)
+            }).collect(),
             extern_prelude: resolutions.extern_prelude,
             hir_map: hir,
             def_path_hash_to_def_id,
@@ -2972,6 +2978,10 @@
         assert_eq!(cnum, LOCAL_CRATE);
         Lrc::new(tcx.maybe_unused_extern_crates.clone())
     };
+    providers.names_imported_by_glob_use = |tcx, id| {
+        assert_eq!(id.krate, LOCAL_CRATE);
+        Lrc::new(tcx.glob_map.get(&id).cloned().unwrap_or_default())
+    };
 
     providers.stability_index = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 26b4735..f1b36e8 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -4,7 +4,7 @@
 pub use self::IntVarValue::*;
 pub use self::fold::TypeFoldable;
 
-use hir::{map as hir_map, FreevarMap, TraitMap};
+use hir::{map as hir_map, FreevarMap, GlobMap, TraitMap};
 use hir::Node;
 use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -115,16 +115,6 @@
 
 // Data types
 
-/// The complete set of all analyses described in this module. This is
-/// produced by the driver and fed to codegen and later passes.
-///
-/// N.B., these contents are being migrated into queries using the
-/// *on-demand* infrastructure.
-#[derive(Clone)]
-pub struct CrateAnalysis {
-    pub glob_map: hir::GlobMap,
-}
-
 #[derive(Clone)]
 pub struct Resolutions {
     pub freevars: FreevarMap,
@@ -132,6 +122,7 @@
     pub maybe_unused_trait_imports: NodeSet,
     pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
     pub export_map: ExportMap,
+    pub glob_map: GlobMap,
     /// Extern prelude entries. The value is `true` if the entry was introduced
     /// via `extern crate` item and not `--extern` option or compiler built-in.
     pub extern_prelude: FxHashMap<Name, bool>,
diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs
index c20846a..ae41ca0 100644
--- a/src/librustc/ty/query/config.rs
+++ b/src/librustc/ty/query/config.rs
@@ -656,6 +656,12 @@
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::entry_fn<'tcx> {
+    fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
+        "looking up the entry function of a crate".into()
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::plugin_registrar_fn<'tcx> {
     fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "looking up the plugin registrar for a crate".into()
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 88c2054..10f3571 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -22,7 +22,7 @@
 use mir;
 use mir::interpret::GlobalId;
 use session::{CompileResult, CrateDisambiguator};
-use session::config::OutputFilenames;
+use session::config::{EntryFnType, OutputFilenames};
 use traits::{self, Vtable};
 use traits::query::{
     CanonicalPredicateGoal, CanonicalProjectionGoal,
@@ -482,6 +482,9 @@
 
         [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc<Vec<ForeignModule>>,
 
+        /// Identifies the entry-point (e.g. the `main` function) for a given
+        /// crate, returning `None` if there is no entry point (such as for library crates).
+        [] fn entry_fn: EntryFn(CrateNum) -> Option<(DefId, EntryFnType)>,
         [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,
         [] fn proc_macro_decls_static: ProcMacroDeclsStatic(CrateNum) -> Option<DefId>,
         [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator,
@@ -547,6 +550,8 @@
         [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool,
         [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum)
             -> Lrc<Vec<(DefId, Span)>>,
+        [] fn names_imported_by_glob_use: NamesImportedByGlobUse(DefId)
+            -> Lrc<FxHashSet<ast::Name>>,
 
         [] fn stability_index: stability_index_node(CrateNum) -> Lrc<stability::Index<'tcx>>,
         [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>,
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 5b7cb55..1cc9bbd 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1332,6 +1332,7 @@
         DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); }
         DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); }
         DepKind::NativeLibraries => { force!(native_libraries, krate!()); }
+        DepKind::EntryFn => { force!(entry_fn, krate!()); }
         DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); }
         DepKind::ProcMacroDeclsStatic => { force!(proc_macro_decls_static, krate!()); }
         DepKind::CrateDisambiguator => { force!(crate_disambiguator, krate!()); }
@@ -1383,6 +1384,7 @@
         DepKind::MaybeUnusedTraitImport => {
             force!(maybe_unused_trait_import, def_id!());
         }
+        DepKind::NamesImportedByGlobUse => { force!(names_imported_by_glob_use, def_id!()); }
         DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); }
         DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); }
         DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); }
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 66303ab..72963cb 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -39,7 +39,6 @@
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 
 use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor};
 
 use dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
 
@@ -157,12 +156,6 @@
     where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG
 {
     // Check the body of fn items.
-    let tcx = this.tcx;
-    let id_range = {
-        let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.hir());
-        visitor.visit_body(this.body);
-        visitor.result()
-    };
     let (all_loans, move_data) =
         gather_loans::gather_loans_in_fn(this, body_id);
 
@@ -184,7 +177,6 @@
                              Some(this.body),
                              cfg,
                              LoanDataFlowOperator,
-                             id_range,
                              all_loans.len());
     for (loan_idx, loan) in all_loans.iter().enumerate() {
         loan_dfcx.add_gen(loan.gen_scope.item_local_id(), loan_idx);
@@ -198,7 +190,6 @@
     let flowed_moves = move_data::FlowedMoveData::new(move_data,
                                                       this,
                                                       cfg,
-                                                      id_range,
                                                       this.body);
 
     Some(AnalysisData { all_loans,
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index c5bee87..56c9f92 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -15,7 +15,6 @@
 use std::usize;
 use syntax_pos::Span;
 use rustc::hir;
-use rustc::hir::intravisit::IdRange;
 
 #[derive(Default)]
 pub struct MoveData<'tcx> {
@@ -559,7 +558,6 @@
     pub fn new(move_data: MoveData<'tcx>,
                bccx: &BorrowckCtxt<'a, 'tcx>,
                cfg: &cfg::CFG,
-               id_range: IdRange,
                body: &hir::Body)
                -> FlowedMoveData<'a, 'tcx> {
         let tcx = bccx.tcx;
@@ -570,7 +568,6 @@
                                  Some(body),
                                  cfg,
                                  MoveDataFlowOperator,
-                                 id_range,
                                  move_data.moves.borrow().len());
         let mut dfcx_assign =
             DataFlowContext::new(tcx,
@@ -578,7 +575,6 @@
                                  Some(body),
                                  cfg,
                                  AssignDataFlowOperator,
-                                 id_range,
                                  move_data.var_assignments.borrow().len());
 
         move_data.add_gen_kills(bccx,
diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs
index 56e25bd..8cf6205 100644
--- a/src/librustc_borrowck/dataflow.rs
+++ b/src/librustc_borrowck/dataflow.rs
@@ -15,7 +15,7 @@
 
 use rustc::util::nodemap::FxHashMap;
 use rustc::hir;
-use rustc::hir::intravisit::{self, IdRange};
+use rustc::hir::intravisit;
 use rustc::hir::print as pprust;
 
 
@@ -230,16 +230,15 @@
                body: Option<&hir::Body>,
                cfg: &cfg::CFG,
                oper: O,
-               id_range: IdRange,
                bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> {
         let usize_bits = mem::size_of::<usize>() * 8;
         let words_per_id = (bits_per_id + usize_bits - 1) / usize_bits;
         let num_nodes = cfg.graph.all_nodes().len();
 
-        debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
+        debug!("DataFlowContext::new(analysis_name: {}, \
                                      bits_per_id={}, words_per_id={}) \
                                      num_nodes: {}",
-               analysis_name, id_range, bits_per_id, words_per_id,
+               analysis_name, bits_per_id, words_per_id,
                num_nodes);
 
         let entry = if oper.initial_value() { usize::MAX } else {0};
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index 2eab626..b504aa5 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -14,7 +14,7 @@
 use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags,
     DILexicalBlock};
 use rustc::hir::CodegenFnAttrFlags;
-use rustc::hir::def_id::{DefId, CrateNum};
+use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
 use rustc::ty::subst::{Substs, UnpackedKind};
 
 use abi::Abi;
@@ -290,9 +290,8 @@
 
         let mut flags = DIFlags::FlagPrototyped;
 
-        let local_id = self.tcx().hir().as_local_node_id(def_id);
-        if let Some((id, _, _)) = *self.sess().entry_fn.borrow() {
-            if local_id == Some(id) {
+        if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
+            if id == def_id {
                 flags |= DIFlags::FlagMainSubprogram;
             }
         }
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index ad9ebbc..dc70ebc 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -3,6 +3,7 @@
 use llvm;
 use rustc::session::Session;
 use rustc::session::config::PrintRequest;
+use rustc_target::spec::MergeFunctions;
 use libc::c_int;
 use std::ffi::CString;
 use syntax::feature_gate::UnstableFeatures;
@@ -61,7 +62,14 @@
             add("-disable-preinline");
         }
         if llvm::LLVMRustIsRustLLVM() {
-            add("-mergefunc-use-aliases");
+            match sess.opts.debugging_opts.merge_functions
+                  .unwrap_or(sess.target.target.options.merge_functions) {
+                MergeFunctions::Disabled |
+                MergeFunctions::Trampolines => {}
+                MergeFunctions::Aliases => {
+                    add("-mergefunc-use-aliases");
+                }
+            }
         }
 
         // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index bf69089..c372892 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -194,7 +194,7 @@
                                  })
                                  .collect();
 
-    if tcx.sess.entry_fn.borrow().is_some() {
+    if tcx.entry_fn(LOCAL_CRATE).is_some() {
         let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("main"));
 
         symbols.push((exported_symbol, SymbolExportLevel::C));
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index fb3e7ea..39bdc70 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -24,6 +24,7 @@
 use rustc_data_structures::svh::Svh;
 use rustc_errors::{Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
 use rustc_errors::emitter::{Emitter};
+use rustc_target::spec::MergeFunctions;
 use syntax::attr;
 use syntax::ext::hygiene::Mark;
 use syntax_pos::MultiSpan;
@@ -152,8 +153,24 @@
                             sess.opts.optimize == config::OptLevel::Aggressive &&
                             !sess.target.target.options.is_like_emscripten;
 
-        self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
-                               sess.opts.optimize == config::OptLevel::Aggressive;
+        // Some targets (namely, NVPTX) interact badly with the MergeFunctions
+        // pass. This is because MergeFunctions can generate new function calls
+        // which may interfere with the target calling convention; e.g. for the
+        // NVPTX target, PTX kernels should not call other PTX kernels.
+        // MergeFunctions can also be configured to generate aliases instead,
+        // but aliases are not supported by some backends (again, NVPTX).
+        // Therefore, allow targets to opt out of the MergeFunctions pass,
+        // but otherwise keep the pass enabled (at O2 and O3) since it can be
+        // useful for reducing code size.
+        self.merge_functions = match sess.opts.debugging_opts.merge_functions
+                                     .unwrap_or(sess.target.target.options.merge_functions) {
+            MergeFunctions::Disabled => false,
+            MergeFunctions::Trampolines |
+            MergeFunctions::Aliases => {
+                sess.opts.optimize == config::OptLevel::Default ||
+                sess.opts.optimize == config::OptLevel::Aggressive
+            }
+        };
     }
 
     pub fn bitcode_needed(&self) -> bool {
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index b88ec07..38caacb 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -441,10 +441,8 @@
 pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx
 ) {
-    let (main_def_id, span) = match *cx.sess().entry_fn.borrow() {
-        Some((id, span, _)) => {
-            (cx.tcx().hir().local_def_id(id), span)
-        }
+    let (main_def_id, span) = match cx.tcx().entry_fn(LOCAL_CRATE) {
+        Some((def_id, _)) => { (def_id, cx.tcx().def_span(def_id)) },
         None => return,
     };
 
@@ -458,7 +456,7 @@
 
     let main_llfn = cx.get_fn(instance);
 
-    let et = cx.sess().entry_fn.get().map(|e| e.2);
+    let et = cx.tcx().entry_fn(LOCAL_CRATE).map(|e| e.1);
     match et {
         Some(EntryFnType::Main) => create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, true),
         Some(EntryFnType::Start) => create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, false),
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index b59bca0..5f61852 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -31,6 +31,7 @@
 #[macro_use] extern crate rustc_data_structures;
 
 use rustc::ty::TyCtxt;
+use rustc::hir::def_id::LOCAL_CRATE;
 
 pub mod link;
 pub mod codegen_backend;
@@ -42,11 +43,9 @@
 /// that actually test that compilation succeeds without
 /// reporting an error.
 pub fn check_for_rustc_errors_attr(tcx: TyCtxt) {
-    if let Some((id, span, _)) = *tcx.sess.entry_fn.borrow() {
-        let main_def_id = tcx.hir().local_def_id(id);
-
-        if tcx.has_attr(main_def_id, "rustc_error") {
-            tcx.sess.span_fatal(span, "compilation successful");
+    if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
+        if tcx.has_attr(def_id, "rustc_error") {
+            tcx.sess.span_fatal(tcx.def_span(def_id), "compilation successful");
         }
     }
 }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 15cb5b0..d23d8b8 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -168,7 +168,6 @@
         let ExpansionResult {
             expanded_crate,
             defs,
-            analysis,
             resolutions,
             mut hir_forest,
         } = {
@@ -251,7 +250,6 @@
                     output,
                     &cstore,
                     &hir_map,
-                    &analysis,
                     &resolutions,
                     &expanded_crate,
                     &hir_map.krate(),
@@ -277,12 +275,11 @@
             sess,
             cstore,
             hir_map,
-            analysis,
             resolutions,
             &mut arenas,
             &crate_name,
             &outputs,
-            |tcx, analysis, rx, result| {
+            |tcx, rx, result| {
                 {
                     // Eventually, we will want to track plugins.
                     tcx.dep_graph.with_ignore(|| {
@@ -293,7 +290,6 @@
                             output,
                             opt_crate,
                             tcx.hir().krate(),
-                            &analysis,
                             tcx,
                             &crate_name,
                         );
@@ -527,7 +523,6 @@
     pub hir_crate: Option<&'a hir::Crate>,
     pub hir_map: Option<&'a hir_map::Map<'tcx>>,
     pub resolutions: Option<&'a Resolutions>,
-    pub analysis: Option<&'a ty::CrateAnalysis>,
     pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
 }
 
@@ -547,7 +542,6 @@
             hir_crate: None,
             hir_map: None,
             resolutions: None,
-            analysis: None,
             tcx: None,
         }
     }
@@ -595,7 +589,6 @@
         out_file: &'a Option<PathBuf>,
         cstore: &'tcx CStore,
         hir_map: &'a hir_map::Map<'tcx>,
-        analysis: &'a ty::CrateAnalysis,
         resolutions: &'a Resolutions,
         krate: &'a ast::Crate,
         hir_crate: &'a hir::Crate,
@@ -606,7 +599,6 @@
             crate_name: Some(crate_name),
             cstore: Some(cstore),
             hir_map: Some(hir_map),
-            analysis: Some(analysis),
             resolutions: Some(resolutions),
             expanded_crate: Some(krate),
             hir_crate: Some(hir_crate),
@@ -623,12 +615,10 @@
         out_file: &'a Option<PathBuf>,
         krate: Option<&'a ast::Crate>,
         hir_crate: &'a hir::Crate,
-        analysis: &'a ty::CrateAnalysis,
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         crate_name: &'a str,
     ) -> Self {
         CompileState {
-            analysis: Some(analysis),
             tcx: Some(tcx),
             expanded_crate: krate,
             hir_crate: Some(hir_crate),
@@ -711,7 +701,6 @@
 pub struct ExpansionResult {
     pub expanded_crate: ast::Crate,
     pub defs: hir_map::Definitions,
-    pub analysis: ty::CrateAnalysis,
     pub resolutions: Resolutions,
     pub hir_forest: hir_map::Forest,
 }
@@ -772,16 +761,13 @@
                 freevars: resolver.freevars,
                 export_map: resolver.export_map,
                 trait_map: resolver.trait_map,
+                glob_map: resolver.glob_map,
                 maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
                 maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
                 extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
                     (ident.name, entry.introduced_by_item)
                 }).collect(),
             },
-
-            analysis: ty::CrateAnalysis {
-                glob_map: resolver.glob_map
-            },
         }),
         Err(x) => Err(x),
     }
@@ -1165,6 +1151,7 @@
     rustc_passes::provide(providers);
     rustc_traits::provide(providers);
     middle::region::provide(providers);
+    middle::entry::provide(providers);
     cstore::provide(providers);
     lint::provide(providers);
 }
@@ -1182,7 +1169,6 @@
     sess: &'tcx Session,
     cstore: &'tcx CStore,
     hir_map: hir_map::Map<'tcx>,
-    analysis: ty::CrateAnalysis,
     resolutions: Resolutions,
     arenas: &'tcx mut AllArenas<'tcx>,
     name: &str,
@@ -1192,7 +1178,6 @@
 where
     F: for<'a> FnOnce(
         TyCtxt<'a, 'tcx, 'tcx>,
-        ty::CrateAnalysis,
         mpsc::Receiver<Box<dyn Any + Send>>,
         CompileResult,
     ) -> R,
@@ -1201,10 +1186,6 @@
         rustc_incremental::load_query_result_cache(sess)
     });
 
-    time(sess, "looking for entry point", || {
-        middle::entry::find_entry_point(sess, &hir_map, name)
-    });
-
     let mut local_providers = ty::query::Providers::default();
     default_provide(&mut local_providers);
     codegen_backend.provide(&mut local_providers);
@@ -1234,6 +1215,10 @@
             // tcx available.
             time(sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
 
+            time(sess, "looking for entry point", || {
+                middle::entry::find_entry_point(tcx)
+            });
+
             time(sess, "looking for plugin registrar", || {
                 plugin::build::find_plugin_registrar(tcx)
             });
@@ -1256,7 +1241,7 @@
             match typeck::check_crate(tcx) {
                 Ok(x) => x,
                 Err(x) => {
-                    f(tcx, analysis, rx, Err(x));
+                    f(tcx, rx, Err(x));
                     return Err(x);
                 }
             }
@@ -1309,7 +1294,7 @@
             // lint warnings and so on -- kindck used to do this abort, but
             // kindck is gone now). -nmatsakis
             if sess.err_count() > 0 {
-                return Ok(f(tcx, analysis, rx, sess.compile_status()));
+                return Ok(f(tcx, rx, sess.compile_status()));
             }
 
             time(sess, "death checking", || middle::dead::check_crate(tcx));
@@ -1320,7 +1305,7 @@
 
             time(sess, "lint checking", || lint::check_crate(tcx));
 
-            return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
+            return Ok(f(tcx, rx, tcx.sess.compile_status()));
         },
     )
 }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 010ac28..c8a5bbe 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -879,7 +879,6 @@
                     pretty::print_after_hir_lowering(state.session,
                                                      state.cstore.unwrap(),
                                                      state.hir_map.unwrap(),
-                                                     state.analysis.unwrap(),
                                                      state.resolutions.unwrap(),
                                                      state.input,
                                                      &state.expanded_crate.take().unwrap(),
@@ -940,7 +939,6 @@
         time(state.session, "save analysis", || {
             save::process_crate(state.tcx.unwrap(),
                                 state.expanded_crate.unwrap(),
-                                state.analysis.unwrap(),
                                 state.crate_name.unwrap(),
                                 state.input,
                                 None,
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index a9ec993..d110830 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -190,7 +190,6 @@
         sess: &'tcx Session,
         cstore: &'tcx CStore,
         hir_map: &hir_map::Map<'tcx>,
-        analysis: &ty::CrateAnalysis,
         resolutions: &Resolutions,
         output_filenames: &OutputFilenames,
         id: &str,
@@ -223,12 +222,11 @@
                                                                  sess,
                                                                  cstore,
                                                                  hir_map.clone(),
-                                                                 analysis.clone(),
                                                                  resolutions.clone(),
                                                                  &mut arenas,
                                                                  id,
                                                                  output_filenames,
-                                                                 |tcx, _, _, _| {
+                                                                 |tcx, _, _| {
                     let empty_tables = ty::TypeckTables::empty(None);
                     let annotation = TypedAnnotation {
                         tcx,
@@ -959,7 +957,6 @@
 pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                 cstore: &'tcx CStore,
                                                 hir_map: &hir_map::Map<'tcx>,
-                                                analysis: &ty::CrateAnalysis,
                                                 resolutions: &Resolutions,
                                                 input: &Input,
                                                 krate: &ast::Crate,
@@ -972,7 +969,6 @@
         print_with_analysis(sess,
                             cstore,
                             hir_map,
-                            analysis,
                             resolutions,
                             crate_name,
                             output_filenames,
@@ -1010,7 +1006,6 @@
                 s.call_with_pp_support_hir(sess,
                                            cstore,
                                            hir_map,
-                                           analysis,
                                            resolutions,
                                            output_filenames,
                                            crate_name,
@@ -1033,7 +1028,6 @@
                 s.call_with_pp_support_hir(sess,
                                            cstore,
                                            hir_map,
-                                           analysis,
                                            resolutions,
                                            output_filenames,
                                            crate_name,
@@ -1048,7 +1042,6 @@
                 s.call_with_pp_support_hir(sess,
                                            cstore,
                                            hir_map,
-                                           analysis,
                                            resolutions,
                                            output_filenames,
                                            crate_name,
@@ -1081,7 +1074,6 @@
                 s.call_with_pp_support_hir(sess,
                                            cstore,
                                            hir_map,
-                                           analysis,
                                            resolutions,
                                            output_filenames,
                                            crate_name,
@@ -1103,13 +1095,12 @@
 }
 
 // In an ideal world, this would be a public function called by the driver after
-// analsysis is performed. However, we want to call `phase_3_run_analysis_passes`
+// analysis is performed. However, we want to call `phase_3_run_analysis_passes`
 // with a different callback than the standard driver, so that isn't easy.
 // Instead, we call that function ourselves.
 fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                        cstore: &'a CStore,
                                        hir_map: &hir_map::Map<'tcx>,
-                                       analysis: &ty::CrateAnalysis,
                                        resolutions: &Resolutions,
                                        crate_name: &str,
                                        output_filenames: &OutputFilenames,
@@ -1134,12 +1125,11 @@
                                                      sess,
                                                      cstore,
                                                      hir_map.clone(),
-                                                     analysis.clone(),
                                                      resolutions.clone(),
                                                      &mut arenas,
                                                      crate_name,
                                                      output_filenames,
-                                                     |tcx, _, _, _| {
+                                                     |tcx, _, _| {
         match ppm {
             PpmMir | PpmMirCFG => {
                 if let Some(nodeid) = nodeid {
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 2d764d1..71c859d 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -341,6 +341,11 @@
             reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
             edition: None,
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(AMBIGUOUS_ASSOCIATED_ITEMS),
+            reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>",
+            edition: None,
+        },
         ]);
 
     // Register renamed and removed lints.
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index a6a8fe5..eb49547 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -177,13 +177,13 @@
 use rustc::hir::{self, CodegenFnAttrFlags};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::mir::interpret::{AllocId, ConstValue};
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
 use rustc::ty::adjustment::CustomCoerceUnsized;
-use rustc::session::config;
+use rustc::session::config::EntryFnType;
 use rustc::mir::{self, Location, Promoted};
 use rustc::mir::visit::Visitor as MirVisitor;
 use rustc::mir::mono::MonoItem;
@@ -321,9 +321,7 @@
     let mut roots = Vec::new();
 
     {
-        let entry_fn = tcx.sess.entry_fn.borrow().map(|(node_id, _, _)| {
-            tcx.hir().local_def_id(node_id)
-        });
+        let entry_fn = tcx.entry_fn(LOCAL_CRATE);
 
         debug!("collect_roots: entry_fn = {:?}", entry_fn);
 
@@ -924,7 +922,7 @@
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     mode: MonoItemCollectionMode,
     output: &'b mut Vec<MonoItem<'tcx>>,
-    entry_fn: Option<DefId>,
+    entry_fn: Option<(DefId, EntryFnType)>,
 }
 
 impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
@@ -1023,7 +1021,7 @@
                 true
             }
             MonoItemCollectionMode::Lazy => {
-                self.entry_fn == Some(def_id) ||
+                self.entry_fn.map(|(id, _)| id) == Some(def_id) ||
                 self.tcx.is_reachable_non_generic(def_id) ||
                 self.tcx.codegen_fn_attrs(def_id).flags.contains(
                     CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
@@ -1048,14 +1046,9 @@
     /// the return type of `main`. This is not needed when
     /// the user writes their own `start` manually.
     fn push_extra_entry_roots(&mut self) {
-        if self.tcx.sess.entry_fn.get().map(|e| e.2) != Some(config::EntryFnType::Main) {
-            return
-        }
-
-        let main_def_id = if let Some(def_id) = self.entry_fn {
-            def_id
-        } else {
-            return
+        let main_def_id = match self.entry_fn {
+            Some((def_id, EntryFnType::Main)) => def_id,
+            _ => return,
         };
 
         let start_def_id = match self.tcx.lang_items().require(StartFnLangItem) {
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index 7014f53..c831cbd 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -1,6 +1,6 @@
 use monomorphize::Instance;
 use rustc::hir;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::session::config::OptLevel;
 use rustc::ty::{self, Ty, TyCtxt, ClosureSubsts, GeneratorSubsts};
 use rustc::ty::subst::Substs;
@@ -75,8 +75,7 @@
 
         match *self.as_mono_item() {
             MonoItem::Fn(ref instance) => {
-                let entry_def_id =
-                    tcx.sess.entry_fn.borrow().map(|(id, _, _)| tcx.hir().local_def_id(id));
+                let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
                 // If this function isn't inlined or otherwise has explicit
                 // linkage, then we'll be creating a globally shared version.
                 if self.explicit_linkage(tcx).is_some() ||
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 05156fb..995df38 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1238,12 +1238,9 @@
                 };
 
                 // Make a comma-separated list of names of imported modules.
-                let glob_map = &self.save_ctxt.analysis.glob_map;
-                let names = if glob_map.contains_key(&id) {
-                    glob_map.get(&id).unwrap().iter().map(|n| n.to_string()).collect()
-                } else {
-                    Vec::new()
-                };
+                let def_id = self.tcx.hir().local_def_id(id);
+                let names = self.tcx.names_imported_by_glob_use(def_id);
+                let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
 
                 // Otherwise it's a span with wrong macro expansion info, which
                 // we don't want to track anyway, since it's probably macro-internal `use`
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 4d55004..73eb5de 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -71,7 +71,6 @@
     tcx: TyCtxt<'l, 'tcx, 'tcx>,
     tables: &'l ty::TypeckTables<'tcx>,
     access_levels: &'l AccessLevels,
-    analysis: &'l ty::CrateAnalysis,
     span_utils: SpanUtils<'tcx>,
     config: Config,
     impl_counter: Cell<u32>,
@@ -1120,7 +1119,6 @@
 pub fn process_crate<'l, 'tcx, H: SaveHandler>(
     tcx: TyCtxt<'l, 'tcx, 'tcx>,
     krate: &ast::Crate,
-    analysis: &'l ty::CrateAnalysis,
     cratename: &str,
     input: &'l Input,
     config: Option<Config>,
@@ -1139,7 +1137,6 @@
         let save_ctxt = SaveContext {
             tcx,
             tables: &ty::TypeckTables::empty(None),
-            analysis,
             access_levels: &access_levels,
             span_utils: SpanUtils::new(&tcx.sess),
             config: find_config(config),
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index f42b0a1..3a21ca1 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -217,6 +217,46 @@
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+pub enum MergeFunctions {
+    Disabled,
+    Trampolines,
+    Aliases
+}
+
+impl MergeFunctions {
+    pub fn desc(&self) -> &str {
+        match *self {
+            MergeFunctions::Disabled => "disabled",
+            MergeFunctions::Trampolines => "trampolines",
+            MergeFunctions::Aliases => "aliases",
+        }
+    }
+}
+
+impl FromStr for MergeFunctions {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<MergeFunctions, ()> {
+        match s {
+            "disabled" => Ok(MergeFunctions::Disabled),
+            "trampolines" => Ok(MergeFunctions::Trampolines),
+            "aliases" => Ok(MergeFunctions::Aliases),
+            _ => Err(()),
+        }
+    }
+}
+
+impl ToJson for MergeFunctions {
+    fn to_json(&self) -> Json {
+        match *self {
+            MergeFunctions::Disabled => "disabled".to_json(),
+            MergeFunctions::Trampolines => "trampolines".to_json(),
+            MergeFunctions::Aliases => "aliases".to_json(),
+        }
+    }
+}
+
 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
 pub type TargetResult = Result<Target, String>;
 
@@ -690,7 +730,15 @@
 
     /// If set, have the linker export exactly these symbols, instead of using
     /// the usual logic to figure this out from the crate itself.
-    pub override_export_symbols: Option<Vec<String>>
+    pub override_export_symbols: Option<Vec<String>>,
+
+    /// Determines how or whether the MergeFunctions LLVM pass should run for
+    /// this target. Either "disabled", "trampolines", or "aliases".
+    /// The MergeFunctions pass is generally useful, but some targets may need
+    /// to opt out. The default is "aliases".
+    ///
+    /// Workaround for: https://github.com/rust-lang/rust/issues/57356
+    pub merge_functions: MergeFunctions
 }
 
 impl Default for TargetOptions {
@@ -773,6 +821,7 @@
             requires_uwtable: false,
             simd_types_indirect: true,
             override_export_symbols: None,
+            merge_functions: MergeFunctions::Aliases,
         }
     }
 }
@@ -875,6 +924,19 @@
                     .map(|o| o.as_u64()
                          .map(|s| base.options.$key_name = Some(s)));
             } );
+            ($key_name:ident, MergeFunctions) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                    match s.parse::<MergeFunctions>() {
+                        Ok(mergefunc) => base.options.$key_name = mergefunc,
+                        _ => return Some(Err(format!("'{}' is not a valid value for \
+                                                      merge-functions. Use 'disabled', \
+                                                      'trampolines', or 'aliases'.",
+                                                      s))),
+                    }
+                    Some(Ok(()))
+                })).unwrap_or(Ok(()))
+            } );
             ($key_name:ident, PanicStrategy) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
@@ -1064,6 +1126,7 @@
         key!(requires_uwtable, bool);
         key!(simd_types_indirect, bool);
         key!(override_export_symbols, opt_list);
+        key!(merge_functions, MergeFunctions)?;
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
             for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -1275,6 +1338,7 @@
         target_option_val!(requires_uwtable);
         target_option_val!(simd_types_indirect);
         target_option_val!(override_export_symbols);
+        target_option_val!(merge_functions);
 
         if default.abi_blacklist != self.options.abi_blacklist {
             d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 8e5eaa1..534279e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -10,6 +10,7 @@
 use lint;
 use middle::resolve_lifetime as rl;
 use namespace::Namespace;
+use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
@@ -1278,29 +1279,50 @@
     }
 
     // Create a type from a path to an associated type.
-    // For a path `A::B::C::D`, `ty` and `ty_path_def` are the type and def for `A::B::C`
+    // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
     // and item_segment is the path segment for `D`. We return a type and a def for
     // the whole path.
-    // Will fail except for `T::A` and `Self::A`; i.e., if `ty`/`ty_path_def` are not a type
+    // Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type
     // parameter or `Self`.
-    pub fn associated_path_def_to_ty(&self,
-                                     ref_id: ast::NodeId,
-                                     span: Span,
-                                     ty: Ty<'tcx>,
-                                     ty_path_def: Def,
-                                     item_segment: &hir::PathSegment)
-                                     -> (Ty<'tcx>, Def)
-    {
+    pub fn associated_path_to_ty(
+        &self,
+        ref_id: ast::NodeId,
+        span: Span,
+        qself_ty: Ty<'tcx>,
+        qself_def: Def,
+        assoc_segment: &hir::PathSegment,
+        permit_variants: bool,
+    ) -> (Ty<'tcx>, Def) {
         let tcx = self.tcx();
-        let assoc_name = item_segment.ident;
+        let assoc_ident = assoc_segment.ident;
 
-        debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
+        debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
 
-        self.prohibit_generics(slice::from_ref(item_segment));
+        self.prohibit_generics(slice::from_ref(assoc_segment));
+
+        // Check if we have an enum variant.
+        let mut variant_resolution = None;
+        if let ty::Adt(adt_def, _) = qself_ty.sty {
+            if adt_def.is_enum() {
+                let variant_def = adt_def.variants.iter().find(|vd| {
+                    tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did)
+                });
+                if let Some(variant_def) = variant_def {
+                    let def = Def::Variant(variant_def.did);
+                    if permit_variants {
+                        check_type_alias_enum_variants_enabled(tcx, span);
+                        tcx.check_stability(variant_def.did, Some(ref_id), span);
+                        return (qself_ty, def);
+                    } else {
+                        variant_resolution = Some(def);
+                    }
+                }
+            }
+        }
 
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
-        let bound = match (&ty.sty, ty_path_def) {
+        let bound = match (&qself_ty.sty, qself_def) {
             (_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
@@ -1313,77 +1335,61 @@
                 };
 
                 let candidates = traits::supertraits(tcx, ty::Binder::bind(trait_ref))
-                    .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
+                    .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_ident));
 
-                match self.one_bound_for_assoc_type(candidates, "Self", assoc_name, span) {
+                match self.one_bound_for_assoc_type(candidates, "Self", assoc_ident, span) {
                     Ok(bound) => bound,
                     Err(ErrorReported) => return (tcx.types.err, Def::Err),
                 }
             }
             (&ty::Param(_), Def::SelfTy(Some(param_did), None)) |
             (&ty::Param(_), Def::TyParam(param_did)) => {
-                match self.find_bound_for_assoc_item(param_did, assoc_name, span) {
+                match self.find_bound_for_assoc_item(param_did, assoc_ident, span) {
                     Ok(bound) => bound,
                     Err(ErrorReported) => return (tcx.types.err, Def::Err),
                 }
             }
-            (&ty::Adt(adt_def, _substs), Def::Enum(_did)) => {
-                let ty_str = ty.to_string();
-                // Incorrect enum variant.
-                let mut err = tcx.sess.struct_span_err(
-                    span,
-                    &format!("no variant `{}` on enum `{}`", &assoc_name.as_str(), ty_str),
-                );
-                // Check if it was a typo.
-                let input = adt_def.variants.iter().map(|variant| &variant.ident.name);
-                if let Some(suggested_name) = find_best_match_for_name(
-                    input,
-                    &assoc_name.as_str(),
-                    None,
-                ) {
-                    err.span_suggestion_with_applicability(
-                        span,
-                        "did you mean",
-                        format!("{}::{}", ty_str, suggested_name.to_string()),
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    err.span_label(span, "unknown variant");
-                }
-                err.emit();
-                return (tcx.types.err, Def::Err);
-            }
             _ => {
-                // Check if we have an enum variant.
-                match ty.sty {
-                    ty::Adt(adt_def, _) if adt_def.is_enum() => {
-                        let variant_def = adt_def.variants.iter().find(|vd| {
-                            tcx.hygienic_eq(assoc_name, vd.ident, adt_def.did)
-                        });
-                        if let Some(variant_def) = variant_def {
-                            check_type_alias_enum_variants_enabled(tcx, span);
-
-                            let def = Def::Variant(variant_def.did);
-                            tcx.check_stability(def.def_id(), Some(ref_id), span);
-                            return (ty, def);
-                        }
-                    },
-                    _ => (),
-                }
-
-                // Don't print `TyErr` to the user.
-                if !ty.references_error() {
+                if variant_resolution.is_some() {
+                    // Variant in type position
+                    let msg = format!("expected type, found variant `{}`", assoc_ident);
+                    tcx.sess.span_err(span, &msg);
+                } else if qself_ty.is_enum() {
+                    // Report as incorrect enum variant rather than ambiguous type.
+                    let mut err = tcx.sess.struct_span_err(
+                        span,
+                        &format!("no variant `{}` on enum `{}`", &assoc_ident.as_str(), qself_ty),
+                    );
+                    // Check if it was a typo.
+                    let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
+                    if let Some(suggested_name) = find_best_match_for_name(
+                        adt_def.variants.iter().map(|variant| &variant.ident.name),
+                        &assoc_ident.as_str(),
+                        None,
+                    ) {
+                        err.span_suggestion_with_applicability(
+                            span,
+                            "did you mean",
+                            format!("{}::{}", qself_ty, suggested_name),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        err.span_label(span, "unknown variant");
+                    }
+                    err.emit();
+                } else if !qself_ty.references_error() {
+                    // Don't print `TyErr` to the user.
                     self.report_ambiguous_associated_type(span,
-                                                          &ty.to_string(),
+                                                          &qself_ty.to_string(),
                                                           "Trait",
-                                                          &assoc_name.as_str());
+                                                          &assoc_ident.as_str());
                 }
                 return (tcx.types.err, Def::Err);
             }
         };
 
         let trait_did = bound.def_id();
-        let (assoc_ident, def_scope) = tcx.adjust_ident(assoc_name, trait_did, ref_id);
+        let (assoc_ident, def_scope) = tcx.adjust_ident(assoc_ident, trait_did, ref_id);
         let item = tcx.associated_items(trait_did).find(|i| {
             Namespace::from(i.kind) == Namespace::Type &&
                 i.ident.modern() == assoc_ident
@@ -1394,11 +1400,35 @@
 
         let def = Def::AssociatedTy(item.def_id);
         if !item.vis.is_accessible_from(def_scope, tcx) {
-            let msg = format!("{} `{}` is private", def.kind_name(), assoc_name);
+            let msg = format!("{} `{}` is private", def.kind_name(), assoc_ident);
             tcx.sess.span_err(span, &msg);
         }
         tcx.check_stability(item.def_id, Some(ref_id), span);
 
+        if let Some(variant_def) = variant_resolution {
+            let mut err = tcx.struct_span_lint_node(
+                AMBIGUOUS_ASSOCIATED_ITEMS,
+                ref_id,
+                span,
+                "ambiguous associated item",
+            );
+
+            let mut could_refer_to = |def: Def, also| {
+                let note_msg = format!("`{}` could{} refer to {} defined here",
+                                       assoc_ident, also, def.kind_name());
+                err.span_note(tcx.def_span(def.def_id()), &note_msg);
+            };
+            could_refer_to(variant_def, "");
+            could_refer_to(def, " also");
+
+            err.span_suggestion_with_applicability(
+                span,
+                "use fully-qualified syntax",
+                format!("<{} as {}>::{}", qself_ty, "Trait", assoc_ident),
+                Applicability::HasPlaceholders,
+            ).emit();
+        }
+
         (ty, def)
     }
 
@@ -1773,7 +1803,7 @@
                 } else {
                     Def::Err
                 };
-                self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
+                self.associated_path_to_ty(ast_ty.id, ast_ty.span, ty, def, segment, false).0
             }
             hir::TyKind::Array(ref ty, ref length) => {
                 let length_def_id = tcx.hir().local_def_id(length.id);
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 02687df..e71dc01 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -408,45 +408,36 @@
 
         let tcx = self.tcx;
 
-        let mode = probe::Mode::Path;
-        match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
-                                  self_ty, expr_id, ProbeScope::TraitsInScope) {
-            Ok(pick) => {
-                debug!("resolve_ufcs: pick={:?}", pick);
-                if let Some(import_id) = pick.import_id {
-                    let import_def_id = tcx.hir().local_def_id(import_id);
-                    debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
-                    Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
-                                                .unwrap().insert(import_def_id);
+        // Check if we have an enum variant.
+        if let ty::Adt(adt_def, _) = self_ty.sty {
+            if adt_def.is_enum() {
+                let variant_def = adt_def.variants.iter().find(|vd| {
+                    tcx.hygienic_eq(method_name, vd.ident, adt_def.did)
+                });
+                if let Some(variant_def) = variant_def {
+                    check_type_alias_enum_variants_enabled(tcx, span);
+
+                    let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind);
+                    tcx.check_stability(def.def_id(), Some(expr_id), span);
+                    return Ok(def);
                 }
-
-                let def = pick.item.def();
-                debug!("resolve_ufcs: def={:?}", def);
-                tcx.check_stability(def.def_id(), Some(expr_id), span);
-
-                Ok(def)
-            }
-            Err(err) => {
-                // Check if we have an enum variant.
-                match self_ty.sty {
-                    ty::Adt(adt_def, _) if adt_def.is_enum() => {
-                        let variant_def = adt_def.variants.iter().find(|vd| {
-                            tcx.hygienic_eq(method_name, vd.ident, adt_def.did)
-                        });
-                        if let Some(variant_def) = variant_def {
-                            check_type_alias_enum_variants_enabled(tcx, span);
-
-                            let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind);
-                            tcx.check_stability(def.def_id(), Some(expr_id), span);
-                            return Ok(def);
-                        }
-                    },
-                    _ => (),
-                }
-
-                Err(err)
             }
         }
+
+        let pick = self.probe_for_name(span, probe::Mode::Path, method_name, IsSuggestion(false),
+                                       self_ty, expr_id, ProbeScope::TraitsInScope)?;
+        debug!("resolve_ufcs: pick={:?}", pick);
+        if let Some(import_id) = pick.import_id {
+            let import_def_id = tcx.hir().local_def_id(import_id);
+            debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
+            Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
+                .unwrap().insert(import_def_id);
+        }
+
+        let def = pick.item.def();
+        debug!("resolve_ufcs: def={:?}", def);
+        tcx.check_stability(def.def_id(), Some(expr_id), span);
+        Ok(def)
     }
 
     /// Find item with name `item_name` defined in impl/trait `def_id`
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1b07385..452fd24 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -132,7 +132,8 @@
 use std::slice;
 
 use require_c_abi_if_variadic;
-use session::{CompileIncomplete, config, Session};
+use session::{CompileIncomplete, Session};
+use session::config::EntryFnType;
 use TypeAndSubsts;
 use lint;
 use util::captures::Captures;
@@ -1163,19 +1164,18 @@
 
     // Check that the main return type implements the termination trait.
     if let Some(term_id) = fcx.tcx.lang_items().termination() {
-        if let Some((id, _, entry_type)) = *fcx.tcx.sess.entry_fn.borrow() {
-            if id == fn_id {
-                if let config::EntryFnType::Main = entry_type {
-                    let substs = fcx.tcx.mk_substs_trait(declared_ret_ty, &[]);
-                    let trait_ref = ty::TraitRef::new(term_id, substs);
-                    let return_ty_span = decl.output.span();
-                    let cause = traits::ObligationCause::new(
-                        return_ty_span, fn_id, ObligationCauseCode::MainFunctionType);
+        if let Some((def_id, EntryFnType::Main)) = fcx.tcx.entry_fn(LOCAL_CRATE) {
+            let main_id = fcx.tcx.hir().as_local_node_id(def_id).unwrap();
+            if main_id == fn_id {
+                let substs = fcx.tcx.mk_substs_trait(declared_ret_ty, &[]);
+                let trait_ref = ty::TraitRef::new(term_id, substs);
+                let return_ty_span = decl.output.span();
+                let cause = traits::ObligationCause::new(
+                    return_ty_span, fn_id, ObligationCauseCode::MainFunctionType);
 
-                    inherited.register_predicate(
-                        traits::Obligation::new(
-                            cause, param_env, trait_ref.to_predicate()));
-                }
+                inherited.register_predicate(
+                    traits::Obligation::new(
+                        cause, param_env, trait_ref.to_predicate()));
             }
         }
     }
@@ -4724,8 +4724,8 @@
                 } else {
                     Def::Err
                 };
-                let (ty, def) = AstConv::associated_path_def_to_ty(self, node_id, path_span,
-                                                                   ty, def, segment);
+                let (ty, def) = AstConv::associated_path_to_ty(self, node_id, path_span,
+                                                               ty, def, segment, true);
 
                 // Write back the new resolution.
                 let hir_id = self.tcx.hir().node_to_hir_id(node_id);
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 8bd484a..6c1c49b 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -103,23 +103,22 @@
 mod outlives;
 mod variance;
 
-use hir::Node;
 use rustc_target::spec::abi::Abi;
-use rustc::hir;
+use rustc::hir::{self, Node};
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::infer::InferOk;
 use rustc::lint;
 use rustc::middle;
 use rustc::session;
-use rustc::session::config::nightly_options;
+use rustc::session::CompileIncomplete;
+use rustc::session::config::{EntryFnType, nightly_options};
 use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::query::Providers;
 use rustc::util;
 use rustc::util::profiling::ProfileCategory;
-use session::{CompileIncomplete, config};
 use syntax_pos::Span;
-use syntax::ast;
 use util::common::time;
 
 use std::iter;
@@ -184,10 +183,9 @@
     })
 }
 
-fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              main_id: ast::NodeId,
-                              main_span: Span) {
-    let main_def_id = tcx.hir().local_def_id(main_id);
+fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, main_def_id: DefId) {
+    let main_id = tcx.hir().as_local_node_id(main_def_id).unwrap();
+    let main_span = tcx.def_span(main_def_id);
     let main_t = tcx.type_of(main_def_id);
     match main_t.sty {
         ty::FnDef(..) => {
@@ -250,10 +248,9 @@
     }
 }
 
-fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                               start_id: ast::NodeId,
-                               start_span: Span) {
-    let start_def_id = tcx.hir().local_def_id(start_id);
+fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, start_def_id: DefId) {
+    let start_id = tcx.hir().as_local_node_id(start_def_id).unwrap();
+    let start_span = tcx.def_span(start_def_id);
     let start_t = tcx.type_of(start_def_id);
     match start_t.sty {
         ty::FnDef(..) => {
@@ -309,11 +306,10 @@
 }
 
 fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    if let Some((id, sp, entry_type)) = *tcx.sess.entry_fn.borrow() {
-        match entry_type {
-            config::EntryFnType::Main => check_main_fn_ty(tcx, id, sp),
-            config::EntryFnType::Start => check_start_fn_ty(tcx, id, sp),
-        }
+    match tcx.entry_fn(LOCAL_CRATE) {
+        Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
+        Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
+        _ => {}
     }
 }
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 78dbf41..7069f04 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -51,9 +51,6 @@
     /// The stack of module NodeIds up till this point
     pub crate_name: Option<String>,
     pub cstore: Rc<CStore>,
-    // Note that external items for which `doc(hidden)` applies to are shown as
-    // non-reachable while local items aren't. This is because we're reusing
-    // the access levels from crateanalysis.
     /// Later on moved into `html::render::CACHE_KEY`
     pub renderinfo: RefCell<RenderInfo>,
     /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
@@ -468,15 +465,13 @@
             freevars: resolver.freevars.clone(),
             export_map: resolver.export_map.clone(),
             trait_map: resolver.trait_map.clone(),
+            glob_map: resolver.glob_map.clone(),
             maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
             maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
             extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
                 (ident.name, entry.introduced_by_item)
             }).collect(),
         };
-        let analysis = ty::CrateAnalysis {
-            glob_map: resolver.glob_map.clone(),
-        };
 
         let mut arenas = AllArenas::new();
         let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
@@ -492,12 +487,11 @@
                                                         &sess,
                                                         &*cstore,
                                                         hir_map,
-                                                        analysis,
                                                         resolutions,
                                                         &mut arenas,
                                                         &name,
                                                         &output_filenames,
-                                                        |tcx, _, _, result| {
+                                                        |tcx, _, result| {
             if result.is_err() {
                 sess.fatal("Compilation failed, aborting rustdoc");
             }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 06846d4..ad1659b 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -309,7 +309,7 @@
 
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
-    // the access levels from crateanalysis.
+    // the access levels from the privacy check pass.
     pub access_levels: AccessLevels<DefId>,
 
     /// The version of the crate being documented, if given from the `--crate-version` flag.
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 24202ca..9a129e7 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -435,7 +435,8 @@
                     match *seq_tt {
                         TokenTree::MetaVarDecl(_, _, id) => id.name == "vis",
                         TokenTree::Sequence(_, ref sub_seq) =>
-                            sub_seq.op == quoted::KleeneOp::ZeroOrMore,
+                            sub_seq.op == quoted::KleeneOp::ZeroOrMore
+                            || sub_seq.op == quoted::KleeneOp::ZeroOrOne,
                         _ => false,
                     }
                 }) {
@@ -543,7 +544,10 @@
                         }
 
                         // Reverse scan: Sequence comes before `first`.
-                        if subfirst.maybe_empty || seq_rep.op == quoted::KleeneOp::ZeroOrMore {
+                        if subfirst.maybe_empty
+                           || seq_rep.op == quoted::KleeneOp::ZeroOrMore
+                           || seq_rep.op == quoted::KleeneOp::ZeroOrOne
+                        {
                             // If sequence is potentially empty, then
                             // union them (preserving first emptiness).
                             first.add_all(&TokenSet { maybe_empty: true, ..subfirst });
@@ -591,8 +595,10 @@
 
                             assert!(first.maybe_empty);
                             first.add_all(subfirst);
-                            if subfirst.maybe_empty ||
-                               seq_rep.op == quoted::KleeneOp::ZeroOrMore {
+                            if subfirst.maybe_empty
+                               || seq_rep.op == quoted::KleeneOp::ZeroOrMore
+                               || seq_rep.op == quoted::KleeneOp::ZeroOrOne
+                            {
                                 // continue scanning for more first
                                 // tokens, but also make sure we
                                 // restore empty-tracking state
diff --git a/src/test/incremental/change_name_of_static_in_fn.rs b/src/test/incremental/change_name_of_static_in_fn.rs
new file mode 100644
index 0000000..5b27b68
--- /dev/null
+++ b/src/test/incremental/change_name_of_static_in_fn.rs
@@ -0,0 +1,17 @@
+
+// revisions:rpass1 rpass2 rpass3
+
+// See issue #57692.
+
+#![allow(warnings)]
+
+fn main() {
+    #[cfg(rpass1)]
+    {
+        static map: u64 = 0;
+    }
+    #[cfg(not(rpass1))]
+    {
+        static MAP: u64 = 0;
+    }
+}
diff --git a/src/test/ui/huge-enum.rs b/src/test/ui/huge-enum.rs
index 18ef457..71c8fd5 100644
--- a/src/test/ui/huge-enum.rs
+++ b/src/test/ui/huge-enum.rs
@@ -1,7 +1,5 @@
-// error-pattern: Option
-// normalize-stderr-test "<\[u32; \d+\]>" -> "<[u32; N]>"
-
-// FIXME: work properly with higher limits
+// normalize-stderr-test "std::option::Option<\[u32; \d+\]>" -> "TYPE"
+// normalize-stderr-test "\[u32; \d+\]" -> "TYPE"
 
 #[cfg(target_pointer_width = "32")]
 fn main() {
diff --git a/src/test/ui/huge-enum.stderr b/src/test/ui/huge-enum.stderr
index b7cf255..67cae3d 100644
--- a/src/test/ui/huge-enum.stderr
+++ b/src/test/ui/huge-enum.stderr
@@ -1,4 +1,4 @@
-error: the type `std::option::Option<[u32; N]>` is too big for the current architecture
+error: the type `TYPE` is too big for the current architecture
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5067.rs b/src/test/ui/issues/issue-5067.rs
index 526a683..616fd09 100644
--- a/src/test/ui/issues/issue-5067.rs
+++ b/src/test/ui/issues/issue-5067.rs
@@ -1,37 +1,59 @@
 #![allow(unused_macros)]
 
+// Tests that repetition matchers cannot match the empty token tree (since that would be
+// ambiguous).
+
+// edition:2018
+
 macro_rules! foo {
     ( $()* ) => {};
     //~^ ERROR repetition matches empty token tree
     ( $()+ ) => {};
     //~^ ERROR repetition matches empty token tree
-
+    ( $()? ) => {};
+    //~^ ERROR repetition matches empty token tree
     ( $(),* ) => {}; // PASS
     ( $(),+ ) => {}; // PASS
-
+    // `?` cannot have a separator...
     ( [$()*] ) => {};
     //~^ ERROR repetition matches empty token tree
     ( [$()+] ) => {};
     //~^ ERROR repetition matches empty token tree
-
+    ( [$()?] ) => {};
+    //~^ ERROR repetition matches empty token tree
     ( [$(),*] ) => {}; // PASS
     ( [$(),+] ) => {}; // PASS
-
+    // `?` cannot have a separator...
     ( $($()* $(),* $(a)* $(a),* )* ) => {};
     //~^ ERROR repetition matches empty token tree
     ( $($()* $(),* $(a)* $(a),* )+ ) => {};
     //~^ ERROR repetition matches empty token tree
-
+    ( $($()* $(),* $(a)* $(a),* )? ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( $($()? $(),* $(a)? $(a),* )* ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( $($()? $(),* $(a)? $(a),* )+ ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( $($()? $(),* $(a)? $(a),* )? ) => {};
+    //~^ ERROR repetition matches empty token tree
     ( $(a     $(),* $(a)* $(a),* )* ) => {}; // PASS
     ( $($(a)+ $(),* $(a)* $(a),* )+ ) => {}; // PASS
+    ( $($(a)+ $(),* $(a)* $(a),* )? ) => {}; // PASS
+
+    ( $(a     $(),* $(a)? $(a),* )* ) => {}; // PASS
+    ( $($(a)+ $(),* $(a)? $(a),* )+ ) => {}; // PASS
+    ( $($(a)+ $(),* $(a)? $(a),* )? ) => {}; // PASS
 
     ( $(a $()+)* ) => {};
     //~^ ERROR repetition matches empty token tree
     ( $(a $()*)+ ) => {};
     //~^ ERROR repetition matches empty token tree
+    ( $(a $()+)? ) => {};
+    //~^ ERROR repetition matches empty token tree
+    ( $(a $()?)+ ) => {};
+    //~^ ERROR repetition matches empty token tree
 }
 
-
 // --- Original Issue --- //
 
 macro_rules! make_vec {
@@ -43,11 +65,10 @@
     let _ = make_vec![a 1, a 2, a 3];
 }
 
-
 // --- Minified Issue --- //
 
 macro_rules! m {
-    ( $()* ) => {}
+    ( $()* ) => {};
     //~^ ERROR repetition matches empty token tree
 }
 
diff --git a/src/test/ui/issues/issue-5067.stderr b/src/test/ui/issues/issue-5067.stderr
index 433b7c8..7ffc607 100644
--- a/src/test/ui/issues/issue-5067.stderr
+++ b/src/test/ui/issues/issue-5067.stderr
@@ -1,62 +1,110 @@
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:4:8
+  --> $DIR/issue-5067.rs:9:8
    |
 LL |     ( $()* ) => {};
    |        ^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:6:8
+  --> $DIR/issue-5067.rs:11:8
    |
 LL |     ( $()+ ) => {};
    |        ^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:12:9
+  --> $DIR/issue-5067.rs:13:8
+   |
+LL |     ( $()? ) => {};
+   |        ^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:18:9
    |
 LL |     ( [$()*] ) => {};
    |         ^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:14:9
+  --> $DIR/issue-5067.rs:20:9
    |
 LL |     ( [$()+] ) => {};
    |         ^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:20:8
+  --> $DIR/issue-5067.rs:22:9
+   |
+LL |     ( [$()?] ) => {};
+   |         ^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:27:8
    |
 LL |     ( $($()* $(),* $(a)* $(a),* )* ) => {};
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:22:8
+  --> $DIR/issue-5067.rs:29:8
    |
 LL |     ( $($()* $(),* $(a)* $(a),* )+ ) => {};
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:28:12
+  --> $DIR/issue-5067.rs:31:8
+   |
+LL |     ( $($()* $(),* $(a)* $(a),* )? ) => {};
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:33:8
+   |
+LL |     ( $($()? $(),* $(a)? $(a),* )* ) => {};
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:35:8
+   |
+LL |     ( $($()? $(),* $(a)? $(a),* )+ ) => {};
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:37:8
+   |
+LL |     ( $($()? $(),* $(a)? $(a),* )? ) => {};
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:47:12
    |
 LL |     ( $(a $()+)* ) => {};
    |            ^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:30:12
+  --> $DIR/issue-5067.rs:49:12
    |
 LL |     ( $(a $()*)+ ) => {};
    |            ^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:38:18
+  --> $DIR/issue-5067.rs:51:12
+   |
+LL |     ( $(a $()+)? ) => {};
+   |            ^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:53:12
+   |
+LL |     ( $(a $()?)+ ) => {};
+   |            ^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-5067.rs:60:18
    |
 LL |     (a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]);
    |                  ^^^^^^^^^^^^^^^^^^
 
 error: repetition matches empty token tree
-  --> $DIR/issue-5067.rs:50:8
+  --> $DIR/issue-5067.rs:71:8
    |
-LL |     ( $()* ) => {}
+LL |     ( $()* ) => {};
    |        ^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/src/test/ui/issues/issue-57597.rs b/src/test/ui/issues/issue-57597.rs
new file mode 100644
index 0000000..ebeb3fe
--- /dev/null
+++ b/src/test/ui/issues/issue-57597.rs
@@ -0,0 +1,80 @@
+// Regression test for #57597.
+//
+// Make sure that nested matchers work correctly rather than causing an infinite loop or crash.
+
+// edition:2018
+
+macro_rules! foo1 {
+    ($($($i:ident)?)+) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo2 {
+    ($($($i:ident)?)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo3 {
+    ($($($i:ident)?)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo4 {
+    ($($($($i:ident)?)?)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo5 {
+    ($($($($i:ident)*)?)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo6 {
+    ($($($($i:ident)?)*)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo7 {
+    ($($($($i:ident)?)?)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo8 {
+    ($($($($i:ident)*)*)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo9 {
+    ($($($($i:ident)?)*)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo10 {
+    ($($($($i:ident)?)*)+) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo11 {
+    ($($($($i:ident)+)?)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo12 {
+    ($($($($i:ident)+)*)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+fn main() {
+    foo1!();
+    foo2!();
+    foo3!();
+    foo4!();
+    foo5!();
+    foo6!();
+    foo7!();
+    foo8!();
+    foo9!();
+    foo10!();
+    foo11!();
+    foo12!();
+}
diff --git a/src/test/ui/issues/issue-57597.stderr b/src/test/ui/issues/issue-57597.stderr
new file mode 100644
index 0000000..0a02ac8
--- /dev/null
+++ b/src/test/ui/issues/issue-57597.stderr
@@ -0,0 +1,74 @@
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:8:7
+   |
+LL |     ($($($i:ident)?)+) => {};
+   |       ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:13:7
+   |
+LL |     ($($($i:ident)?)*) => {};
+   |       ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:18:7
+   |
+LL |     ($($($i:ident)?)?) => {};
+   |       ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:23:7
+   |
+LL |     ($($($($i:ident)?)?)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:28:7
+   |
+LL |     ($($($($i:ident)*)?)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:33:7
+   |
+LL |     ($($($($i:ident)?)*)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:38:7
+   |
+LL |     ($($($($i:ident)?)?)*) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:43:7
+   |
+LL |     ($($($($i:ident)*)*)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:48:7
+   |
+LL |     ($($($($i:ident)?)*)*) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:53:7
+   |
+LL |     ($($($($i:ident)?)*)+) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:58:7
+   |
+LL |     ($($($($i:ident)+)?)*) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:63:7
+   |
+LL |     ($($($($i:ident)+)*)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/ui/type-alias-enum-variants-priority-2.rs b/src/test/ui/type-alias-enum-variants-priority-2.rs
new file mode 100644
index 0000000..295f8ac
--- /dev/null
+++ b/src/test/ui/type-alias-enum-variants-priority-2.rs
@@ -0,0 +1,13 @@
+#![feature(type_alias_enum_variants)]
+
+enum E {
+    V(u8)
+}
+
+impl E {
+    fn V() {}
+}
+
+fn main() {
+    <E>::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied
+}
diff --git a/src/test/ui/type-alias-enum-variants-priority-2.stderr b/src/test/ui/type-alias-enum-variants-priority-2.stderr
new file mode 100644
index 0000000..c6ec96e
--- /dev/null
+++ b/src/test/ui/type-alias-enum-variants-priority-2.stderr
@@ -0,0 +1,12 @@
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+  --> $DIR/type-alias-enum-variants-priority-2.rs:12:5
+   |
+LL |     V(u8)
+   |     ----- defined here
+...
+LL |     <E>::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied
+   |     ^^^^^^^^ expected 1 parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/type-alias-enum-variants-priority-3.rs b/src/test/ui/type-alias-enum-variants-priority-3.rs
new file mode 100644
index 0000000..33f9655
--- /dev/null
+++ b/src/test/ui/type-alias-enum-variants-priority-3.rs
@@ -0,0 +1,10 @@
+#![feature(type_alias_enum_variants)]
+
+enum E {
+    V
+}
+
+fn check() -> <E>::V {}
+//~^ ERROR expected type, found variant `V`
+
+fn main() {}
diff --git a/src/test/ui/type-alias-enum-variants-priority-3.stderr b/src/test/ui/type-alias-enum-variants-priority-3.stderr
new file mode 100644
index 0000000..b345154
--- /dev/null
+++ b/src/test/ui/type-alias-enum-variants-priority-3.stderr
@@ -0,0 +1,8 @@
+error: expected type, found variant `V`
+  --> $DIR/type-alias-enum-variants-priority-3.rs:7:15
+   |
+LL | fn check() -> <E>::V {}
+   |               ^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-enum-variants-priority.rs b/src/test/ui/type-alias-enum-variants-priority.rs
new file mode 100644
index 0000000..db1da2b
--- /dev/null
+++ b/src/test/ui/type-alias-enum-variants-priority.rs
@@ -0,0 +1,20 @@
+#![feature(type_alias_enum_variants)]
+#![deny(ambiguous_associated_items)]
+
+enum E {
+    V
+}
+
+trait Tr {
+    type V;
+    fn f() -> Self::V;
+}
+
+impl Tr for E {
+    type V = u8;
+    fn f() -> Self::V { 0 }
+    //~^ ERROR ambiguous associated item
+    //~| WARN this was previously accepted
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-enum-variants-priority.stderr b/src/test/ui/type-alias-enum-variants-priority.stderr
new file mode 100644
index 0000000..dcf7dc7
--- /dev/null
+++ b/src/test/ui/type-alias-enum-variants-priority.stderr
@@ -0,0 +1,26 @@
+error: ambiguous associated item
+  --> $DIR/type-alias-enum-variants-priority.rs:15:15
+   |
+LL |     fn f() -> Self::V { 0 }
+   |               ^^^^^^^ help: use fully-qualified syntax: `<E as Trait>::V`
+   |
+note: lint level defined here
+  --> $DIR/type-alias-enum-variants-priority.rs:2:9
+   |
+LL | #![deny(ambiguous_associated_items)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57644 <https://github.com/rust-lang/rust/issues/57644>
+note: `V` could refer to variant defined here
+  --> $DIR/type-alias-enum-variants-priority.rs:5:5
+   |
+LL |     V
+   |     ^
+note: `V` could also refer to associated type defined here
+  --> $DIR/type-alias-enum-variants-priority.rs:9:5
+   |
+LL |     type V;
+   |     ^^^^^^^
+
+error: aborting due to previous error
+