about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-10 07:46:58 +0000
committerbors <bors@rust-lang.org>2019-11-10 07:46:58 +0000
commit86c28325ff813e5cf4d0cab320a7c9f6fb0766b8 (patch)
treeff5aeb60cbe141f97643322de00f4349ef9adaef
parent57a5f92bef4b459005920f1aeff05a52c7e356b0 (diff)
parent43a74051c7b699e2df66122cfcf074aaf144a4fe (diff)
Auto merge of #66072 - Mark-Simulacrum:next-node-id, r=nikomatsakis
Move next node ID to Resolver

This moves the `next_node_id` method(s) and related tracking information to the resolver. By doing so, we also remove the OneThread and Cell on next_node_id in Session in this move, which means that the new code is simpler and less "interesting" as it doesn't tie itself to a single thread.

This required moving some of the pretty-printing logic around, but this was just copying the code without any semantic changes, so it's just a second commit instead of a separate PR; I can polish it up a bit more if desired.
-rw-r--r--Cargo.lock1
-rw-r--r--src/librustc/hir/lowering.rs18
-rw-r--r--src/librustc/hir/lowering/expr.rs2
-rw-r--r--src/librustc/hir/lowering/item.rs4
-rw-r--r--src/librustc/session/config.rs220
-rw-r--r--src/librustc/session/mod.rs21
-rw-r--r--src/librustc_driver/Cargo.toml1
-rw-r--r--src/librustc_driver/lib.rs36
-rw-r--r--src/librustc_driver/pretty.rs328
-rw-r--r--src/librustc_interface/passes.rs9
-rw-r--r--src/librustc_interface/util.rs37
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs2
-rw-r--r--src/librustc_resolve/lib.rs19
-rw-r--r--src/librustc_resolve/macros.rs2
14 files changed, 356 insertions, 344 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0f770f3eadb..8b157d2b3f4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3506,6 +3506,7 @@ dependencies = [
  "rustc_mir",
  "rustc_plugin",
  "rustc_plugin_impl",
+ "rustc_resolve",
  "rustc_save_analysis",
  "rustc_target",
  "serialize",
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 278f45371b1..f2d5f043f90 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -183,6 +183,8 @@ pub trait Resolver {
     ) -> (ast::Path, Res<NodeId>);
 
     fn lint_buffer(&mut self) -> &mut lint::LintBuffer;
+
+    fn next_node_id(&mut self) -> NodeId;
 }
 
 type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
