about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-07-10 23:02:44 +0000
committerbors <bors@rust-lang.org>2019-07-10 23:02:44 +0000
commit35cacbce1661366250a877da4fa5b6b4cb03542e (patch)
tree345ce24b5fe515e9b8db95f0971244464326073a /src
parentcd2cd4c9627e52c33e68e8c93a8916dc11094cbb (diff)
parent3c299a987cfd9522c4e1f6e53ed79123b4a4acab (diff)
downloadrust-35cacbce1661366250a877da4fa5b6b4cb03542e.tar.gz
rust-35cacbce1661366250a877da4fa5b6b4cb03542e.zip
Auto merge of #62561 - Centril:rollup-5pxj3bo, r=Centril
Rollup of 5 pull requests

Successful merges:

 - #62275 (rustc_mir: treat DropAndReplace as Drop + Assign in qualify_consts.)
 - #62465 (Sometimes generate storage statements for temporaries with type `!`)
 - #62481 (Use `fold` in `Iterator::last` default implementation)
 - #62493 (#62357: doc(ptr): add example for {read,write}_unaligned)
 - #62532 (Some more cleanups to syntax::print)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/libcore/iter/traits/iterator.rs4
-rw-r--r--src/libcore/ptr/mod.rs32
-rw-r--r--src/librustc/hir/map/mod.rs4
-rw-r--r--src/librustc/hir/print.rs184
-rw-r--r--src/librustc_borrowck/dataflow.rs3
-rw-r--r--src/librustc_driver/pretty.rs34
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_mir/build/expr/as_place.rs10
-rw-r--r--src/librustc_mir/build/expr/as_temp.rs65
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs23
-rw-r--r--src/libsyntax/ast.rs8
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libsyntax/parse/diagnostics.rs2
-rw-r--r--src/libsyntax/parse/lexer/comments.rs5
-rw-r--r--src/libsyntax/parse/literal.rs2
-rw-r--r--src/libsyntax/parse/parser.rs5
-rw-r--r--src/libsyntax/parse/token.rs30
-rw-r--r--src/libsyntax/print/helpers.rs34
-rw-r--r--src/libsyntax/print/pp.rs136
-rw-r--r--src/libsyntax/print/pprust.rs385
-rw-r--r--src/test/mir-opt/loop_test.rs1
-rw-r--r--src/test/ui/borrowck/assign-never-type.rs14
-rw-r--r--src/test/ui/consts/const-eval/const_let.rs15
-rw-r--r--src/test/ui/consts/const-eval/const_let.stderr27
24 files changed, 505 insertions, 521 deletions
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index 6eddac672c1..7e941267ce8 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -263,9 +263,7 @@ pub trait Iterator {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn last(self) -> Option<Self::Item> where Self: Sized {
-        let mut last = None;
-        for x in self { last = Some(x); }
-        last
+        self.fold(None, |_, x| Some(x))
     }
 
     /// Returns the `n`th element of the iterator.
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 2a6c2b1331e..df66a2978de 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -669,6 +669,22 @@ pub unsafe fn read<T>(src: *const T) -> T {
 ///
 /// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
 // FIXME: Update docs based on outcome of RFC #2582 and friends.
+///
+/// # Examples
+///
+/// Read an usize value from a byte buffer:
+///
+/// ```
+/// use std::mem;
+///
+/// fn read_usize(x: &[u8]) -> usize {
+///     assert!(x.len() >= mem::size_of::<usize>());
+///
+///     let ptr = x.as_ptr() as *const usize;
+///
+///     unsafe { ptr.read_unaligned() }
+/// }
+/// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn read_unaligned<T>(src: *const T) -> T {
@@ -839,6 +855,22 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 ///
 /// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
 // FIXME: Update docs based on outcome of RFC #2582 and friends.
+///
+/// # Examples
+///
+/// Write an usize value to a byte buffer:
+///
+/// ```
+/// use std::mem;
+///
+/// fn write_usize(x: &mut [u8], val: usize) {
+///     assert!(x.len() >= mem::size_of::<usize>());
+///
+///     let ptr = x.as_mut_ptr() as *mut usize;
+///
+///     unsafe { ptr.write_unaligned(val) }
+/// }
+/// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 63f60d0ab95..9fb85410fc7 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -1212,10 +1212,8 @@ impl<'a> print::State<'a> {
             Node::Pat(a)          => self.print_pat(&a),
             Node::Arm(a)          => self.print_arm(&a),
             Node::Block(a)        => {
-                use syntax::print::pprust::PrintState;
-
                 // containing cbox, will be closed by print-block at }
-                self.cbox(print::indent_unit);
+                self.cbox(print::INDENT_UNIT);
                 // head-ibox, will be closed by print-block after {
                 self.ibox(0);
                 self.print_block(&a)
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 6817107635a..5a14b30e699 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -2,10 +2,9 @@ use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::source_map::{SourceMap, Spanned};
 use syntax::parse::ParseSess;
-use syntax::parse::lexer::comments;
 use syntax::print::pp::{self, Breaks};
 use syntax::print::pp::Breaks::{Consistent, Inconsistent};
-use syntax::print::pprust::{self, PrintState};
+use syntax::print::pprust::{Comments, PrintState};
 use syntax::symbol::kw;
 use syntax::util::parser::{self, AssocOp, Fixity};
 use syntax_pos::{self, BytePos, FileName};
@@ -17,7 +16,6 @@ use crate::hir::ptr::P;
 
 use std::borrow::Cow;
 use std::cell::Cell;
-use std::io::Read;
 use std::vec;
 
 pub enum AnnNode<'a> {
@@ -70,34 +68,31 @@ impl PpAnn for hir::Crate {
 }
 
 pub struct State<'a> {
-    pub s: pp::Printer<'a>,
-    cm: Option<&'a SourceMap>,
-    comments: Option<Vec<comments::Comment>>,
-    cur_cmnt: usize,
-    boxes: Vec<pp::Breaks>,
+    pub s: pp::Printer,
+    comments: Option<Comments<'a>>,
     ann: &'a (dyn PpAnn + 'a),
 }
 
-impl<'a> PrintState<'a> for State<'a> {
-    fn writer(&mut self) -> &mut pp::Printer<'a> {
-        &mut self.s
+impl std::ops::Deref for State<'_> {
+    type Target = pp::Printer;
+    fn deref(&self) -> &Self::Target {
+        &self.s
     }
+}
 
-    fn boxes(&mut self) -> &mut Vec<pp::Breaks> {
-        &mut self.boxes
+impl std::ops::DerefMut for State<'_> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.s
     }
+}
 
-    fn comments(&mut self) -> &mut Option<Vec<comments::Comment>> {
+impl<'a> PrintState<'a> for State<'a> {
+    fn comments(&mut self) -> &mut Option<Comments<'a>> {
         &mut self.comments
     }
-
-    fn cur_cmnt(&mut self) -> &mut usize {
-        &mut self.cur_cmnt
-    }
 }
 
-#[allow(non_upper_case_globals)]
-pub const indent_unit: usize = 4;
+pub const INDENT_UNIT: usize = 4;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments to copy forward.
@@ -105,11 +100,9 @@ pub fn print_crate<'a>(cm: &'a SourceMap,
                        sess: &ParseSess,
                        krate: &hir::Crate,
                        filename: FileName,