@@ -672,7 +674,8 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn next_id(&mut self) -> hir::HirId {
-        self.lower_node_id(self.sess.next_node_id())
+        let node_id = self.resolver.next_node_id();
+        self.lower_node_id(node_id)
     }
 
     fn lower_res(&mut self, res: Res<NodeId>) -> Res {
@@ -781,7 +784,7 @@ impl<'a> LoweringContext<'a> {
         hir_name: ParamName,
         parent_index: DefIndex,
     ) -> hir::GenericParam {
-        let node_id = self.sess.next_node_id();
+        let node_id = self.resolver.next_node_id();
 
         // Get the name we'll use to make the def-path. Note
         // that collisions are ok here and this shouldn't
@@ -1106,7 +1109,7 @@ impl<'a> LoweringContext<'a> {
                     // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
                     // constructing the HIR for `impl bounds...` and then lowering that.
 
-                    let impl_trait_node_id = self.sess.next_node_id();
+                    let impl_trait_node_id = self.resolver.next_node_id();
                     let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
                     self.resolver.definitions().create_def_with_parent(
                         parent_def_index,
@@ -1117,9 +1120,10 @@ impl<'a> LoweringContext<'a> {
                     );
 
                     self.with_dyn_type_scope(false, |this| {
+                        let node_id = this.resolver.next_node_id();
                         let ty = this.lower_ty(
                             &Ty {
-                                id: this.sess.next_node_id(),
+                                id: node_id,
                                 kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
                                 span: constraint.span,
                             },
@@ -1586,7 +1590,7 @@ impl<'a> LoweringContext<'a> {
                         name,
                     }));
 
-                    let def_node_id = self.context.sess.next_node_id();
+                    let def_node_id = self.context.resolver.next_node_id();
                     let hir_id =
                         self.context.lower_node_id_with_owner(def_node_id, self.opaque_ty_id);
                     self.context.resolver.definitions().create_def_with_parent(
@@ -3234,7 +3238,7 @@ impl<'a> LoweringContext<'a> {
             Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
 
             None => (
-                self.sess.next_node_id(),
+                self.resolver.next_node_id(),
                 "`&` without an explicit lifetime name cannot be used here",
                 "explicit lifetime name needed here",
             ),
@@ -3271,7 +3275,7 @@ impl<'a> LoweringContext<'a> {
                     span,
                     "expected 'implicit elided lifetime not allowed' error",
                 );
-                let id = self.sess.next_node_id();
+                let id = self.resolver.next_node_id();
                 self.new_named_lifetime(id, span, hir::LifetimeName::Error)
             }
             // `PassThrough` is the normal case.
diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index 73db762a64b..42ce74aedef 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -595,7 +595,7 @@ impl LoweringContext<'_> {
         };
 
         // `::std::task::Poll::Ready(result) => break result`
-        let loop_node_id = self.sess.next_node_id();
+        let loop_node_id = self.resolver.next_node_id();
         let loop_hir_id = self.lower_node_id(loop_node_id);
         let ready_arm = {
             let x_ident = Ident::with_dummy_span(sym::result);
diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs
index 7aa1aa8bb51..4e20f476d85 100644
--- a/src/librustc/hir/lowering/item.rs
+++ b/src/librustc/hir/lowering/item.rs
@@ -522,7 +522,7 @@ impl LoweringContext<'_> {
                     let ident = *ident;
                     let mut path = path.clone();
                     for seg in &mut path.segments {
-                        seg.id = self.sess.next_node_id();
+                        seg.id = self.resolver.next_node_id();
                     }
                     let span = path.span;
 
@@ -599,7 +599,7 @@ impl LoweringContext<'_> {
 
                     // Give the segments new node-ids since they are being cloned.
                     for seg in &mut prefix.segments {
-                        seg.id = self.sess.next_node_id();
+                        seg.id = self.resolver.next_node_id();
                     }
 
                     // Each `use` import is an item and thus are owners of the
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index eb5654e80a8..4a14960aa69 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1,10 +1,13 @@
 //! Contains infrastructure for configuring the compiler, including parsing
 //! command-line options.
 
+// ignore-tidy-filelength
+
 use crate::lint;
 use crate::middle::cstore;
 use crate::session::{early_error, early_warn, Session};
 use crate::session::search_paths::SearchPath;
+use crate::hir::map as hir_map;
 
 use rustc_data_structures::fx::FxHashSet;
 
@@ -440,6 +443,8 @@ top_level_options!(
         // `true` if we're emitting JSON blobs about each artifact produced
         // by the compiler.
         json_artifact_notifications: bool [TRACKED],
+
+        pretty: Option<(PpMode, Option<UserIdentifiedItem>)> [UNTRACKED],
     }
 );
 
@@ -621,6 +626,7 @@ impl Default for Options {
             remap_path_prefix: Vec::new(),
             edition: DEFAULT_EDITION,
             json_artifact_notifications: false,
+            pretty: None,
         }
     }
 }
@@ -2516,6 +2522,8 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
 
+    let pretty = parse_pretty(matches, &debugging_opts, error_format);
+
     Options {
         crate_types,
         optimize: opt_level,
@@ -2546,6 +2554,73 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         remap_path_prefix,
         edition,
         json_artifact_notifications,
+        pretty,
+    }
+}
+
+fn parse_pretty(
+    matches: &getopts::Matches,
+    debugging_opts: &DebuggingOptions,
+    efmt: ErrorOutputType,
+) -> Option<(PpMode, Option<UserIdentifiedItem>)> {
+    let pretty = if debugging_opts.unstable_options {
+        matches.opt_default("pretty", "normal").map(|a| {
+            // stable pretty-print variants only
+            parse_pretty_inner(efmt, &a, false)
+        })
+    } else {
+        None
+    };
+
+    return if pretty.is_none() {
+        debugging_opts.unpretty.as_ref().map(|a| {
+            // extended with unstable pretty-print variants
+            parse_pretty_inner(efmt, &a, true)
+        })
+    } else {
+        pretty
+    };
+
+    fn parse_pretty_inner(
+        efmt: ErrorOutputType,
+        name: &str,
+        extended: bool,
+    ) -> (PpMode, Option<UserIdentifiedItem>) {
+        use PpMode::*;
+        use PpSourceMode::*;
+        let mut split = name.splitn(2, '=');
+        let first = split.next().unwrap();
+        let opt_second = split.next();
+        let first = match (first, extended) {
+            ("normal", _) => PpmSource(PpmNormal),
+            ("identified", _) => PpmSource(PpmIdentified),
+            ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
+            ("expanded", _) => PpmSource(PpmExpanded),
+            ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
+            ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
+            ("hir", true) => PpmHir(PpmNormal),
+            ("hir,identified", true) => PpmHir(PpmIdentified),
+            ("hir,typed", true) => PpmHir(PpmTyped),
+            ("hir-tree", true) => PpmHirTree(PpmNormal),
+            ("mir", true) => PpmMir,
+            ("mir-cfg", true) => PpmMirCFG,
+            _ => {
+                if extended {
+                    early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
+                                        `expanded`, `identified`, `expanded,identified`, \
+                                        `expanded,hygiene`, `everybody_loops`, \
+                                        `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
+                                        `mir` or `mir-cfg`; got {}",
+                                        name));
+                } else {
+                    early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
+                                        `expanded`, `identified`, or `expanded,identified`; got {}",
+                                        name));
+                }
+            }
+        };
+        let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok());
+        (first, opt_second)
     }
 }
 
@@ -2656,6 +2731,151 @@ impl fmt::Display for CrateType {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum PpSourceMode {
+    PpmNormal,
+    PpmEveryBodyLoops,
+    PpmExpanded,
+    PpmIdentified,
+    PpmExpandedIdentified,
+    PpmExpandedHygiene,
+    PpmTyped,
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum PpMode {
+    PpmSource(PpSourceMode),
+    PpmHir(PpSourceMode),
+    PpmHirTree(PpSourceMode),
+    PpmMir,
+    PpmMirCFG,
+}
+
+impl PpMode {
+    pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool {
+        use PpMode::*;
+        use PpSourceMode::*;
+        match *self {
+            PpmSource(PpmNormal) |
+            PpmSource(PpmEveryBodyLoops) |
+            PpmSource(PpmIdentified) => opt_uii.is_some(),
+
+            PpmSource(PpmExpanded) |
+            PpmSource(PpmExpandedIdentified) |
+            PpmSource(PpmExpandedHygiene) |
+            PpmHir(_) |
+            PpmHirTree(_) |
+            PpmMir |
+            PpmMirCFG => true,
+            PpmSource(PpmTyped) => panic!("invalid state"),
+        }
+    }
+
+    pub fn needs_analysis(&self) -> bool {
+        use PpMode::*;
+        match *self {
+            PpmMir | PpmMirCFG => true,
+            _ => false,
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum UserIdentifiedItem {
+    ItemViaNode(ast::NodeId),
+    ItemViaPath(Vec<String>),
+}
+
+impl FromStr for UserIdentifiedItem {
+    type Err = ();
+    fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
+        use UserIdentifiedItem::*;
+        Ok(s.parse()
+            .map(ast::NodeId::from_u32)
+            .map(ItemViaNode)
+            .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
+    }
+}
+
+pub enum NodesMatchingUII<'a> {
+    NodesMatchingDirect(std::option::IntoIter<ast::NodeId>),
+    NodesMatchingSuffix(Box<dyn Iterator<Item = ast::NodeId> + 'a>),
+}
+
+impl<'a> Iterator for NodesMatchingUII<'a> {
+    type Item = ast::NodeId;
+
+    fn next(&mut self) -> Option<ast::NodeId> {
+        use NodesMatchingUII::*;
+        match self {
+            &mut NodesMatchingDirect(ref mut iter) => iter.next(),
+            &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        use NodesMatchingUII::*;
+        match self {
+            &NodesMatchingDirect(ref iter) => iter.size_hint(),
+            &NodesMatchingSuffix(ref iter) => iter.size_hint(),
+        }
+    }
+}
+
+impl UserIdentifiedItem {
+    pub fn reconstructed_input(&self) -> String {
+        use UserIdentifiedItem::*;
+        match *self {
+            ItemViaNode(node_id) => node_id.to_string(),
+            ItemViaPath(ref parts) => parts.join("::"),
+        }
+    }
+
+    pub fn all_matching_node_ids<'a, 'hir>(&'a self,
+                                       map: &'a hir_map::Map<'hir>)
+                                       -> NodesMatchingUII<'a> {
+        use UserIdentifiedItem::*;
+        use NodesMatchingUII::*;
+        match *self {
+            ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
+            ItemViaPath(ref parts) => {
+                NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts)))
+            }
+        }
+    }
+
+    pub fn to_one_node_id(self,
+                      user_option: &str,
+                      sess: &Session,
+                      map: &hir_map::Map<'_>)
+                      -> ast::NodeId {
+        let fail_because = |is_wrong_because| -> ast::NodeId {
+            let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
+                                   {}, which {}",
+                                  user_option,
+                                  self.reconstructed_input(),
+                                  is_wrong_because);
+            sess.fatal(&message)
+        };
+
+        let mut saw_node = ast::DUMMY_NODE_ID;
+        let mut seen = 0;
+        for node in self.all_matching_node_ids(map) {
+            saw_node = node;
+            seen += 1;
+            if seen > 1 {
+                fail_because("does not resolve uniquely");
+            }
+        }
+        if seen == 0 {
+            fail_because("does not resolve to any item");
+        }
+
+        assert!(seen == 1);
+        return saw_node;
+    }
+}
+
 /// Command-line arguments passed to the compiler have to be incorporated with
 /// the dependency tracking system for incremental compilation. This module
 /// provides some utilities to make this more convenient.
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 403b32df20e..bab7ab89ce7 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -21,7 +21,6 @@ use errors::{DiagnosticBuilder, DiagnosticId, Applicability};
 use errors::emitter::{Emitter, EmitterWriter};
 use errors::emitter::HumanReadableErrorType;
 use errors::annotate_snippet_emitter_writer::{AnnotateSnippetEmitterWriter};
-use syntax::ast::{self, NodeId};
 use syntax::edition::Edition;
 use syntax::expand::allocator::AllocatorKind;
 use syntax::feature_gate::{self, AttributeType};
@@ -38,7 +37,7 @@ use rustc_data_structures::jobserver;
 use ::jobserver::Client;
 
 use std;
-use std::cell::{self, Cell, RefCell};
+use std::cell::{self, RefCell};
 use std::env;
 use std::fmt;
 use std::io::Write;
@@ -127,8 +126,6 @@ pub struct Session {
     /// Data about code being compiled, gathered during compilation.
     pub code_stats: Lock<CodeStats>,
 
-    next_node_id: OneThread<Cell<ast::NodeId>>,
-
     /// If `-zfuel=crate=n` is specified, `Some(crate)`.
     optimization_fuel_crate: Option<String>,
 
@@ -355,21 +352,6 @@ impl Session {
         self.diagnostic().span_note_without_error(sp, msg)
     }
 
-    pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId {
-        let id = self.next_node_id.get();
-
-        match id.as_usize().checked_add(count) {
-            Some(next) => {
-                self.next_node_id.set(ast::NodeId::from_usize(next));
-            }
-            None => bug!("input too large; ran out of node-IDs!"),
-        }
-
-        id
-    }
-    pub fn next_node_id(&self) -> NodeId {
-        self.reserve_node_ids(1)
-    }
     pub fn diagnostic(&self) -> &errors::Handler {
         &self.parse_sess.span_diagnostic
     }
@@ -1187,7 +1169,6 @@ fn build_session_(
         recursion_limit: Once::new(),
         type_length_limit: Once::new(),
         const_eval_stack_frame_limit: 100,
-        next_node_id: OneThread::new(Cell::new(NodeId::from_u32(1))),
         allocator_kind: Once::new(),
         injected_panic_runtime: Once::new(),
         imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index a9e4e6db1c7..0a803187d49 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -27,5 +27,6 @@ rustc_save_analysis = { path = "../librustc_save_analysis" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_interface = { path = "../librustc_interface" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
+rustc_resolve = { path = "../librustc_resolve" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 47acf387f35..7973a804f1a 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -25,8 +25,6 @@ extern crate lazy_static;
 
 pub extern crate rustc_plugin_impl as plugin;
 
-use pretty::{PpMode, UserIdentifiedItem};
-
 //use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
@@ -285,33 +283,29 @@ pub fn run_compiler(
             return sess.compile_status();
         }
 
-        let pretty_info = parse_pretty(sess, &matches);
-
         compiler.parse()?;
 
-        if let Some((ppm, opt_uii)) = pretty_info {
+        if let Some((ppm, opt_uii)) = &sess.opts.pretty {
             if ppm.needs_ast_map(&opt_uii) {
-                pretty::visit_crate(sess, &mut compiler.parse()?.peek_mut(), ppm);
                 compiler.global_ctxt()?.peek_mut().enter(|tcx| {
                     let expanded_crate = compiler.expansion()?.take().0;
                     pretty::print_after_hir_lowering(
                         tcx,
                         compiler.input(),
                         &expanded_crate,
-                        ppm,
+                        *ppm,
                         opt_uii.clone(),
                         compiler.output_file().as_ref().map(|p| &**p),
                     );
                     Ok(())
                 })?;
             } else {
-                let mut krate = compiler.parse()?.take();
-                pretty::visit_crate(sess, &mut krate, ppm);
+                let krate = compiler.parse()?.take();
                 pretty::print_after_parsing(
                     sess,
                     &compiler.input(),
                     &krate,
-                    ppm,
+                    *ppm,
                     compiler.output_file().as_ref().map(|p| &**p),
                 );
             }
@@ -470,28 +464,6 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option
     }
 }
 
-fn parse_pretty(sess: &Session,
-                matches: &getopts::Matches)
-                -> Option<(PpMode, Option<UserIdentifiedItem>)> {
-    let pretty = if sess.opts.debugging_opts.unstable_options {
-        matches.opt_default("pretty", "normal").map(|a| {
-            // stable pretty-print variants only
-            pretty::parse_pretty(sess, &a, false)
-        })
-    } else {
-        None
-    };
-
-    if pretty.is_none() {
-        sess.opts.debugging_opts.unpretty.as_ref().map(|a| {
-            // extended with unstable pretty-print variants
-            pretty::parse_pretty(sess, &a, true)
-        })
-    } else {
-        pretty
-    }
-}
-
 // Whether to stop or continue compilation.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum Compilation {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 0de5b700b4f..23253dc4dad 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -5,117 +5,27 @@ use rustc::hir::map as hir_map;
 use rustc::hir::print as pprust_hir;
 use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::session::Session;
-use rustc::session::config::Input;
+use rustc::session::config::{PpMode, PpSourceMode, UserIdentifiedItem, Input};
 use rustc::ty::{self, TyCtxt};
 use rustc::util::common::ErrorReported;
-use rustc_interface::util::ReplaceBodyWithLoop;
 use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
 
 use syntax::ast;
-use syntax::mut_visit::MutVisitor;
 use syntax::print::{pprust};
 use syntax_pos::FileName;
 
 use std::cell::Cell;
 use std::fs::File;
 use std::io::Write;
-use std::option;
 use std::path::Path;
-use std::str::FromStr;
 
 pub use self::UserIdentifiedItem::*;
 pub use self::PpSourceMode::*;
 pub use self::PpMode::*;
-use self::NodesMatchingUII::*;
 use crate::abort_on_err;
 
 use crate::source_name;
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum PpSourceMode {
-    PpmNormal,
-    PpmEveryBodyLoops,
-    PpmExpanded,
-    PpmIdentified,
-    PpmExpandedIdentified,
-    PpmExpandedHygiene,
-    PpmTyped,
-}
-
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum PpMode {
-    PpmSource(PpSourceMode),
-    PpmHir(PpSourceMode),
-    PpmHirTree(PpSourceMode),
-    PpmMir,
-    PpmMirCFG,
-}
-
-impl PpMode {
-    pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool {
-        match *self {
-            PpmSource(PpmNormal) |
-            PpmSource(PpmEveryBodyLoops) |
-            PpmSource(PpmIdentified) => opt_uii.is_some(),
-
-            PpmSource(PpmExpanded) |
-            PpmSource(PpmExpandedIdentified) |
-            PpmSource(PpmExpandedHygiene) |
-            PpmHir(_) |
-            PpmHirTree(_) |
-            PpmMir |
-            PpmMirCFG => true,
-            PpmSource(PpmTyped) => panic!("invalid state"),
-        }
-    }
-
-    pub fn needs_analysis(&self) -> bool {
-        match *self {
-            PpmMir | PpmMirCFG => true,
-            _ => false,
-        }
-    }
-}
-
-pub fn parse_pretty(sess: &Session,
-                    name: &str,
-                    extended: bool)
-                    -> (PpMode, Option<UserIdentifiedItem>) {
-    let mut split = name.splitn(2, '=');
-    let first = split.next().unwrap();
-    let opt_second = split.next();
-    let first = match (first, extended) {
-        ("normal", _) => PpmSource(PpmNormal),
-        ("identified", _) => PpmSource(PpmIdentified),
-        ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
-        ("expanded", _) => PpmSource(PpmExpanded),
-        ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
-        ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
-        ("hir", true) => PpmHir(PpmNormal),
-        ("hir,identified", true) => PpmHir(PpmIdentified),
-        ("hir,typed", true) => PpmHir(PpmTyped),
-        ("hir-tree", true) => PpmHirTree(PpmNormal),
-        ("mir", true) => PpmMir,
-        ("mir-cfg", true) => PpmMirCFG,
-        _ => {
-            if extended {
-                sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \
-                                     `expanded`, `identified`, `expanded,identified`, \
-                                     `expanded,hygiene`, `everybody_loops`, \
-                                     `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
-                                     `mir` or `mir-cfg`; got {}",
-                                    name));
-            } else {
-                sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \
-                                     `identified`, or `expanded,identified`; got {}",
-                                    name));
-            }
-        }
-    };
-    let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok());
-    (first, opt_second)
-}
-
 
 
 // This slightly awkward construction is to allow for each PpMode to