-                       input: &mut dyn Read,
-                       out: &'a mut String,
-                       ann: &'a dyn PpAnn)
-                       {
-    let mut s = State::new_from_input(cm, sess, filename, input, out, ann);
+                       input: String,
+                       ann: &'a dyn PpAnn) -> String {
+    let mut s = State::new_from_input(cm, sess, filename, input, ann);
 
     // When printing the AST, we sometimes need to inject `#[no_std]` here.
     // Since you can't compile the HIR, it's not necessary.
@@ -123,25 +116,12 @@ impl<'a> State<'a> {
     pub fn new_from_input(cm: &'a SourceMap,
                           sess: &ParseSess,
                           filename: FileName,
-                          input: &mut dyn Read,
-                          out: &'a mut String,
+                          input: String,
                           ann: &'a dyn PpAnn)
                           -> State<'a> {
-        let comments = comments::gather_comments(sess, filename, input);
-        State::new(cm, out, ann, Some(comments))
-    }
-
-    pub fn new(cm: &'a SourceMap,
-               out: &'a mut String,
-               ann: &'a dyn PpAnn,
-               comments: Option<Vec<comments::Comment>>)
-               -> State<'a> {
         State {
-            s: pp::mk_printer(out),
-            cm: Some(cm),
-            comments,
-            cur_cmnt: 0,
-            boxes: Vec::new(),
+            s: pp::mk_printer(),
+            comments: Some(Comments::new(cm, sess, filename, input)),
             ann,
         }
     }
@@ -150,20 +130,13 @@ impl<'a> State<'a> {
 pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
     where F: FnOnce(&mut State<'_>)
 {
-    let mut wr = String::new();
-    {
-        let mut printer = State {
-            s: pp::mk_printer(&mut wr),
-            cm: None,
-            comments: None,
-            cur_cmnt: 0,
-            boxes: Vec::new(),
-            ann,
-        };
-        f(&mut printer);
-        printer.s.eof();
-    }
-    wr
+    let mut printer = State {
+        s: pp::mk_printer(),
+        comments: None,
+        ann,
+    };
+    f(&mut printer);
+    printer.s.eof()
 }
 
 pub fn visibility_qualified<S: Into<Cow<'static, str>>>(vis: &hir::Visibility, w: S) -> String {
@@ -175,7 +148,6 @@ pub fn visibility_qualified<S: Into<Cow<'static, str>>>(vis: &hir::Visibility, w
 
 impl<'a> State<'a> {
     pub fn cbox(&mut self, u: usize) {
-        self.boxes.push(pp::Breaks::Consistent);
         self.s.cbox(u);
     }
 
@@ -191,7 +163,7 @@ impl<'a> State<'a> {
     pub fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
         let w = w.into();
         // outer-box is consistent
-        self.cbox(indent_unit);
+        self.cbox(INDENT_UNIT);
         // head-box is inconsistent
         self.ibox(w.len() + 1);
         // keyword that starts the head
@@ -205,17 +177,12 @@ impl<'a> State<'a> {
         self.end(); // close the head-box
     }
 
-    pub fn bclose_(&mut self, span: syntax_pos::Span, indented: usize) {
-        self.bclose_maybe_open(span, indented, true)
-    }
-
     pub fn bclose_maybe_open(&mut self,
                              span: syntax_pos::Span,
-                             indented: usize,
                              close_box: bool)
                              {
         self.maybe_print_comment(span.hi());
-        self.break_offset_if_not_bol(1, -(indented as isize));
+        self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
         self.s.word("}");
         if close_box {
             self.end(); // close the outer-box
@@ -223,24 +190,17 @@ impl<'a> State<'a> {
     }
 
     pub fn bclose(&mut self, span: syntax_pos::Span) {
-        self.bclose_(span, indent_unit)
-    }
-
-    pub fn in_cbox(&self) -> bool {
-        match self.boxes.last() {
-            Some(&last_box) => last_box == pp::Breaks::Consistent,
-            None => false,
-        }
+        self.bclose_maybe_open(span, true)
     }
 
     pub fn space_if_not_bol(&mut self) {
-        if !self.is_bol() {
+        if !self.s.is_beginning_of_line() {
             self.s.space();
         }
     }
 
     pub fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
-        if !self.is_bol() {
+        if !self.s.is_beginning_of_line() {
             self.s.break_offset(n, off)
         } else {
             if off != 0 && self.s.last_token().is_hardbreak_tok() {
@@ -766,7 +726,7 @@ impl<'a> State<'a> {
             self.space_if_not_bol();
             self.maybe_print_comment(v.span.lo());
             self.print_outer_attributes(&v.node.attrs);
-            self.ibox(indent_unit);
+            self.ibox(INDENT_UNIT);
             self.print_variant(v);
             self.s.word(",");
             self.end();
@@ -953,10 +913,10 @@ impl<'a> State<'a> {
         decl: impl Fn(&mut Self)
     ) {
         self.space_if_not_bol();
-        self.ibox(indent_unit);
+        self.ibox(INDENT_UNIT);
         self.word_nbsp("let");
 
-        self.ibox(indent_unit);
+        self.ibox(INDENT_UNIT);
         decl(self);
         self.end();
 
@@ -998,26 +958,18 @@ impl<'a> State<'a> {
     }
 
     pub fn print_block_unclosed(&mut self, blk: &hir::Block) {
-        self.print_block_unclosed_indent(blk, indent_unit)
-    }
-
-    pub fn print_block_unclosed_indent(&mut self,
-                                       blk: &hir::Block,
-                                       indented: usize)
-                                       {
-        self.print_block_maybe_unclosed(blk, indented, &[], false)
+        self.print_block_maybe_unclosed(blk, &[], false)
     }
 
     pub fn print_block_with_attrs(&mut self,
                                   blk: &hir::Block,
                                   attrs: &[ast::Attribute])
                                   {
-        self.print_block_maybe_unclosed(blk, indent_unit, attrs, true)
+        self.print_block_maybe_unclosed(blk, attrs, true)
     }
 
     pub fn print_block_maybe_unclosed(&mut self,
                                       blk: &hir::Block,
-                                      indented: usize,
                                       attrs: &[ast::Attribute],
                                       close_box: bool)
                                       {
@@ -1041,7 +993,7 @@ impl<'a> State<'a> {
             self.print_expr(&expr);
             self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
         }
-        self.bclose_maybe_open(blk.span, indented, close_box);
+        self.bclose_maybe_open(blk.span, close_box);
         self.ann.post(self, AnnNode::Block(blk))
     }
 
@@ -1089,7 +1041,7 @@ impl<'a> State<'a> {
     }
 
     fn print_expr_vec(&mut self, exprs: &[hir::Expr]) {
-        self.ibox(indent_unit);
+        self.ibox(INDENT_UNIT);
         self.s.word("[");
         self.commasep_exprs(Inconsistent, exprs);
         self.s.word("]");
@@ -1097,7 +1049,7 @@ impl<'a> State<'a> {
     }
 
     fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::AnonConst) {
-        self.ibox(indent_unit);
+        self.ibox(INDENT_UNIT);
         self.s.word("[");
         self.print_expr(element);
         self.word_space(";");
@@ -1116,7 +1068,7 @@ impl<'a> State<'a> {
         self.commasep_cmnt(Consistent,
                            &fields[..],
                            |s, field| {
-                               s.ibox(indent_unit);
+                               s.ibox(INDENT_UNIT);
                                if !field.is_shorthand {
                                     s.print_ident(field.ident);
                                     s.word_space(":");
@@ -1127,7 +1079,7 @@ impl<'a> State<'a> {
                            |f| f.span);
         match *wth {
             Some(ref expr) => {
-                self.ibox(indent_unit);
+                self.ibox(INDENT_UNIT);
                 if !fields.is_empty() {
                     self.s.word(",");
                     self.s.space();
@@ -1226,13 +1178,13 @@ impl<'a> State<'a> {
 
     fn print_literal(&mut self, lit: &hir::Lit) {
         self.maybe_print_comment(lit.span.lo());
-        self.writer().word(pprust::literal_to_string(lit.node.to_lit_token()))
+        self.word(lit.node.to_lit_token().to_string())
     }
 
     pub fn print_expr(&mut self, expr: &hir::Expr) {
         self.maybe_print_comment(expr.span.lo());
         self.print_outer_attributes(&expr.attrs);
-        self.ibox(indent_unit);
+        self.ibox(INDENT_UNIT);
         self.ann.pre(self, AnnNode::Expr(expr));
         match expr.node {
             hir::ExprKind::Box(ref expr) => {
@@ -1284,7 +1236,7 @@ impl<'a> State<'a> {
             }
             hir::ExprKind::DropTemps(ref init) => {
                 // Print `{`:
-                self.cbox(indent_unit);
+                self.cbox(INDENT_UNIT);
                 self.ibox(0);
                 self.bopen();
 
@@ -1298,7 +1250,7 @@ impl<'a> State<'a> {
                 self.print_ident(temp);
 
                 // Print `}`:
-                self.bclose_maybe_open(expr.span, indent_unit, true);
+                self.bclose_maybe_open(expr.span, true);
             }
             hir::ExprKind::Loop(ref blk, opt_label, _) => {
                 if let Some(label) = opt_label {
@@ -1310,8 +1262,8 @@ impl<'a> State<'a> {
                 self.print_block(&blk);
             }
             hir::ExprKind::Match(ref expr, ref arms, _) => {
-                self.cbox(indent_unit);
-                self.ibox(4);
+                self.cbox(INDENT_UNIT);
+                self.ibox(INDENT_UNIT);
                 self.word_nbsp("match");
                 self.print_expr_as_cond(&expr);
                 self.s.space();
@@ -1319,7 +1271,7 @@ impl<'a> State<'a> {
                 for arm in arms {
                     self.print_arm(arm);
                 }
-                self.bclose_(expr.span, indent_unit);
+                self.bclose(expr.span);
             }
             hir::ExprKind::Closure(capture_clause, ref decl, body, _fn_decl_span, _gen) => {
                 self.print_capture_clause(capture_clause);
@@ -1342,7 +1294,7 @@ impl<'a> State<'a> {
                     self.word_space(":");
                 }
                 // containing cbox, will be closed by print-block at }
-                self.cbox(indent_unit);
+                self.cbox(INDENT_UNIT);
                 // head-box, will be closed by print-block after {
                 self.ibox(0);
                 self.print_block(&blk);
@@ -1712,7 +1664,7 @@ impl<'a> State<'a> {
                 self.commasep_cmnt(Consistent,
                                    &fields[..],
                                    |s, f| {
-                                       s.cbox(indent_unit);
+                                       s.cbox(INDENT_UNIT);
                                        if !f.node.is_shorthand {
                                            s.print_ident(f.node.ident);
                                            s.word_nbsp(":");
@@ -1821,7 +1773,7 @@ impl<'a> State<'a> {
         if arm.attrs.is_empty() {
             self.s.space();
         }
-        self.cbox(indent_unit);
+        self.cbox(INDENT_UNIT);
         self.ann.pre(self, AnnNode::Arm(arm));
         self.ibox(0);
         self.print_outer_attributes(&arm.attrs);
@@ -1854,7 +1806,7 @@ impl<'a> State<'a> {
                     self.word_space(":");
                 }
                 // the block will close the pattern's ibox
-                self.print_block_unclosed_indent(&blk, indent_unit);
+                self.print_block_unclosed(&blk);
 
                 // If it is a user-provided unsafe block, print a comma after it
                 if let hir::UnsafeBlock(hir::UserProvided) = blk.rules {
@@ -1893,7 +1845,7 @@ impl<'a> State<'a> {
         // Make sure we aren't supplied *both* `arg_names` and `body_id`.
         assert!(arg_names.is_empty() || body_id.is_none());
         self.commasep(Inconsistent, &decl.inputs, |s, ty| {
-            s.ibox(indent_unit);
+            s.ibox(INDENT_UNIT);
             if let Some(arg_name) = arg_names.get(i) {
                 s.s.word(arg_name.as_str().to_string());
                 s.s.word(":");
@@ -1920,7 +1872,7 @@ impl<'a> State<'a> {
         self.s.word("|");
         let mut i = 0;
         self.commasep(Inconsistent, &decl.inputs, |s, ty| {
-            s.ibox(indent_unit);
+            s.ibox(INDENT_UNIT);
 
             s.ann.nested(s, Nested::BodyArgPat(body_id, i));
             i += 1;
@@ -2119,7 +2071,7 @@ impl<'a> State<'a> {
         }
 
         self.space_if_not_bol();
-        self.ibox(indent_unit);
+        self.ibox(INDENT_UNIT);
         self.word_space("->");
         match decl.output {
             hir::DefaultReturn(..) => unreachable!(),
@@ -2141,7 +2093,7 @@ impl<'a> State<'a> {
                        generic_params: &[hir::GenericParam],
                        arg_names: &[ast::Ident])
                        {
-        self.ibox(indent_unit);
+        self.ibox(INDENT_UNIT);
         if !generic_params.is_empty() {
             self.s.word("for");
             self.print_generic_params(generic_params);
@@ -2174,23 +2126,9 @@ impl<'a> State<'a> {
                                         span: syntax_pos::Span,
                                         next_pos: Option<BytePos>)
                                         {
-        let cm = match self.cm {
-            Some(cm) => cm,
-            _ => return,
-        };
-        if let Some(ref cmnt) = self.next_comment() {
-            if (*cmnt).style != comments::Trailing {
-                return;
-            }
-            let span_line = cm.lookup_char_pos(span.hi());
-            let comment_line = cm.lookup_char_pos((*cmnt).pos);
-            let mut next = (*cmnt).pos + BytePos(1);
-            if let Some(p) = next_pos {
-                next = p;
-            }
-            if span.hi() < (*cmnt).pos && (*cmnt).pos < next &&
-               span_line.line == comment_line.line {
-                self.print_comment(cmnt);
+        if let Some(cmnts) = self.comments() {
+            if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
+                self.print_comment(&cmnt);
             }
         }
     }
diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs
index f1f9f3f71e4..94849728a93 100644
--- a/src/librustc_borrowck/dataflow.rs
+++ b/src/librustc_borrowck/dataflow.rs
@@ -8,7 +8,6 @@ use rustc::cfg::CFGIndex;
 use rustc::ty::TyCtxt;
 use std::mem;
 use std::usize;
-use syntax::print::pprust::PrintState;
 use log::debug;
 
 use rustc_data_structures::graph::implementation::OUTGOING;
@@ -530,7 +529,7 @@ impl<'tcx, O: DataFlowOperator + Clone + 'static> DataFlowContext<'tcx, O> {
 
         debug!("Dataflow result for {}:", self.analysis_name);
         debug!("{}", pprust::to_string(self, |s| {
-            s.cbox(pprust::indent_unit);
+            s.cbox(pprust::INDENT_UNIT);
             s.ibox(0);
             s.print_expr(&body.value)
         }));
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index fc55d5ac355..51b161c3768 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -19,7 +19,6 @@ use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
 use syntax::ast;
 use syntax::mut_visit::MutVisitor;
 use syntax::print::{pprust};
-use syntax::print::pprust::PrintState;
 use syntax_pos::FileName;
 
 use graphviz as dot;
@@ -687,16 +686,14 @@ pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) {
     }
 }
 
-fn get_source(input: &Input, sess: &Session) -> (Vec<u8>, FileName) {
+fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
     let src_name = source_name(input);
-    let src = sess.source_map()
+    let src = String::clone(&sess.source_map()
         .get_source_file(&src_name)
         .unwrap()
         .src
         .as_ref()
-        .unwrap()
-        .as_bytes()
-        .to_vec();
+        .unwrap());
     (src, src_name)
 }
 
@@ -719,7 +716,6 @@ pub fn print_after_parsing(sess: &Session,
                            ofile: Option<&Path>) {
     let (src, src_name) = get_source(input, sess);
 
-    let mut rdr = &*src;
     let mut out = String::new();
 
     if let PpmSource(s) = ppm {
@@ -728,12 +724,11 @@ pub fn print_after_parsing(sess: &Session,
         s.call_with_pp_support(sess, None, move |annotation| {
             debug!("pretty printing source code {:?}", s);
             let sess = annotation.sess();
-            pprust::print_crate(sess.source_map(),
+            *out = pprust::print_crate(sess.source_map(),
                                 &sess.parse_sess,
                                 krate,
                                 src_name,
-                                &mut rdr,
-                                out,
+                                src,
                                 annotation.pp_ann(),
                                 false)
         })
@@ -764,22 +759,21 @@ pub fn print_after_hir_lowering<'tcx>(
 
     let (src, src_name) = get_source(input, tcx.sess);
 
-    let mut rdr = &src[..];
     let mut out = String::new();
 
     match (ppm, opt_uii) {
             (PpmSource(s), _) => {
                 // Silently ignores an identified node.
                 let out = &mut out;
+                let src = src.clone();
                 s.call_with_pp_support(tcx.sess, Some(tcx), move |annotation| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
-                    pprust::print_crate(sess.source_map(),
+                    *out = pprust::print_crate(sess.source_map(),
                                         &sess.parse_sess,
                                         krate,
                                         src_name,
-                                        &mut rdr,
-                                        out,
+                                        src,
                                         annotation.pp_ann(),
                                         true)
                 })
@@ -787,15 +781,15 @@ 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| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
-                    pprust_hir::print_crate(sess.source_map(),
+                    *out = pprust_hir::print_crate(sess.source_map(),
                                             &sess.parse_sess,
                                             krate,
                                             src_name,
-                                            &mut rdr,
-                                            out,
+                                            src,
                                             annotation.pp_ann())
                 })
             }
@@ -810,6 +804,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, _| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
@@ -817,8 +812,7 @@ pub fn print_after_hir_lowering<'tcx>(
                     let mut pp_state = pprust_hir::State::new_from_input(sess.source_map(),
                                                                          &sess.parse_sess,
                                                                          src_name,
-                                                                         &mut rdr,
-                                                                         out,
+                                                                         src,
                                                                          annotation.pp_ann());
                     for node_id in uii.all_matching_node_ids(hir_map) {
                         let hir_id = tcx.hir().node_to_hir_id(node_id);
@@ -830,7 +824,7 @@ pub fn print_after_hir_lowering<'tcx>(
                         pp_state.synth_comment(path);
                         pp_state.s.hardbreak();
                     }
-                    pp_state.s.eof();
+                    *out = pp_state.s.eof();
                 })
             }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index c7f57be6426..567b6b1a891 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1316,7 +1316,7 @@ impl EncodeContext<'tcx> {
         let def_id = self.tcx.hir().local_def_id(macro_def.hir_id);
         Entry {
             kind: EntryKind::MacroDef(self.lazy(&MacroDef {
-                body: pprust::tts_to_string(&macro_def.body.trees().collect::<Vec<_>>()),
+                body: pprust::tokens_to_string(macro_def.body.clone()),
                 legacy: macro_def.legacy,
             })),
             visibility: self.lazy(&ty::Visibility::Public),
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 0640c01d255..82accb47437 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -73,13 +73,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());
 
                 let slice = unpack!(block = this.as_place(block, lhs));
-                // region_scope=None so place indexes live forever. They are scalars so they
-                // do not need storage annotations, and they are often copied between
-                // places.
                 // Making this a *fresh* temporary also means we do not have to worry about
                 // the index changing later: Nothing will ever change this temporary.
                 // The "retagging" transformation (for Stacked Borrows) relies on this.
-                let idx = unpack!(block = this.as_temp(block, None, index, Mutability::Mut));
+                let idx = unpack!(block = this.as_temp(
+                    block,
+                    expr.temp_lifetime,
+                    index,
+                    Mutability::Not,
+                ));
 
                 // bounds check:
                 let (len, lt) = (
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index 1fe6be8bbc8..dbcc330eca3 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -3,6 +3,7 @@
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use crate::build::scope::DropKind;
 use crate::hair::*;
+use rustc::hir;
 use rustc::middle::region;
 use rustc::mir::*;
 
@@ -66,32 +67,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         };
         let temp_place = &Place::from(temp);
 
-        if !expr_ty.is_never() {
-            this.cfg.push(
-                block,
-                Statement {
-                    source_info,
-                    kind: StatementKind::StorageLive(temp),
-                },
-            );
-
-            // In constants, `temp_lifetime` is `None` for temporaries that live for the
-            // `'static` lifetime. Thus we do not drop these temporaries and simply leak them.
-            // This is equivalent to what `let x = &foo();` does in functions. The temporary
-            // is lifted to their surrounding scope. In a function that means the temporary lives
-            // until just before the function returns. In constants that means it outlives the
-            // constant's initialization value computation. Anything outliving a constant
-            // must have the `'static` lifetime and live forever.
-            // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything
-            // within a block will keep the regular drops just like runtime code.
-            if let Some(temp_lifetime) = temp_lifetime {
-                this.schedule_drop(
-                    expr_span,
-                    temp_lifetime,
-                    temp,
-                    expr_ty,
-                    DropKind::Storage,
+        match expr.kind {
+            // Don't bother with StorageLive and Dead for these temporaries,
+            // they are never assigned.
+            ExprKind::Break { .. } |
+            ExprKind::Continue { .. } |
+            ExprKind::Return { .. } => (),
+            ExprKind::Block {
+                body: hir::Block { expr: None, targeted_by_break: false, .. }
+            } if expr_ty.is_never() => (),
+            _ => {
+                this.cfg.push(
+                    block,
+                    Statement {
+                        source_info,
+                        kind: StatementKind::StorageLive(temp),
+                    },
                 );
+
+                // In constants, `temp_lifetime` is `None` for temporaries that
+                // live for the `'static` lifetime. Thus we do not drop these
+                // temporaries and simply leak them.
+                // This is equivalent to what `let x = &foo();` does in
+                // functions. The temporary is lifted to their surrounding
+                // scope. In a function that means the temporary lives until
+                // just before the function returns. In constants that means it
+                // outlives the constant's initialization value computation.
+                // Anything outliving a constant must have the `'static`
+                // lifetime and live forever.
+                // Anything with a shorter lifetime (e.g the `&foo()` in
+                // `bar(&foo())` or anything within a block will keep the
+                // regular drops just like runtime code.
+                if let Some(temp_lifetime) = temp_lifetime {
+                    this.schedule_drop(
+                        expr_span,
+                        temp_lifetime,
+                        temp,
+                        expr_ty,
+                        DropKind::Storage,
+                    );
+                }
             }
         }
 
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 2dffafd6e54..1fa539f8a2a 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -142,6 +142,7 @@ impl<'a, 'tcx> ConstCx<'a, 'tcx> {
 #[derive(Copy, Clone, Debug)]
 enum ValueSource<'a, 'tcx> {
     Rvalue(&'a Rvalue<'tcx>),
+    DropAndReplace(&'a Operand<'tcx>),
     Call {
         callee: &'a Operand<'tcx>,
         args: &'a [Operand<'tcx>],
@@ -298,6 +299,7 @@ trait Qualif {
     fn in_value(cx: &ConstCx<'_, 'tcx>, source: ValueSource<'_, 'tcx>) -> bool {
         match source {
             ValueSource::Rvalue(rvalue) => Self::in_rvalue(cx, rvalue),
+            ValueSource::DropAndReplace(source) => Self::in_operand(cx, source),
             ValueSource::Call { callee, args, return_ty } => {
                 Self::in_call(cx, callee, args, return_ty)
             }
@@ -889,6 +891,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
             let target = match body[bb].terminator().kind {
                 TerminatorKind::Goto { target } |
                 TerminatorKind::Drop { target, .. } |
+                TerminatorKind::DropAndReplace { target, .. } |
                 TerminatorKind::Assert { target, .. } |
                 TerminatorKind::Call { destination: Some((_, target)), .. } => {
                     Some(target)
@@ -900,7 +903,6 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                 }
 
                 TerminatorKind::SwitchInt {..} |
-                TerminatorKind::DropAndReplace { .. } |
                 TerminatorKind::Resume |
                 TerminatorKind::Abort |
                 TerminatorKind::GeneratorDrop |
@@ -1393,8 +1395,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
             for arg in args {
                 self.visit_operand(arg, location);
             }
-        } else if let TerminatorKind::Drop { location: ref place, .. } = *kind {
-            self.super_terminator_kind(kind, location);
+        } else if let TerminatorKind::Drop {
+            location: ref place, ..
+        } | TerminatorKind::DropAndReplace {
+            location: ref place, ..
+        } = *kind {
+            match *kind {
+                TerminatorKind::DropAndReplace { .. } => {}
+                _ => self.super_terminator_kind(kind, location),
+            }
 
             // Deny *any* live drops anywhere other than functions.
             if self.mode.requires_const_checking() {
@@ -1423,6 +1432,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                     }
                 }
             }
+
+            match *kind {
+                TerminatorKind::DropAndReplace { ref value, .. } => {
+                    self.assign(place, ValueSource::DropAndReplace(value), location);
+                    self.visit_operand(value, location);
+                }
+                _ => {}
+            }
         } else {
             // Qualify any operands inside other terminators.
             self.super_terminator_kind(kind, location);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index c627596bbdf..8801e89a0cf 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -50,11 +50,17 @@ impl fmt::Debug for Lifetime {
             f,
             "lifetime({}: {})",
             self.id,
-            pprust::lifetime_to_string(self)
+            self
         )
     }
 }
 
+impl fmt::Display for Lifetime {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.ident.name.as_str())
+    }
+}
+
 /// A "Path" is essentially Rust's notion of a name.
 ///
 /// It's represented as a sequence of identifiers,
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index a7c5ed158e0..ee7fb97ffd7 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -162,6 +162,7 @@ pub mod visit;
 pub mod print {
     pub mod pp;
     pub mod pprust;
+    mod helpers;
 }
 
 pub mod ext {
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index edcdb18a037..ae24047ac82 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -611,8 +611,6 @@ impl<'a> Parser<'a> {
         match ty.node {
             TyKind::Rptr(ref lifetime, ref mut_ty) => {
                 let sum_with_parens = pprust::to_string(|s| {
-                    use crate::print::pprust::PrintState;
-
                     s.s.word("&");
                     s.print_opt_lifetime(lifetime);
                     s.print_mutability(mut_ty.mutbl);
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index 988f1aa38d9..6ed2a7adad1 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -8,7 +8,6 @@ use crate::parse::lexer::{self, ParseSess, StringReader};
 use syntax_pos::{BytePos, CharPos, Pos, FileName};
 use log::debug;
 
-use std::io::Read;
 use std::usize;
 
 #[derive(Clone, Copy, PartialEq, Debug)]
@@ -340,10 +339,8 @@ fn consume_comment(rdr: &mut StringReader<'_>,
 
 // it appears this function is called only from pprust... that's
 // probably not a good thing.
-pub fn gather_comments(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) -> Vec<Comment>
+pub fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec<Comment>
 {
-    let mut src = String::new();
-    srdr.read_to_string(&mut src).unwrap();
     let cm = SourceMap::new(sess.source_map().path_mapping().clone());
     let source_file = cm.new_source_file(path, src);
     let mut rdr = lexer::StringReader::new(sess, source_file, None);
diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs
index ef55bf6b929..683d1641565 100644
--- a/src/libsyntax/parse/literal.rs
+++ b/src/libsyntax/parse/literal.rs
@@ -344,7 +344,7 @@ impl<'a> Parser<'a> {
                 // Pack possible quotes and prefixes from the original literal into
                 // the error literal's symbol so they can be pretty-printed faithfully.
                 let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
-                let symbol = Symbol::intern(&pprust::literal_to_string(suffixless_lit));
+                let symbol = Symbol::intern(&suffixless_lit.to_string());
                 let lit = token::Lit::new(token::Err, symbol, lit.suffix);
                 Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
             }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a95b6891fb9..83dbff6b2d5 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2571,7 +2571,6 @@ impl<'a> Parser<'a> {
                               None => continue,
                           };
                           let sugg = pprust::to_string(|s| {
-                              use crate::print::pprust::PrintState;
                               s.popen();
                               s.print_expr(&e);
                               s.s.word( ".");
@@ -4588,11 +4587,11 @@ impl<'a> Parser<'a> {
                         stmt_span = stmt_span.with_hi(self.prev_span.hi());
                     }
                     let sugg = pprust::to_string(|s| {
-                        use crate::print::pprust::{PrintState, INDENT_UNIT};
+                        use crate::print::pprust::INDENT_UNIT;
                         s.ibox(INDENT_UNIT);
                         s.bopen();
                         s.print_stmt(&stmt);
-                        s.bclose_maybe_open(stmt.span, INDENT_UNIT, false)
+                        s.bclose_maybe_open(stmt.span, false)
                     });
                     e.span_suggestion(
                         stmt_span,
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index ebd0decacb5..472e4b474d6 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -80,6 +80,34 @@ pub struct Lit {
     pub suffix: Option<Symbol>,
 }
 
+impl fmt::Display for Lit {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Lit { kind, symbol, suffix } = *self;
+        match kind {
+            Byte          => write!(f, "b'{}'", symbol)?,
+            Char          => write!(f, "'{}'", symbol)?,
+            Str           => write!(f, "\"{}\"", symbol)?,
+            StrRaw(n)     => write!(f, "r{delim}\"{string}\"{delim}",
+                                     delim="#".repeat(n as usize),
+                                     string=symbol)?,
+            ByteStr       => write!(f, "b\"{}\"", symbol)?,
+            ByteStrRaw(n) => write!(f, "br{delim}\"{string}\"{delim}",
+                                     delim="#".repeat(n as usize),
+                                     string=symbol)?,
+            Integer       |
+            Float         |
+            Bool          |
+            Err           => write!(f, "{}", symbol)?,
+        }
+
+        if let Some(suffix) = suffix {
+            write!(f, "{}", suffix)?;
+        }
+
+        Ok(())
+    }
+}
+
 impl LitKind {
     /// An English article for the literal token kind.
     crate fn article(self) -> &'static str {
@@ -788,7 +816,7 @@ fn prepend_attrs(sess: &ParseSess,
         assert_eq!(attr.style, ast::AttrStyle::Outer,
                    "inner attributes should prevent cached tokens from existing");
 
-        let source = pprust::attr_to_string(attr);
+        let source = pprust::attribute_to_string(attr);
         let macro_filename = FileName::macro_expansion_source_code(&source);
         if attr.is_sugared_doc {
             let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
diff --git a/src/libsyntax/print/helpers.rs b/src/libsyntax/print/helpers.rs
new file mode 100644
index 00000000000..3449e07f456
--- /dev/null
+++ b/src/libsyntax/print/helpers.rs
@@ -0,0 +1,34 @@
+use std::borrow::Cow;
+use crate::print::pp::Printer;
+
+impl Printer {
+    pub fn word_space<W: Into<Cow<'static, str>>>(&mut self, w: W) {
+        self.word(w);
+        self.space();
+    }
+
+    pub fn popen(&mut self) {
+        self.word("(");
+    }
+
+    pub fn pclose(&mut self) {
+        self.word(")");
+    }
+
+    pub fn hardbreak_if_not_bol(&mut self) {
+        if !self.is_beginning_of_line() {
+            self.hardbreak()
+        }
+    }
+
+    pub fn space_if_not_bol(&mut self) {
+        if !self.is_beginning_of_line() { self.space(); }
+    }
+
+    pub fn nbsp(&mut self) { self.word(" ") }
+
+    pub fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) {
+        self.word(w);
+        self.nbsp()
+    }
+}
diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs
index f64e95aee5b..660e77f77d0 100644
--- a/src/libsyntax/print/pp.rs
+++ b/src/libsyntax/print/pp.rs
@@ -131,7 +131,7 @@
 //! it.
 //!
 //! In this implementation (following the paper, again) the SCAN process is the
-//! methods called `Printer::pretty_print_*`, and the 'PRINT' process is the
+//! methods called `Printer::scan_*`, and the 'PRINT' process is the
 //! method called `Printer::print`.
 
 use std::collections::VecDeque;
@@ -163,7 +163,7 @@ pub enum Token {
     // In practice a string token contains either a `&'static str` or a
     // `String`. `Cow` is overkill for this because we never modify the data,
     // but it's more convenient than rolling our own more specialized type.
-    String(Cow<'static, str>, isize),
+    String(Cow<'static, str>),
     Break(BreakToken),
     Begin(BeginToken),
     End,
@@ -194,7 +194,7 @@ impl Token {
 impl fmt::Display for Token {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            Token::String(ref s, len) => write!(f, "STR({},{})", s, len),
+            Token::String(ref s) => write!(f, "STR({},{})", s, s.len()),
             Token::Break(_) => f.write_str("BREAK"),
             Token::Begin(_) => f.write_str("BEGIN"),
             Token::End => f.write_str("END"),
@@ -222,26 +222,26 @@ fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
 }
 
 #[derive(Copy, Clone)]
-crate enum PrintStackBreak {
+enum PrintStackBreak {
     Fits,
     Broken(Breaks),
 }
 
 #[derive(Copy, Clone)]
-crate struct PrintStackElem {
+struct PrintStackElem {
     offset: isize,
     pbreak: PrintStackBreak
 }
 
 const SIZE_INFINITY: isize = 0xffff;
 
-pub fn mk_printer(out: &mut String) -> Printer<'_> {
+pub fn mk_printer() -> Printer {
     let linewidth = 78;
     // Yes 55, it makes the ring buffers big enough to never fall behind.
     let n: usize = 55 * linewidth;
     debug!("mk_printer {}", linewidth);
     Printer {
-        out,
+        out: String::new(),
         buf_max_len: n,
         margin: linewidth as isize,
         space: linewidth as isize,
@@ -258,8 +258,8 @@ pub fn mk_printer(out: &mut String) -> Printer<'_> {
     }
 }
 
-pub struct Printer<'a> {
-    out: &'a mut String,
+pub struct Printer {
+    out: String,
     buf_max_len: usize,
     /// Width of lines we're constrained to
     margin: isize,
@@ -300,8 +300,8 @@ impl Default for BufEntry {
     }
 }
 
-impl<'a> Printer<'a> {
-    pub fn last_token(&mut self) -> Token {
+impl Printer {
+    pub fn last_token(&self) -> Token {
         self.buf[self.right].token.clone()
     }
 
@@ -310,15 +310,14 @@ impl<'a> Printer<'a> {
         self.buf[self.right].token = t;
     }
 
-    fn pretty_print_eof(&mut self) {
+    fn scan_eof(&mut self) {
         if !self.scan_stack.is_empty() {
             self.check_stack(0);
             self.advance_left();
         }
-        self.indent(0);
     }
 
-    fn pretty_print_begin(&mut self, b: BeginToken) {
+    fn scan_begin(&mut self, b: BeginToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
@@ -329,25 +328,21 @@ impl<'a> Printer<'a> {
         }
         debug!("pp Begin({})/buffer Vec<{},{}>",
                b.offset, self.left, self.right);
-        self.buf[self.right] = BufEntry { token: Token::Begin(b), size: -self.right_total };
-        let right = self.right;
-        self.scan_push(right);
+        self.scan_push(BufEntry { token: Token::Begin(b), size: -self.right_total });
     }
 
-    fn pretty_print_end(&mut self) {
+    fn scan_end(&mut self) {
         if self.scan_stack.is_empty() {
             debug!("pp End/print Vec<{},{}>", self.left, self.right);
             self.print_end();
         } else {
             debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
             self.advance_right();
-            self.buf[self.right] = BufEntry { token: Token::End, size: -1 };
-            let right = self.right;
-            self.scan_push(right);
+            self.scan_push(BufEntry { token: Token::End, size: -1 });
         }
     }
 
-    fn pretty_print_break(&mut self, b: BreakToken) {
+    fn scan_break(&mut self, b: BreakToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
@@ -359,28 +354,27 @@ impl<'a> Printer<'a> {
         debug!("pp Break({})/buffer Vec<{},{}>",
                b.offset, self.left, self.right);
         self.check_stack(0);
-        let right = self.right;
-        self.scan_push(right);
-        self.buf[self.right] = BufEntry { token: Token::Break(b), size: -self.right_total };
+        self.scan_push(BufEntry { token: Token::Break(b), size: -self.right_total });
         self.right_total += b.blank_space;
     }
 
-    fn pretty_print_string(&mut self, s: Cow<'static, str>, len: isize) {
+    fn scan_string(&mut self, s: Cow<'static, str>) {
         if self.scan_stack.is_empty() {
             debug!("pp String('{}')/print Vec<{},{}>",
                    s, self.left, self.right);
-            self.print_string(s, len);
+            self.print_string(s);
         } else {
             debug!("pp String('{}')/buffer Vec<{},{}>",
                    s, self.left, self.right);
             self.advance_right();
-            self.buf[self.right] = BufEntry { token: Token::String(s, len), size: len };
+            let len = s.len() as isize;
+            self.buf[self.right] = BufEntry { token: Token::String(s), size: len };
             self.right_total += len;
             self.check_stream();
         }
     }
 
-    crate fn check_stream(&mut self) {
+    fn check_stream(&mut self) {
         debug!("check_stream Vec<{}, {}> with left_total={}, right_total={}",
                self.left, self.right, self.left_total, self.right_total);
         if self.right_total - self.left_total > self.space {
@@ -398,24 +392,25 @@ impl<'a> Printer<'a> {
         }
     }
 
-    crate fn scan_push(&mut self, x: usize) {
-        debug!("scan_push {}", x);
-        self.scan_stack.push_front(x);
+    fn scan_push(&mut self, entry: BufEntry) {
+        debug!("scan_push {}", self.right);
+        self.buf[self.right] = entry;
+        self.scan_stack.push_front(self.right);
     }
 
-    crate fn scan_pop(&mut self) -> usize {
+    fn scan_pop(&mut self) -> usize {
         self.scan_stack.pop_front().unwrap()
     }
 
-    crate fn scan_top(&mut self) -> usize {
+    fn scan_top(&mut self) -> usize {
         *self.scan_stack.front().unwrap()
     }
 
-    crate fn scan_pop_bottom(&mut self) -> usize {
+    fn scan_pop_bottom(&mut self) -> usize {
         self.scan_stack.pop_back().unwrap()
     }
 
-    crate fn advance_right(&mut self) {
+    fn advance_right(&mut self) {
         self.right += 1;
         self.right %= self.buf_max_len;
         // Extend the buf if necessary.
@@ -425,7 +420,7 @@ impl<'a> Printer<'a> {
         assert_ne!(self.right, self.left);
     }
 
-    crate fn advance_left(&mut self) {
+    fn advance_left(&mut self) {
         debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right,
                self.left, self.buf[self.left].size);
 
@@ -436,7 +431,8 @@ impl<'a> Printer<'a> {
 
             let len = match left {
                 Token::Break(b) => b.blank_space,
-                Token::String(_, len) => {
+                Token::String(ref s) => {
+                    let len = s.len() as isize;
                     assert_eq!(len, left_size);
                     len
                 }
@@ -458,26 +454,26 @@ impl<'a> Printer<'a> {
         }
     }
 
-    crate fn check_stack(&mut self, k: isize) {
+    fn check_stack(&mut self, k: usize) {
         if !self.scan_stack.is_empty() {
             let x = self.scan_top();
             match self.buf[x].token {
                 Token::Begin(_) => {
                     if k > 0 {
-                        let popped = self.scan_pop();
-                        self.buf[popped].size = self.buf[x].size + self.right_total;
+                        self.scan_pop();
+                        self.buf[x].size += self.right_total;
                         self.check_stack(k - 1);
                     }
                 }
                 Token::End => {
                     // paper says + not =, but that makes no sense.
-                    let popped = self.scan_pop();
-                    self.buf[popped].size = 1;
+                    self.scan_pop();
+                    self.buf[x].size = 1;
                     self.check_stack(k + 1);
                 }
                 _ => {
-                    let popped = self.scan_pop();
-                    self.buf[popped].size = self.buf[x].size + self.right_total;
+                    self.scan_pop();
+                    self.buf[x].size += self.right_total;
                     if k > 0 {
                         self.check_stack(k);
                     }
@@ -486,19 +482,19 @@ impl<'a> Printer<'a> {
         }
     }
 
-    crate fn print_newline(&mut self, amount: isize) {
+    fn print_newline(&mut self, amount: isize) {
         debug!("NEWLINE {}", amount);
         self.out.push('\n');
         self.pending_indentation = 0;
         self.indent(amount);
     }
 
-    crate fn indent(&mut self, amount: isize) {
+    fn indent(&mut self, amount: isize) {
         debug!("INDENT {}", amount);
         self.pending_indentation += amount;
     }
 
-    crate fn get_top(&mut self) -> PrintStackElem {
+    fn get_top(&mut self) -> PrintStackElem {
         match self.print_stack.last() {
             Some(el) => *el,
             None => PrintStackElem {
@@ -508,7 +504,7 @@ impl<'a> Printer<'a> {
         }
     }
 
-    crate fn print_begin(&mut self, b: BeginToken, l: isize) {
+    fn print_begin(&mut self, b: BeginToken, l: isize) {
         if l > self.space {
             let col = self.margin - self.space + b.offset;
             debug!("print Begin -> push broken block at col {}", col);
@@ -525,14 +521,12 @@ impl<'a> Printer<'a> {
         }
     }
 
-    crate fn print_end(&mut self) {
+    fn print_end(&mut self) {
         debug!("print End -> pop End");
-        let print_stack = &mut self.print_stack;
-        assert!(!print_stack.is_empty());
-        print_stack.pop().unwrap();
+        self.print_stack.pop().unwrap();
     }
 
-    crate fn print_break(&mut self, b: BreakToken, l: isize) {
+    fn print_break(&mut self, b: BreakToken, l: isize) {
         let top = self.get_top();
         match top.pbreak {
             PrintStackBreak::Fits => {
@@ -562,7 +556,8 @@ impl<'a> Printer<'a> {
         }
     }
 
-    crate fn print_string(&mut self, s: Cow<'static, str>, len: isize) {
+    fn print_string(&mut self, s: Cow<'static, str>) {
+        let len = s.len() as isize;
         debug!("print String({})", s);
         // assert!(len <= space);
         self.space -= len;
@@ -579,7 +574,7 @@ impl<'a> Printer<'a> {
         self.out.push_str(&s);
     }
 
-    crate fn print(&mut self, token: Token, l: isize) {
+    fn print(&mut self, token: Token, l: isize) {
         debug!("print {} {} (remaining line space={})", token, l,
                self.space);
         debug!("{}", buf_str(&self.buf,
@@ -590,9 +585,10 @@ impl<'a> Printer<'a> {
             Token::Begin(b) => self.print_begin(b, l),
             Token::End => self.print_end(),
             Token::Break(b) => self.print_break(b, l),
-            Token::String(s, len) => {
+            Token::String(s) => {
+                let len = s.len() as isize;
                 assert_eq!(len, l);
-                self.print_string(s, len);
+                self.print_string(s);
             }
             Token::Eof => panic!(), // Eof should never get here.
         }
@@ -601,15 +597,15 @@ impl<'a> Printer<'a> {
     // Convenience functions to talk to the printer.
 
     /// "raw box"
-    crate fn rbox(&mut self, indent: usize, b: Breaks) {
-        self.pretty_print_begin(BeginToken {
+    pub fn rbox(&mut self, indent: usize, b: Breaks) {
+        self.scan_begin(BeginToken {
             offset: indent as isize,
             breaks: b
         })
     }
 
     /// Inconsistent breaking box
-    crate fn ibox(&mut self, indent: usize) {
+    pub fn ibox(&mut self, indent: usize) {
         self.rbox(indent, Breaks::Inconsistent)
     }
 
@@ -619,24 +615,24 @@ impl<'a> Printer<'a> {
     }
 
     pub fn break_offset(&mut self, n: usize, off: isize) {
-        self.pretty_print_break(BreakToken {
+        self.scan_break(BreakToken {
             offset: off,
             blank_space: n as isize
         })
     }
 
-    crate fn end(&mut self) {
-        self.pretty_print_end()
+    pub fn end(&mut self) {
+        self.scan_end()
     }
 
-    pub fn eof(&mut self) {
-        self.pretty_print_eof()
+    pub fn eof(mut self) -> String {
+        self.scan_eof();
+        self.out
     }
 
     pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
         let s = wrd.into();
-        let len = s.len() as isize;
-        self.pretty_print_string(s, len)
+        self.scan_string(s)
     }
 
     fn spaces(&mut self, n: usize) {
@@ -655,6 +651,10 @@ impl<'a> Printer<'a> {
         self.spaces(SIZE_INFINITY as usize)
     }
 
+    pub fn is_beginning_of_line(&self) -> bool {
+        self.last_token().is_eof() || self.last_token().is_hardbreak_tok()
+    }
+
     pub fn hardbreak_tok_offset(off: isize) -> Token {
         Token::Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 7e099bc4d50..8050026a00d 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 use crate::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
 use crate::ast::{SelfKind, GenericBound, TraitBoundModifier};
 use crate::ast::{Attribute, MacDelimiter, GenericArg};
@@ -21,7 +19,6 @@ use syntax_pos::{self, BytePos};
 use syntax_pos::{DUMMY_SP, FileName, Span};
 
 use std::borrow::Cow;
-use std::io::Read;
 
 pub enum AnnNode<'a> {
     Ident(&'a ast::Ident),
@@ -43,12 +40,53 @@ pub struct NoAnn;
 
 impl PpAnn for NoAnn {}
 
+pub struct Comments<'a> {
+    cm: &'a SourceMap,
+    comments: Vec<comments::Comment>,
+    current: usize,
+}
+
+impl<'a> Comments<'a> {
+    pub fn new(
+        cm: &'a SourceMap,
+        sess: &ParseSess,
+        filename: FileName,
+        input: String,
+    ) -> Comments<'a> {
+        let comments = comments::gather_comments(sess, filename, input);
+        Comments {
+            cm,
+            comments,
+            current: 0,
+        }
+    }
+
+    pub fn next(&self) -> Option<comments::Comment> {
+        self.comments.get(self.current).cloned()
+    }
+
+    pub fn trailing_comment(
+        &mut self,
+        span: syntax_pos::Span,
+        next_pos: Option<BytePos>,
+    ) -> Option<comments::Comment> {
+        if let Some(cmnt) = self.next() {
+            if cmnt.style != comments::Trailing { return None; }
+            let span_line = self.cm.lookup_char_pos(span.hi());
+            let comment_line = self.cm.lookup_char_pos(cmnt.pos);
+            let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
+            if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
+                return Some(cmnt);
+            }
+        }
+
+        None
+    }
+}
+
 pub struct State<'a> {
-    pub s: pp::Printer<'a>,
-    cm: Option<&'a SourceMap>,
-    comments: Option<Vec<comments::Comment>>,
-    cur_cmnt: usize,
-    boxes: Vec<pp::Breaks>,
+    pub s: pp::Printer,
+    comments: Option<Comments<'a>>,
     ann: &'a (dyn PpAnn+'a),
     is_expanded: bool
 }
@@ -61,11 +99,15 @@ pub fn print_crate<'a>(cm: &'a SourceMap,
                        sess: &ParseSess,
                        krate: &ast::Crate,
                        filename: FileName,
-                       input: &mut dyn Read,
-                       out: &mut String,
+                       input: String,
                        ann: &'a dyn PpAnn,
-                       is_expanded: bool) {
-    let mut s = State::new_from_input(cm, sess, filename, input, out, ann, is_expanded);
+                       is_expanded: bool) -> String {
+    let mut s = State {
+        s: pp::mk_printer(),
+        comments: Some(Comments::new(cm, sess, filename, input)),
+        ann,
+        is_expanded,
+    };
 
     if is_expanded && std_inject::injected_crate_name().is_some() {
         // We need to print `#![no_std]` (and its feature gate) so that
@@ -91,53 +133,17 @@ pub fn print_crate<'a>(cm: &'a SourceMap,
     s.s.eof()
 }
 
-impl<'a> State<'a> {
-    pub fn new_from_input(cm: &'a SourceMap,
-                          sess: &ParseSess,
-                          filename: FileName,
-                          input: &mut dyn Read,
-                          out: &'a mut String,
-                          ann: &'a dyn PpAnn,
-                          is_expanded: bool) -> State<'a> {
-        let comments = comments::gather_comments(sess, filename, input);
-        State::new(cm, out, ann, Some(comments), is_expanded)
-    }
-
-    pub fn new(cm: &'a SourceMap,
-               out: &'a mut String,
-               ann: &'a dyn PpAnn,
-               comments: Option<Vec<comments::Comment>>,
-               is_expanded: bool) -> State<'a> {
-        State {
-            s: pp::mk_printer(out),
-            cm: Some(cm),
-            comments,
-            cur_cmnt: 0,
-            boxes: Vec::new(),
-            ann,
-            is_expanded,
-        }
-    }
-}
-
 pub fn to_string<F>(f: F) -> String where
     F: FnOnce(&mut State<'_>),
 {
-    let mut wr = String::new();
-    {
-        let mut printer = State {
-            s: pp::mk_printer(&mut wr),
-            cm: None,
-            comments: None,
-            cur_cmnt: 0,
-            boxes: Vec::new(),
-            ann: &NoAnn,
-            is_expanded: false
-        };
-        f(&mut printer);
-        printer.s.eof();
-    }
-    wr
+    let mut printer = State {
+        s: pp::mk_printer(),
+        comments: None,
+        ann: &NoAnn,
+        is_expanded: false
+    };
+    f(&mut printer);
+    printer.s.eof()
 }
 
 fn binop_to_string(op: BinOpToken) -> &'static str {
@@ -322,18 +328,10 @@ pub fn pat_to_string(pat: &ast::Pat) -> String {
     to_string(|s| s.print_pat(pat))
 }
 
-pub fn arm_to_string(arm: &ast::Arm) -> String {
-    to_string(|s| s.print_arm(arm))
-}
-
 pub fn expr_to_string(e: &ast::Expr) -> String {
     to_string(|s| s.print_expr(e))
 }
 
-pub fn lifetime_to_string(lt: &ast::Lifetime) -> String {
-    to_string(|s| s.print_lifetime(*lt))
-}
-
 pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
     to_string(|s| s.print_tt(tt, false))
 }
@@ -350,19 +348,15 @@ pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
     to_string(|s| s.print_stmt(stmt))
 }
 
-pub fn attr_to_string(attr: &ast::Attribute) -> String {
-    to_string(|s| s.print_attribute(attr))
-}
-
 pub fn item_to_string(i: &ast::Item) -> String {
     to_string(|s| s.print_item(i))
 }
 
-pub fn impl_item_to_string(i: &ast::ImplItem) -> String {
+fn impl_item_to_string(i: &ast::ImplItem) -> String {
     to_string(|s| s.print_impl_item(i))
 }
 
-pub fn trait_item_to_string(i: &ast::TraitItem) -> String {
+fn trait_item_to_string(i: &ast::TraitItem) -> String {
     to_string(|s| s.print_trait_item(i))
 }
 
@@ -370,14 +364,6 @@ pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String
     to_string(|s| s.print_generic_params(generic_params))
 }
 
-pub fn where_clause_to_string(i: &ast::WhereClause) -> String {
-    to_string(|s| s.print_where_clause(i))
-}
-
-pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
-    to_string(|s| s.print_fn_block_args(p))
-}
-
 pub fn path_to_string(p: &ast::Path) -> String {
     to_string(|s| s.print_path(p, false, 0))
 }
@@ -390,7 +376,8 @@ pub fn vis_to_string(v: &ast::Visibility) -> String {
     to_string(|s| s.print_visibility(v))
 }
 
-pub fn fun_to_string(decl: &ast::FnDecl,
+#[cfg(test)]
+fn fun_to_string(decl: &ast::FnDecl,
                      header: ast::FnHeader,
                      name: ast::Ident,
                      generics: &ast::Generics)
@@ -404,7 +391,7 @@ pub fn fun_to_string(decl: &ast::FnDecl,
     })
 }
 
-pub fn block_to_string(blk: &ast::Block) -> String {
+fn block_to_string(blk: &ast::Block) -> String {
     to_string(|s| {
         // containing cbox, will be closed by print-block at }
         s.cbox(INDENT_UNIT);
@@ -426,11 +413,8 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String {
     to_string(|s| s.print_attribute(attr))
 }
 
-pub fn lit_to_string(l: &ast::Lit) -> String {
-    to_string(|s| s.print_literal(l))
-}
-
-pub fn variant_to_string(var: &ast::Variant) -> String {
+#[cfg(test)]
+fn variant_to_string(var: &ast::Variant) -> String {
     to_string(|s| s.print_variant(var))
 }
 
@@ -438,73 +422,29 @@ pub fn arg_to_string(arg: &ast::Arg) -> String {
     to_string(|s| s.print_arg(arg, false))
 }
 
-pub fn mac_to_string(arg: &ast::Mac) -> String {
-    to_string(|s| s.print_mac(arg))
-}
-
-pub fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
+fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
     to_string(|s| s.print_foreign_item(arg))
 }
 
-pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
+fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
     format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
 }
 
-pub trait PrintState<'a> {
-    fn writer(&mut self) -> &mut pp::Printer<'a>;
-    fn boxes(&mut self) -> &mut Vec<pp::Breaks>;
-    fn comments(&mut self) -> &mut Option<Vec<comments::Comment>>;
-    fn cur_cmnt(&mut self) -> &mut usize;
-
-    fn word_space<S: Into<Cow<'static, str>>>(&mut self, w: S) {
-        self.writer().word(w);
-        self.writer().space()
-    }
-
-    fn popen(&mut self) { self.writer().word("(") }
-
-    fn pclose(&mut self) { self.writer().word(")") }
-
-    fn is_begin(&mut self) -> bool {
-        match self.writer().last_token() {
-            pp::Token::Begin(_) => true,
-            _ => false,
-        }
-    }
-
-    fn is_end(&mut self) -> bool {
-        match self.writer().last_token() {
-            pp::Token::End => true,
-            _ => false,
-        }
-    }
-
-    // is this the beginning of a line?
-    fn is_bol(&mut self) -> bool {
-        self.writer().last_token().is_eof() || self.writer().last_token().is_hardbreak_tok()
-    }
-
-    fn hardbreak_if_not_bol(&mut self) {
-        if !self.is_bol() {
-            self.writer().hardbreak()
-        }
-    }
-
-    // "raw box"
-    fn rbox(&mut self, u: usize, b: pp::Breaks) {
-        self.boxes().push(b);
-        self.writer().rbox(u, b)
+impl std::ops::Deref for State<'_> {
+    type Target = pp::Printer;
+    fn deref(&self) -> &Self::Target {
+        &self.s
     }
+}
 
-    fn ibox(&mut self, u: usize) {
-        self.boxes().push(pp::Breaks::Inconsistent);
-        self.writer().ibox(u);
+impl std::ops::DerefMut for State<'_> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.s
     }
+}
 
-    fn end(&mut self) {
-        self.boxes().pop().unwrap();
-        self.writer().end()
-    }
+pub trait PrintState<'a>: std::ops::Deref<Target=pp::Printer> + std::ops::DerefMut {
+    fn comments(&mut self) -> &mut Option<Comments<'a>>;
 
     fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F)
         where F: FnMut(&mut Self, &T),
@@ -533,9 +473,9 @@ pub trait PrintState<'a> {
         match cmnt.style {
             comments::Mixed => {
                 assert_eq!(cmnt.lines.len(), 1);
-                self.writer().zerobreak();
-                self.writer().word(cmnt.lines[0].clone());
-                self.writer().zerobreak()
+                self.zerobreak();
+                self.word(cmnt.lines[0].clone());
+                self.zerobreak()
             }
             comments::Isolated => {
                 self.hardbreak_if_not_bol();
@@ -543,61 +483,55 @@ pub trait PrintState<'a> {
                     // Don't print empty lines because they will end up as trailing
                     // whitespace
                     if !line.is_empty() {
-                        self.writer().word(line.clone());
+                        self.word(line.clone());
                     }
-                    self.writer().hardbreak();
+                    self.hardbreak();
                 }
             }
             comments::Trailing => {
-                if !self.is_bol() {
-                    self.writer().word(" ");
+                if !self.is_beginning_of_line() {
+                    self.word(" ");
                 }
                 if cmnt.lines.len() == 1 {
-                    self.writer().word(cmnt.lines[0].clone());
-                    self.writer().hardbreak()
+                    self.word(cmnt.lines[0].clone());
+                    self.hardbreak()
                 } else {
                     self.ibox(0);
                     for line in &cmnt.lines {
                         if !line.is_empty() {
-                            self.writer().word(line.clone());
+                            self.word(line.clone());
                         }
-                        self.writer().hardbreak();
+                        self.hardbreak();
                     }
                     self.end();
                 }
             }
             comments::BlankLine => {
                 // We need to do at least one, possibly two hardbreaks.
-                let is_semi = match self.writer().last_token() {
-                    pp::Token::String(s, _) => ";" == s,
+                let twice = match self.last_token() {
+                    pp::Token::String(s) => ";" == s,
+                    pp::Token::Begin(_) => true,
+                    pp::Token::End => true,
                     _ => false
                 };
-                if is_semi || self.is_begin() || self.is_end() {
-                    self.writer().hardbreak();
+                if twice {
+                    self.hardbreak();
                 }
-                self.writer().hardbreak();
+                self.hardbreak();
             }
         }
-        *self.cur_cmnt() = *self.cur_cmnt() + 1;
+        if let Some(cm) = self.comments() {
+            cm.current += 1;
+        }
     }
 
     fn next_comment(&mut self) -> Option<comments::Comment> {
-        let cur_cmnt = *self.cur_cmnt();
-        match *self.comments() {
-            Some(ref cmnts) => {
-                if cur_cmnt < cmnts.len() {
-                    Some(cmnts[cur_cmnt].clone())
-                } else {
-                    None
-                }
-            }
-            _ => None
-        }
+        self.comments().as_mut().and_then(|c| c.next())
     }
 
     fn print_literal(&mut self, lit: &ast::Lit) {
         self.maybe_print_comment(lit.span.lo());
-        self.writer().word(literal_to_string(lit.token))
+        self.word(lit.token.to_string())
     }
 
     fn print_string(&mut self, st: &str,
@@ -612,7 +546,7 @@ pub trait PrintState<'a> {
                          string=st))
             }
         };
-        self.writer().word(st)
+        self.word(st)
     }
 
     fn print_inner_attributes(&mut self,
@@ -664,10 +598,10 @@ pub trait PrintState<'a> {
     fn print_attribute_path(&mut self, path: &ast::Path) {
         for (i, segment) in path.segments.iter().enumerate() {
             if i > 0 {
-                self.writer().word("::");
+                self.word("::");
             }
             if segment.ident.name != kw::PathRoot {
-                self.writer().word(ident_to_string(segment.ident, segment.ident.is_raw_guess()));
+                self.word(ident_to_string(segment.ident, segment.ident.is_raw_guess()));
             }
         }
     }
@@ -683,21 +617,21 @@ pub trait PrintState<'a> {
         }
         self.maybe_print_comment(attr.span.lo());
         if attr.is_sugared_doc {
-            self.writer().word(attr.value_str().unwrap().as_str().to_string());
-            self.writer().hardbreak()
+            self.word(attr.value_str().unwrap().as_str().to_string());
+            self.hardbreak()
         } else {
             match attr.style {
-                ast::AttrStyle::Inner => self.writer().word("#!["),
-                ast::AttrStyle::Outer => self.writer().word("#["),
+                ast::AttrStyle::Inner => self.word("#!["),
+                ast::AttrStyle::Outer => self.word("#["),
             }
             if let Some(mi) = attr.meta() {
                 self.print_meta_item(&mi);
             } else {
                 self.print_attribute_path(&attr.path);
-                self.writer().space();
+                self.space();
                 self.print_tts(attr.tokens.clone());
             }
-            self.writer().word("]");
+            self.word("]");
         }
     }
 
@@ -718,7 +652,7 @@ pub trait PrintState<'a> {
             ast::MetaItemKind::Word => self.print_attribute_path(&item.path),
             ast::MetaItemKind::NameValue(ref value) => {
                 self.print_attribute_path(&item.path);
-                self.writer().space();
+                self.space();
                 self.word_space("=");
                 self.print_literal(value);
             }
@@ -744,20 +678,20 @@ pub trait PrintState<'a> {
     fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) {
         match tt {
             TokenTree::Token(ref token) => {
-                self.writer().word(token_to_string_ext(&token, convert_dollar_crate));
+                self.word(token_to_string_ext(&token, convert_dollar_crate));
                 match token.kind {
                     token::DocComment(..) => {
-                        self.writer().hardbreak()
+                        self.hardbreak()
                     }
                     _ => {}
                 }
             }
             TokenTree::Delimited(_, delim, tts) => {
-                self.writer().word(token_kind_to_string(&token::OpenDelim(delim)));
-                self.writer().space();
+                self.word(token_kind_to_string(&token::OpenDelim(delim)));
+                self.space();
                 self.print_tts(tts);
-                self.writer().space();
-                self.writer().word(token_kind_to_string(&token::CloseDelim(delim)))
+                self.space();
+                self.word(token_kind_to_string(&token::CloseDelim(delim)))
             },
         }
     }
@@ -770,49 +704,21 @@ pub trait PrintState<'a> {
         self.ibox(0);
         for (i, tt) in tts.into_trees().enumerate() {
             if i != 0 {
-                self.writer().space();
+                self.space();
             }
             self.print_tt(tt, convert_dollar_crate);
         }
         self.end();
     }
-
-    fn space_if_not_bol(&mut self) {
-        if !self.is_bol() { self.writer().space(); }
-    }
-
-    fn nbsp(&mut self) { self.writer().word(" ") }
 }
 
 impl<'a> PrintState<'a> for State<'a> {
-    fn writer(&mut self) -> &mut pp::Printer<'a> {
-        &mut self.s
-    }
-
-    fn boxes(&mut self) -> &mut Vec<pp::Breaks> {
-        &mut self.boxes
-    }
-
-    fn comments(&mut self) -> &mut Option<Vec<comments::Comment>> {
+    fn comments(&mut self) -> &mut Option<Comments<'a>> {
         &mut self.comments
     }
-
-    fn cur_cmnt(&mut self) -> &mut usize {
-        &mut self.cur_cmnt
-    }
 }
 
 impl<'a> State<'a> {
-    pub fn cbox(&mut self, u: usize) {
-        self.boxes.push(pp::Breaks::Consistent);
-        self.s.cbox(u);
-    }
-
-    crate fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) {
-        self.s.word(w);
-        self.nbsp()
-    }
-
     crate fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
         let w = w.into();
         // outer-box is consistent
@@ -830,26 +736,21 @@ impl<'a> State<'a> {
         self.end(); // close the head-box
     }
 
-    crate fn bclose_(&mut self, span: syntax_pos::Span,
-                   indented: usize) {
-        self.bclose_maybe_open(span, indented, true)
-    }
-    crate fn bclose_maybe_open(&mut self, span: syntax_pos::Span,
-                             indented: usize, close_box: bool) {
+    crate fn bclose_maybe_open(&mut self, span: syntax_pos::Span, close_box: bool) {
         self.maybe_print_comment(span.hi());
-        self.break_offset_if_not_bol(1, -(indented as isize));
+        self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
         self.s.word("}");
         if close_box {
             self.end(); // close the outer-box
         }
     }
     crate fn bclose(&mut self, span: syntax_pos::Span) {
-        self.bclose_(span, INDENT_UNIT)
+        self.bclose_maybe_open(span, true)
     }
 
     crate fn break_offset_if_not_bol(&mut self, n: usize,
                                    off: isize) {
-        if !self.is_bol() {
+        if !self.s.is_beginning_of_line() {
             self.s.break_offset(n, off)
         } else {
             if off != 0 && self.s.last_token().is_hardbreak_tok() {
@@ -1650,20 +1551,18 @@ impl<'a> State<'a> {
         self.print_block_with_attrs(blk, &[])
     }
 
-    crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block,
-                                       indented: usize) {
-        self.print_block_maybe_unclosed(blk, indented, &[], false)
+    crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
+        self.print_block_maybe_unclosed(blk, &[], false)
     }
 
     crate fn print_block_with_attrs(&mut self,
                                   blk: &ast::Block,
                                   attrs: &[ast::Attribute]) {
-        self.print_block_maybe_unclosed(blk, INDENT_UNIT, attrs, true)
+        self.print_block_maybe_unclosed(blk, attrs, true)
     }
 
     crate fn print_block_maybe_unclosed(&mut self,
                                       blk: &ast::Block,
-                                      indented: usize,
                                       attrs: &[ast::Attribute],
                                       close_box: bool) {
         match blk.rules {
@@ -1688,7 +1587,7 @@ impl<'a> State<'a> {
             }
         }
 
-        self.bclose_maybe_open(blk.span, indented, close_box);
+        self.bclose_maybe_open(blk.span, close_box);
         self.ann.post(self, AnnNode::Block(blk))
     }
 
@@ -2070,7 +1969,7 @@ impl<'a> State<'a> {
             }
             ast::ExprKind::Match(ref expr, ref arms) => {
                 self.cbox(INDENT_UNIT);
-                self.ibox(4);
+                self.ibox(INDENT_UNIT);
                 self.word_nbsp("match");
                 self.print_expr_as_cond(expr);
                 self.s.space();
@@ -2079,7 +1978,7 @@ impl<'a> State<'a> {
                 for arm in arms {
                     self.print_arm(arm);
                 }
-                self.bclose_(expr.span, INDENT_UNIT);
+                self.bclose(expr.span);
             }
             ast::ExprKind::Closure(
                 capture_clause, asyncness, movability, ref decl, ref body, _) => {
@@ -2610,7 +2509,7 @@ impl<'a> State<'a> {
                 }
 
                 // the block will close the pattern's ibox
-                self.print_block_unclosed_indent(blk, INDENT_UNIT);
+                self.print_block_unclosed_indent(blk);
 
                 // If it is a user-provided unsafe block, print a comma after it
                 if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
@@ -2963,18 +2862,10 @@ impl<'a> State<'a> {
 
     crate fn maybe_print_trailing_comment(&mut self, span: syntax_pos::Span,
                                         next_pos: Option<BytePos>)
-        {
-        let cm = match self.cm {
-            Some(cm) => cm,
-            _ => return,
-        };
-        if let Some(ref cmnt) = self.next_comment() {
-            if cmnt.style != comments::Trailing { return; }
-            let span_line = cm.lookup_char_pos(span.hi());
-            let comment_line = cm.lookup_char_pos(cmnt.pos);
-            let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
-            if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
-                self.print_comment(cmnt);
+    {
+        if let Some(cmnts) = self.comments() {
+            if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
+                self.print_comment(&cmnt);
             }
         }
     }
diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs
index 177080c04f9..418febbdc01 100644
--- a/src/test/mir-opt/loop_test.rs
+++ b/src/test/mir-opt/loop_test.rs
@@ -26,6 +26,7 @@ fn main() {
 //        _1 = ();
 //        StorageDead(_2);
 //        StorageDead(_1);
+//        StorageLive(_4);
 //        goto -> bb5;
 //    }
 //    ...
diff --git a/src/test/ui/borrowck/assign-never-type.rs b/src/test/ui/borrowck/assign-never-type.rs
new file mode 100644
index 00000000000..4f30ea14670
--- /dev/null
+++ b/src/test/ui/borrowck/assign-never-type.rs
@@ -0,0 +1,14 @@
+// Regression test for issue 62165
+
+// check-pass
+
+#![feature(never_type)]
+
+pub fn main() {
+    loop {
+        match None {
+            None => return,
+            Some(val) => val,
+        };
+    };
+}
diff --git a/src/test/ui/consts/const-eval/const_let.rs b/src/test/ui/consts/const-eval/const_let.rs
index 63321b91200..18692dbced6 100644
--- a/src/test/ui/consts/const-eval/const_let.rs
+++ b/src/test/ui/consts/const-eval/const_let.rs
@@ -9,10 +9,21 @@ impl Drop for FakeNeedsDrop {
 // ok
 const X: FakeNeedsDrop = { let x = FakeNeedsDrop; x };
 
+// ok (used to incorrectly error, see #62273)
+const X2: FakeNeedsDrop = { let x; x = FakeNeedsDrop; x };
+
 // error
 const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-//~^ ERROR constant contains unimplemented expression type
+//~^ ERROR destructors cannot be evaluated at compile-time
+
+// error
+const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
+//~^ ERROR destructors cannot be evaluated at compile-time
 
 // error
 const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
-//~^ ERROR constant contains unimplemented expression type
+//~^ ERROR destructors cannot be evaluated at compile-time
+
+// error
+const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
+//~^ ERROR destructors cannot be evaluated at compile-time
diff --git a/src/test/ui/consts/const-eval/const_let.stderr b/src/test/ui/consts/const-eval/const_let.stderr
index 00de97e6fb3..0a6a222ae29 100644
--- a/src/test/ui/consts/const-eval/const_let.stderr
+++ b/src/test/ui/consts/const-eval/const_let.stderr
@@ -1,15 +1,26 @@
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const_let.rs:13:55
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/const_let.rs:16:32
    |
 LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-   |                                                       ^
+   |                                ^^^^^ constants cannot evaluate destructors
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const_let.rs:17:35
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/const_let.rs:20:33
+   |
+LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
+   |                                 ^^^^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/const_let.rs:24:21
    |
 LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
-   |                                   ^
+   |                     ^^^^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/const_let.rs:28:22
+   |
+LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
+   |                      ^^^^^ constants cannot evaluate destructors
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0019`.