@@ -131,76 +41,74 @@ pub fn parse_pretty(sess: &Session,
 // (The `use_once_payload` is working around the current lack of once
 // functions in the compiler.)
 
-impl PpSourceMode {
-    /// Constructs a `PrinterSupport` object and passes it to `f`.
-    fn call_with_pp_support<'tcx, A, F>(
-        &self,
-        sess: &'tcx Session,
-        tcx: Option<TyCtxt<'tcx>>,
-        f: F,
-    ) -> A
-    where
-        F: FnOnce(&dyn PrinterSupport) -> A,
-    {
-        match *self {
-            PpmNormal | PpmEveryBodyLoops | PpmExpanded => {
-                let annotation = NoAnn {
-                    sess,
-                    tcx,
-                };
-                f(&annotation)
-            }
+/// Constructs a `PrinterSupport` object and passes it to `f`.
+fn call_with_pp_support<'tcx, A, F>(
+    ppmode: &PpSourceMode,
+    sess: &'tcx Session,
+    tcx: Option<TyCtxt<'tcx>>,
+    f: F,
+) -> A
+where
+    F: FnOnce(&dyn PrinterSupport) -> A,
+{
+    match *ppmode {
+        PpmNormal | PpmEveryBodyLoops | PpmExpanded => {
+            let annotation = NoAnn {
+                sess,
+                tcx,
+            };
+            f(&annotation)
+        }
 
-            PpmIdentified | PpmExpandedIdentified => {
-                let annotation = IdentifiedAnnotation {
-                    sess,
-                    tcx,
-                };
-                f(&annotation)
-            }
-            PpmExpandedHygiene => {
-                let annotation = HygieneAnnotation {
-                    sess,
-                };
-                f(&annotation)
-            }
-            _ => panic!("Should use call_with_pp_support_hir"),
+        PpmIdentified | PpmExpandedIdentified => {
+            let annotation = IdentifiedAnnotation {
+                sess,
+                tcx,
+            };
+            f(&annotation)
+        }
+        PpmExpandedHygiene => {
+            let annotation = HygieneAnnotation {
+                sess,
+            };
+            f(&annotation)
+        }
+        _ => panic!("Should use call_with_pp_support_hir"),
+    }
+}
+fn call_with_pp_support_hir<A, F>(ppmode: &PpSourceMode, tcx: TyCtxt<'_>, f: F) -> A
+where
+    F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate) -> A,
+{
+    match *ppmode {
+        PpmNormal => {
+            let annotation = NoAnn {
+                sess: tcx.sess,
+                tcx: Some(tcx),
+            };
+            f(&annotation, tcx.hir().forest.krate())
         }
-    }
-    fn call_with_pp_support_hir<A, F>(&self, tcx: TyCtxt<'_>, f: F) -> A
-    where
-        F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate) -> A,
-    {
-        match *self {
-            PpmNormal => {
-                let annotation = NoAnn {
-                    sess: tcx.sess,
-                    tcx: Some(tcx),
-                };
-                f(&annotation, tcx.hir().forest.krate())
-            }
 
-            PpmIdentified => {
-                let annotation = IdentifiedAnnotation {
-                    sess: tcx.sess,
-                    tcx: Some(tcx),
-                };
+        PpmIdentified => {
+            let annotation = IdentifiedAnnotation {
+                sess: tcx.sess,
+                tcx: Some(tcx),
+            };
+            f(&annotation, tcx.hir().forest.krate())
+        }
+        PpmTyped => {
+            abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
+
+            let empty_tables = ty::TypeckTables::empty(None);
+            let annotation = TypedAnnotation {
+                tcx,
+                tables: Cell::new(&empty_tables)
+            };
+            tcx.dep_graph.with_ignore(|| {
                 f(&annotation, tcx.hir().forest.krate())
-            }
-            PpmTyped => {
-                abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
-
-                let empty_tables = ty::TypeckTables::empty(None);
-                let annotation = TypedAnnotation {
-                    tcx,
-                    tables: Cell::new(&empty_tables)
-                };
-                tcx.dep_graph.with_ignore(|| {
-                    f(&annotation, tcx.hir().forest.krate())
-                })
-            }
-            _ => panic!("Should use call_with_pp_support"),
+            })
         }
+        _ => panic!("Should use call_with_pp_support"),
     }
 }
 
@@ -482,102 +390,6 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
     }
 }
 
-#[derive(Clone, Debug)]
-pub enum UserIdentifiedItem {
-    ItemViaNode(ast::NodeId),
-    ItemViaPath(Vec<String>),
-}
-
-impl FromStr for UserIdentifiedItem {
-    type Err = ();
-    fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
-        Ok(s.parse()
-            .map(ast::NodeId::from_u32)
-            .map(ItemViaNode)
-            .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
-    }
-}
-
-enum NodesMatchingUII<'a> {
-    NodesMatchingDirect(option::IntoIter<ast::NodeId>),
-    NodesMatchingSuffix(Box<dyn Iterator<Item = ast::NodeId> + 'a>),
-}
-
-impl<'a> Iterator for NodesMatchingUII<'a> {
-    type Item = ast::NodeId;
-
-    fn next(&mut self) -> Option<ast::NodeId> {
-        match self {
-            &mut NodesMatchingDirect(ref mut iter) => iter.next(),
-            &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match self {
-            &NodesMatchingDirect(ref iter) => iter.size_hint(),
-            &NodesMatchingSuffix(ref iter) => iter.size_hint(),
-        }
-    }
-}
-
-impl UserIdentifiedItem {
-    fn reconstructed_input(&self) -> String {
-        match *self {
-            ItemViaNode(node_id) => node_id.to_string(),
-            ItemViaPath(ref parts) => parts.join("::"),
-        }
-    }
-
-    fn all_matching_node_ids<'a, 'hir>(&'a self,
-                                       map: &'a hir_map::Map<'hir>)
-                                       -> NodesMatchingUII<'a> {
-        match *self {
-            ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
-            ItemViaPath(ref parts) => {
-                NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts)))
-            }
-        }
-    }
-
-    fn to_one_node_id(self,
-                      user_option: &str,
-                      sess: &Session,
-                      map: &hir_map::Map<'_>)
-                      -> ast::NodeId {
-        let fail_because = |is_wrong_because| -> ast::NodeId {
-            let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
-                                   {}, which {}",
-                                  user_option,
-                                  self.reconstructed_input(),
-                                  is_wrong_because);
-            sess.fatal(&message)
-        };
-
-        let mut saw_node = ast::DUMMY_NODE_ID;
-        let mut seen = 0;
-        for node in self.all_matching_node_ids(map) {
-            saw_node = node;
-            seen += 1;
-            if seen > 1 {
-                fail_because("does not resolve uniquely");
-            }
-        }
-        if seen == 0 {
-            fail_because("does not resolve to any item");
-        }
-
-        assert!(seen == 1);
-        return saw_node;
-    }
-}
-
-pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) {
-    if let PpmSource(PpmEveryBodyLoops) = ppm {
-        ReplaceBodyWithLoop::new(sess).visit_crate(krate);
-    }
-}
-
 fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
     let src_name = source_name(input);
     let src = String::clone(&sess.source_map()
@@ -613,7 +425,7 @@ pub fn print_after_parsing(sess: &Session,
     if let PpmSource(s) = ppm {
         // Silently ignores an identified node.
         let out = &mut out;
-        s.call_with_pp_support(sess, None, move |annotation| {
+        call_with_pp_support(&s, sess, None, move |annotation| {
             debug!("pretty printing source code {:?}", s);
             let sess = annotation.sess();
             *out = pprust::print_crate(sess.source_map(),
@@ -658,7 +470,7 @@ pub fn print_after_hir_lowering<'tcx>(
                 // Silently ignores an identified node.
                 let out = &mut out;
                 let src = src.clone();
-                s.call_with_pp_support(tcx.sess, Some(tcx), move |annotation| {
+                call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     *out = pprust::print_crate(sess.source_map(),
@@ -674,7 +486,7 @@ pub fn print_after_hir_lowering<'tcx>(
             (PpmHir(s), None) => {
                 let out = &mut out;
                 let src = src.clone();
-                s.call_with_pp_support_hir(tcx, move |annotation, krate| {
+                call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     *out = pprust_hir::print_crate(sess.source_map(),
@@ -688,7 +500,7 @@ pub fn print_after_hir_lowering<'tcx>(
 
             (PpmHirTree(s), None) => {
                 let out = &mut out;
-                s.call_with_pp_support_hir(tcx, move |_annotation, krate| {
+                call_with_pp_support_hir(&s, tcx, move |_annotation, krate| {
                     debug!("pretty printing source code {:?}", s);
                     *out = format!("{:#?}", krate);
                 });
@@ -697,7 +509,7 @@ pub fn print_after_hir_lowering<'tcx>(
             (PpmHir(s), Some(uii)) => {
                 let out = &mut out;
                 let src = src.clone();
-                s.call_with_pp_support_hir(tcx, move |annotation, _| {
+                call_with_pp_support_hir(&s, tcx, move |annotation, _| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     let hir_map = annotation.hir_map().expect("-Z unpretty missing HIR map");
@@ -722,7 +534,7 @@ pub fn print_after_hir_lowering<'tcx>(
 
             (PpmHirTree(s), Some(uii)) => {
                 let out = &mut out;
-                s.call_with_pp_support_hir(tcx, move |_annotation, _krate| {
+                call_with_pp_support_hir(&s, tcx, move |_annotation, _krate| {
                     debug!("pretty printing source code {:?}", s);
                     for node_id in uii.all_matching_node_ids(tcx.hir()) {
                         let hir_id = tcx.hir().node_to_hir_id(node_id);
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index ce34caee6fa..04a0b0e7619 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -16,6 +16,7 @@ use rustc::traits;
 use rustc::util::common::{time, ErrorReported};
 use rustc::session::Session;
 use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType};
+use rustc::session::config::{PpMode, PpSourceMode};
 use rustc::session::search_paths::PathKind;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
@@ -394,8 +395,12 @@ fn configure_and_expand_inner<'a>(
 
     // If we're actually rustdoc then there's no need to actually compile
     // anything, so switch everything to just looping
-    if sess.opts.actually_rustdoc {
-        util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate);
+    let mut should_loop = sess.opts.actually_rustdoc;
+    if let Some((PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops), _)) = sess.opts.pretty {
+        should_loop |= true;
+    }
+    if should_loop {
+        util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
     }
 
     let has_proc_macro_decls = time(sess, "AST validation", || {
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index a74ea4bca39..0c08f65d11d 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -18,7 +18,7 @@ use rustc_mir;
 use rustc_passes;
 use rustc_plugin;
 use rustc_privacy;
-use rustc_resolve;
+use rustc_resolve::{self, Resolver};
 use rustc_typeck;
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
@@ -715,18 +715,18 @@ pub fn build_output_filenames(
 //    ambitious form of the closed RFC #1637. See also [#34511].
 //
 // [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401
-pub struct ReplaceBodyWithLoop<'a> {
+pub struct ReplaceBodyWithLoop<'a, 'b> {
     within_static_or_const: bool,
     nested_blocks: Option<Vec<ast::Block>>,
-    sess: &'a Session,
+    resolver: &'a mut Resolver<'b>,
 }
 
-impl<'a> ReplaceBodyWithLoop<'a> {
-    pub fn new(sess: &'a Session) -> ReplaceBodyWithLoop<'a> {
+impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
+    pub fn new(resolver: &'a mut Resolver<'b>) -> ReplaceBodyWithLoop<'a, 'b> {
         ReplaceBodyWithLoop {
             within_static_or_const: false,
             nested_blocks: None,
-            sess
+            resolver,
         }
     }
 
@@ -788,11 +788,12 @@ impl<'a> ReplaceBodyWithLoop<'a> {
     }
 
     fn is_sig_const(sig: &ast::FnSig) -> bool {
-        sig.header.constness.node == ast::Constness::Const || Self::should_ignore_fn(&sig.decl)
+        sig.header.constness.node == ast::Constness::Const ||
+            ReplaceBodyWithLoop::should_ignore_fn(&sig.decl)
     }
 }
 
-impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> {
+impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
     fn visit_item_kind(&mut self, i: &mut ast::ItemKind) {
         let is_const = match i {
             ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
@@ -827,40 +828,40 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> {
     fn visit_block(&mut self, b: &mut P<ast::Block>) {
         fn stmt_to_block(rules: ast::BlockCheckMode,
                          s: Option<ast::Stmt>,
-                         sess: &Session) -> ast::Block {
+                         resolver: &mut Resolver<'_>) -> ast::Block {
             ast::Block {
                 stmts: s.into_iter().collect(),
                 rules,
-                id: sess.next_node_id(),
+                id: resolver.next_node_id(),
                 span: syntax_pos::DUMMY_SP,
             }
         }
 
-        fn block_to_stmt(b: ast::Block, sess: &Session) -> ast::Stmt {
+        fn block_to_stmt(b: ast::Block, resolver: &mut Resolver<'_>) -> ast::Stmt {
             let expr = P(ast::Expr {
-                id: sess.next_node_id(),
+                id: resolver.next_node_id(),
                 kind: ast::ExprKind::Block(P(b), None),
                 span: syntax_pos::DUMMY_SP,
                 attrs: ThinVec::new(),
             });
 
             ast::Stmt {
-                id: sess.next_node_id(),
+                id: resolver.next_node_id(),
                 kind: ast::StmtKind::Expr(expr),
                 span: syntax_pos::DUMMY_SP,
             }
         }
 
-        let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.sess);
+        let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.resolver);
         let loop_expr = P(ast::Expr {
             kind: ast::ExprKind::Loop(P(empty_block), None),
-            id: self.sess.next_node_id(),
+            id: self.resolver.next_node_id(),
             span: syntax_pos::DUMMY_SP,
                 attrs: ThinVec::new(),
         });
 
         let loop_stmt = ast::Stmt {
-            id: self.sess.next_node_id(),
+            id: self.resolver.next_node_id(),
             span: syntax_pos::DUMMY_SP,
             kind: ast::StmtKind::Expr(loop_expr),
         };
@@ -878,7 +879,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> {
                     // we put a Some in there earlier with that replace(), so this is valid
                     let new_blocks = self.nested_blocks.take().unwrap();
                     self.nested_blocks = old_blocks;
-                    stmts.extend(new_blocks.into_iter().map(|b| block_to_stmt(b, &self.sess)));
+                    stmts.extend(new_blocks.into_iter().map(|b| block_to_stmt(b, self.resolver)));
                 }
 
                 let mut new_block = ast::Block {
@@ -892,7 +893,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> {
                         old_blocks.push(new_block);
                     }
 
-                    stmt_to_block(b.rules, Some(loop_stmt), self.sess)
+                    stmt_to_block(b.rules, Some(loop_stmt), &mut self.resolver)
                 } else {
                     //push `loop {}` onto the end of our fresh block and yield that
                     new_block.stmts.push(loop_stmt);
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 4239518b879..1ce356d4891 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -449,7 +449,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                                     name: kw::PathRoot,
                                     span: source.ident.span,
                                 },
-                                id: Some(self.r.session.next_node_id()),
+                                id: Some(self.r.next_node_id()),
                             });
                             source.ident.name = crate_name;
                         }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 5c996bffb9a..e94b544582e 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -961,6 +961,8 @@ pub struct Resolver<'a> {
     variant_vis: DefIdMap<ty::Visibility>,
 
     lint_buffer: lint::LintBuffer,
+
+    next_node_id: NodeId,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1078,6 +1080,10 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
     fn lint_buffer(&mut self) -> &mut lint::LintBuffer {
         &mut self.lint_buffer
     }
+
+    fn next_node_id(&mut self) -> NodeId {
+        self.next_node_id()
+    }
 }
 
 impl<'a> Resolver<'a> {
@@ -1226,9 +1232,18 @@ impl<'a> Resolver<'a> {
                     .collect(),
             variant_vis: Default::default(),
             lint_buffer: lint::LintBuffer::default(),
+            next_node_id: NodeId::from_u32(1),
         }
     }
 
+    pub fn next_node_id(&mut self) -> NodeId {
+        let next = self.next_node_id.as_usize()
+            .checked_add(1)
+            .expect("input too large; ran out of NodeIds");
+        self.next_node_id = ast::NodeId::from_usize(next);
+        self.next_node_id
+    }
+
     pub fn lint_buffer(&mut self) -> &mut lint::LintBuffer {
         &mut self.lint_buffer
     }
@@ -2827,9 +2842,9 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
+    fn new_ast_path_segment(&mut self, ident: Ident) -> ast::PathSegment {
         let mut seg = ast::PathSegment::from_ident(ident);
-        seg.id = self.session.next_node_id();
+        seg.id = self.next_node_id();
         seg
     }
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3d5a7f26eda..cc811d3b59a 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -95,7 +95,7 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
 
 impl<'a> base::Resolver for Resolver<'a> {
     fn next_node_id(&mut self) -> NodeId {
-        self.session.next_node_id()
+        self.next_node_id()
     }
 
     fn resolve_dollar_crates(&mut self) {