about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorn-salim <53019816+n-salim@users.noreply.github.com>2019-09-23 14:12:26 -0700
committerGitHub <noreply@github.com>2019-09-23 14:12:26 -0700
commitcd88dae21174f37aa47a45e4b848c4a5ececf19e (patch)
tree196ef2334e2f7787737af02f2e78ed53c10fb5a8 /src/libsyntax
parent494d83c89279a955dfb559ded5d5ac2ac06fc255 (diff)
parent66bf391c3aabfc77f5f7139fc9e6944f995d574e (diff)
downloadrust-cd88dae21174f37aa47a45e4b848c4a5ececf19e.tar.gz
rust-cd88dae21174f37aa47a45e4b848c4a5ececf19e.zip
Merge pull request #26 from rust-lang/master
Sync to rust-lang/rust master
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs3
-rw-r--r--src/libsyntax/ext/build.rs328
-rw-r--r--src/libsyntax/ext/proc_macro_server.rs4
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs5
-rw-r--r--src/libsyntax/feature_gate/accepted.rs2
-rw-r--r--src/libsyntax/feature_gate/active.rs3
-rw-r--r--src/libsyntax/feature_gate/check.rs1
-rw-r--r--src/libsyntax/json.rs26
-rw-r--r--src/libsyntax/lib.rs4
-rw-r--r--src/libsyntax/parse/attr.rs11
-rw-r--r--src/libsyntax/parse/diagnostics.rs16
-rw-r--r--src/libsyntax/parse/lexer/tests.rs1
-rw-r--r--src/libsyntax/parse/mod.rs4
-rw-r--r--src/libsyntax/parse/parser.rs4
-rw-r--r--src/libsyntax/parse/parser/expr.rs11
-rw-r--r--src/libsyntax/parse/parser/generics.rs99
-rw-r--r--src/libsyntax/parse/parser/pat.rs2
-rw-r--r--src/libsyntax/parse/parser/path.rs18
-rw-r--r--src/libsyntax/parse/parser/stmt.rs2
-rw-r--r--src/libsyntax/parse/parser/ty.rs6
-rw-r--r--src/libsyntax/tests.rs1
21 files changed, 132 insertions, 419 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 384c0555c85..a6be5b10178 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1048,9 +1048,6 @@ impl<'a> ExtCtxt<'a> {
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.parse_sess.span_diagnostic.span_warn(sp, msg);
     }
-    pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
-        self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
-    }
     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
         self.parse_sess.span_diagnostic.span_bug(sp, msg);
     }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index f1d0e0b68f7..f903b66e296 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -1,33 +1,28 @@
-use crate::ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind};
+use crate::ast::{self, Ident, Expr, BlockCheckMode, UnOp, PatKind};
 use crate::attr;
-use crate::source_map::{dummy_spanned, respan, Spanned};
+use crate::source_map::{respan, Spanned};
 use crate::ext::base::ExtCtxt;
 use crate::ptr::P;
 use crate::symbol::{kw, sym, Symbol};
 use crate::ThinVec;
 
-use rustc_target::spec::abi::Abi;
 use syntax_pos::{Pos, Span};
 
-// Left so that Cargo tests don't break, this can be removed once those no longer use it
-pub trait AstBuilder {}
-
 impl<'a> ExtCtxt<'a> {
     pub fn path(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path {
-        self.path_all(span, false, strs, vec![], vec![])
+        self.path_all(span, false, strs, vec![])
     }
     pub fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path {
         self.path(span, vec![id])
     }
     pub fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path {
-        self.path_all(span, true, strs, vec![], vec![])
+        self.path_all(span, true, strs, vec![])
     }
     pub fn path_all(&self,
                 span: Span,
                 global: bool,
                 mut idents: Vec<ast::Ident> ,
-                args: Vec<ast::GenericArg>,
-                constraints: Vec<ast::AssocTyConstraint> )
+                args: Vec<ast::GenericArg>)
                 -> ast::Path {
         assert!(!idents.is_empty());
         let add_root = global && !idents[0].is_path_segment_keyword();
@@ -39,8 +34,8 @@ impl<'a> ExtCtxt<'a> {
         segments.extend(idents.into_iter().map(|ident| {
             ast::PathSegment::from_ident(ident.with_span_pos(span))
         }));
-        let args = if !args.is_empty() || !constraints.is_empty() {
-            ast::AngleBracketedArgs { args, constraints, span }.into()
+        let args = if !args.is_empty() {
+            ast::AngleBracketedArgs { args, constraints: Vec::new(), span }.into()
         } else {
             None
         };
@@ -52,42 +47,6 @@ impl<'a> ExtCtxt<'a> {
         ast::Path { span, segments }
     }
 
-    /// Constructs a qualified path.
-    ///
-    /// Constructs a path like `<self_type as trait_path>::ident`.
-    pub fn qpath(&self,
-             self_type: P<ast::Ty>,
-             trait_path: ast::Path,
-             ident: ast::Ident)
-             -> (ast::QSelf, ast::Path) {
-        self.qpath_all(self_type, trait_path, ident, vec![], vec![])
-    }
-
-    /// Constructs a qualified path.
-    ///
-    /// Constructs a path like `<self_type as trait_path>::ident<'a, T, A = Bar>`.
-    pub fn qpath_all(&self,
-                 self_type: P<ast::Ty>,
-                 trait_path: ast::Path,
-                 ident: ast::Ident,
-                 args: Vec<ast::GenericArg>,
-                 constraints: Vec<ast::AssocTyConstraint>)
-                 -> (ast::QSelf, ast::Path) {
-        let mut path = trait_path;
-        let args = if !args.is_empty() || !constraints.is_empty() {
-            ast::AngleBracketedArgs { args, constraints, span: ident.span }.into()
-        } else {
-            None
-        };
-        path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args });
-
-        (ast::QSelf {
-            ty: self_type,
-            path_span: path.span,
-            position: path.segments.len() - 1
-        }, path)
-    }
-
     pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
         ast::MutTy {
             ty,
@@ -149,10 +108,6 @@ impl<'a> ExtCtxt<'a> {
                 ast::TyKind::Ptr(self.ty_mt(ty, mutbl)))
     }
 
-    pub fn ty_infer(&self, span: Span) -> P<ast::Ty> {
-        self.ty(span, ast::TyKind::Infer)
-    }
-
     pub fn typaram(&self,
                span: Span,
                ident: ast::Ident,
@@ -220,14 +175,6 @@ impl<'a> ExtCtxt<'a> {
         }
     }
 
-    pub fn stmt_semi(&self, expr: P<ast::Expr>) -> ast::Stmt {
-        ast::Stmt {
-            id: ast::DUMMY_NODE_ID,
-            span: expr.span,
-            node: ast::StmtKind::Semi(expr),
-        }
-    }
-
     pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: ast::Ident,
                 ex: P<ast::Expr>) -> ast::Stmt {
         let pat = if mutbl {
@@ -251,34 +198,6 @@ impl<'a> ExtCtxt<'a> {
         }
     }
 
-    pub fn stmt_let_typed(&self,
-                      sp: Span,
-                      mutbl: bool,
-                      ident: ast::Ident,
-                      typ: P<ast::Ty>,
-                      ex: P<ast::Expr>)
-                      -> ast::Stmt {
-        let pat = if mutbl {
-            let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mutable);
-            self.pat_ident_binding_mode(sp, ident, binding_mode)
-        } else {
-            self.pat_ident(sp, ident)
-        };
-        let local = P(ast::Local {
-            pat,
-            ty: Some(typ),
-            init: Some(ex),
-            id: ast::DUMMY_NODE_ID,
-            span: sp,
-            attrs: ThinVec::new(),
-        });
-        ast::Stmt {
-            id: ast::DUMMY_NODE_ID,
-            node: ast::StmtKind::Local(local),
-            span: sp,
-        }
-    }
-
     // Generates `let _: Type;`, which is usually used for type assertions.
     pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
         let local = P(ast::Local {
@@ -333,11 +252,6 @@ impl<'a> ExtCtxt<'a> {
         self.expr(path.span, ast::ExprKind::Path(None, path))
     }
 
-    /// Constructs a `QPath` expression.
-    pub fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P<ast::Expr> {
-        self.expr(span, ast::ExprKind::Path(Some(qself), path))
-    }
-
     pub fn expr_ident(&self, span: Span, id: ast::Ident) -> P<ast::Expr> {
         self.expr_path(self.path_ident(span, id))
     }
@@ -351,27 +265,12 @@ impl<'a> ExtCtxt<'a> {
     }
 
     pub fn expr_deref(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
-        self.expr_unary(sp, UnOp::Deref, e)
-    }
-    pub fn expr_unary(&self, sp: Span, op: ast::UnOp, e: P<ast::Expr>) -> P<ast::Expr> {
-        self.expr(sp, ast::ExprKind::Unary(op, e))
+        self.expr(sp, ast::ExprKind::Unary(UnOp::Deref, e))
     }
 
-    pub fn expr_field_access(
-        &self, sp: Span, expr: P<ast::Expr>, ident: ast::Ident,
-    ) -> P<ast::Expr> {
-        self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp)))
-    }
-    pub fn expr_tup_field_access(&self, sp: Span, expr: P<ast::Expr>, idx: usize) -> P<ast::Expr> {
-        let ident = Ident::new(sym::integer(idx), sp);
-        self.expr(sp, ast::ExprKind::Field(expr, ident))
-    }
     pub fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e))
     }
-    pub fn expr_mut_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
-        self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Mutable, e))
-    }
 
     pub fn expr_call(
         &self, span: Span, expr: P<ast::Expr>, args: Vec<P<ast::Expr>>,
@@ -427,28 +326,10 @@ impl<'a> ExtCtxt<'a> {
         self.expr_lit(span, ast::LitKind::Int(i as u128,
                                               ast::LitIntType::Unsigned(ast::UintTy::Usize)))
     }
-    pub fn expr_isize(&self, sp: Span, i: isize) -> P<ast::Expr> {
-        if i < 0 {
-            let i = (-i) as u128;
-            let lit_ty = ast::LitIntType::Signed(ast::IntTy::Isize);
-            let lit = self.expr_lit(sp, ast::LitKind::Int(i, lit_ty));
-            self.expr_unary(sp, ast::UnOp::Neg, lit)
-        } else {
-            self.expr_lit(sp, ast::LitKind::Int(i as u128,
-                                                ast::LitIntType::Signed(ast::IntTy::Isize)))
-        }
-    }
     pub fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr> {
         self.expr_lit(sp, ast::LitKind::Int(u as u128,
                                             ast::LitIntType::Unsigned(ast::UintTy::U32)))
     }
-    pub fn expr_u16(&self, sp: Span, u: u16) -> P<ast::Expr> {
-        self.expr_lit(sp, ast::LitKind::Int(u as u128,
-                                            ast::LitIntType::Unsigned(ast::UintTy::U16)))
-    }
-    pub fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr> {
-        self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U8)))
-    }
     pub fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr> {
         self.expr_lit(sp, ast::LitKind::Bool(value))
     }
@@ -456,10 +337,6 @@ impl<'a> ExtCtxt<'a> {
     pub fn expr_vec(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Array(exprs))
     }
-    pub fn expr_vec_ng(&self, sp: Span) -> P<ast::Expr> {
-        self.expr_call_global(sp, self.std_path(&[sym::vec, sym::Vec, sym::new]),
-                              Vec::new())
-    }
     pub fn expr_vec_slice(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
         self.expr_addr_of(sp, self.expr_vec(sp, exprs))
     }
@@ -476,16 +353,6 @@ impl<'a> ExtCtxt<'a> {
         self.expr_call_global(sp, some, vec![expr])
     }
 
-    pub fn expr_none(&self, sp: Span) -> P<ast::Expr> {
-        let none = self.std_path(&[sym::option, sym::Option, sym::None]);
-        let none = self.path_global(sp, none);
-        self.expr_path(none)
-    }
-
-    pub fn expr_break(&self, sp: Span) -> P<ast::Expr> {
-        self.expr(sp, ast::ExprKind::Break(None, None))
-    }
-
     pub fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Tup(exprs))
     }
@@ -514,11 +381,6 @@ impl<'a> ExtCtxt<'a> {
         self.expr_call_global(sp, ok, vec![expr])
     }
 
-    pub fn expr_err(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
-        let err = self.std_path(&[sym::result, sym::Result, sym::Err]);
-        self.expr_call_global(sp, err, vec![expr])
-    }
-
     pub fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> {
         let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]);
         let ok_path = self.path_global(sp, ok);
@@ -635,10 +497,6 @@ impl<'a> ExtCtxt<'a> {
         self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els))
     }
 
-    pub fn expr_loop(&self, span: Span, block: P<ast::Block>) -> P<ast::Expr> {
-        self.expr(span, ast::ExprKind::Loop(block, None))
-    }
-
     pub fn lambda_fn_decl(&self,
                       span: Span,
                       fn_decl: P<ast::FnDecl>,
@@ -659,7 +517,7 @@ impl<'a> ExtCtxt<'a> {
               body: P<ast::Expr>)
               -> P<ast::Expr> {
         let fn_decl = self.fn_decl(
-            ids.iter().map(|id| self.param(span, *id, self.ty_infer(span))).collect(),
+            ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(),
             ast::FunctionRetTy::Default(span));
 
         // FIXME -- We are using `span` as the span of the `|...|`
@@ -682,16 +540,6 @@ impl<'a> ExtCtxt<'a> {
         self.lambda(span, vec![ident], body)
     }
 
-    pub fn lambda_stmts(&self,
-                    span: Span,
-                    ids: Vec<ast::Ident>,
-                    stmts: Vec<ast::Stmt>)
-                    -> P<ast::Expr> {
-        self.lambda(span, ids, self.expr_block(self.block(span, stmts)))
-    }
-    pub fn lambda_stmts_0(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Expr> {
-        self.lambda0(span, self.expr_block(self.block(span, stmts)))
-    }
     pub fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>,
                       ident: ast::Ident) -> P<ast::Expr> {
         self.lambda1(span, self.expr_block(self.block(span, stmts)), ident)
@@ -733,43 +581,6 @@ impl<'a> ExtCtxt<'a> {
         })
     }
 
-    pub fn item_fn_poly(&self,
-                    span: Span,
-                    name: Ident,
-                    inputs: Vec<ast::Param> ,
-                    output: P<ast::Ty>,
-                    generics: Generics,
-                    body: P<ast::Block>) -> P<ast::Item> {
-        self.item(span,
-                  name,
-                  Vec::new(),
-                  ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)),
-                              ast::FnHeader {
-                                  unsafety: ast::Unsafety::Normal,
-                                  asyncness: dummy_spanned(ast::IsAsync::NotAsync),
-                                  constness: dummy_spanned(ast::Constness::NotConst),
-                                  abi: Abi::Rust,
-                              },
-                              generics,
-                              body))
-    }
-
-    pub fn item_fn(&self,
-               span: Span,
-               name: Ident,
-               inputs: Vec<ast::Param> ,
-               output: P<ast::Ty>,
-               body: P<ast::Block>
-              ) -> P<ast::Item> {
-        self.item_fn_poly(
-            span,
-            name,
-            inputs,
-            output,
-            Generics::default(),
-            body)
-    }
-
     pub fn variant(&self, span: Span, ident: Ident, tys: Vec<P<ast::Ty>> ) -> ast::Variant {
         let fields: Vec<_> = tys.into_iter().map(|ty| {
             ast::StructField {
@@ -800,52 +611,6 @@ impl<'a> ExtCtxt<'a> {
         }
     }
 
-    pub fn item_enum_poly(&self, span: Span, name: Ident,
-                      enum_definition: ast::EnumDef,
-                      generics: Generics) -> P<ast::Item> {
-        self.item(span, name, Vec::new(), ast::ItemKind::Enum(enum_definition, generics))
-    }
-
-    pub fn item_enum(&self, span: Span, name: Ident,
-                 enum_definition: ast::EnumDef) -> P<ast::Item> {
-        self.item_enum_poly(span, name, enum_definition,
-                            Generics::default())
-    }
-
-    pub fn item_struct(&self, span: Span, name: Ident,
-                   struct_def: ast::VariantData) -> P<ast::Item> {
-        self.item_struct_poly(
-            span,
-            name,
-            struct_def,
-            Generics::default()
-        )
-    }
-
-    pub fn item_struct_poly(&self, span: Span, name: Ident,
-        struct_def: ast::VariantData, generics: Generics) -> P<ast::Item> {
-        self.item(span, name, Vec::new(), ast::ItemKind::Struct(struct_def, generics))
-    }
-
-    pub fn item_mod(&self, span: Span, inner_span: Span, name: Ident,
-                attrs: Vec<ast::Attribute>,
-                items: Vec<P<ast::Item>>) -> P<ast::Item> {
-        self.item(
-            span,
-            name,
-            attrs,
-            ast::ItemKind::Mod(ast::Mod {
-                inner: inner_span,
-                items,
-                inline: true
-            })
-        )
-    }
-
-    pub fn item_extern_crate(&self, span: Span, name: Ident) -> P<ast::Item> {
-        self.item(span, name, Vec::new(), ast::ItemKind::ExternCrate(None))
-    }
-
     pub fn item_static(&self,
                    span: Span,
                    name: Ident,
@@ -865,15 +630,6 @@ impl<'a> ExtCtxt<'a> {
         self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, expr))
     }
 
-    pub fn item_ty_poly(&self, span: Span, name: Ident, ty: P<ast::Ty>,
-                    generics: Generics) -> P<ast::Item> {
-        self.item(span, name, Vec::new(), ast::ItemKind::TyAlias(ty, generics))
-    }
-
-    pub fn item_ty(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> P<ast::Item> {
-        self.item_ty_poly(span, name, ty, Generics::default())
-    }
-
     pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute {
         attr::mk_attr_outer(mi)
     }
@@ -881,70 +637,4 @@ impl<'a> ExtCtxt<'a> {
     pub fn meta_word(&self, sp: Span, w: ast::Name) -> ast::MetaItem {
         attr::mk_word_item(Ident::new(w, sp))
     }
-
-    pub fn meta_list_item_word(&self, sp: Span, w: ast::Name) -> ast::NestedMetaItem {
-        attr::mk_nested_word_item(Ident::new(w, sp))
-    }
-
-    pub fn meta_list(&self, sp: Span, name: ast::Name, mis: Vec<ast::NestedMetaItem>)
-                 -> ast::MetaItem {
-        attr::mk_list_item(Ident::new(name, sp), mis)
-    }
-
-    pub fn meta_name_value(&self, span: Span, name: ast::Name, lit_kind: ast::LitKind)
-                       -> ast::MetaItem {
-        attr::mk_name_value_item(Ident::new(name, span), lit_kind, span)
-    }
-
-    pub fn item_use(&self, sp: Span,
-                vis: ast::Visibility, vp: P<ast::UseTree>) -> P<ast::Item> {
-        P(ast::Item {
-            id: ast::DUMMY_NODE_ID,
-            ident: Ident::invalid(),
-            attrs: vec![],
-            node: ast::ItemKind::Use(vp),
-            vis,
-            span: sp,
-            tokens: None,
-        })
-    }
-
-    pub fn item_use_simple(&self, sp: Span, vis: ast::Visibility, path: ast::Path) -> P<ast::Item> {
-        self.item_use_simple_(sp, vis, None, path)
-    }
-
-    pub fn item_use_simple_(&self, sp: Span, vis: ast::Visibility,
-                        rename: Option<ast::Ident>, path: ast::Path) -> P<ast::Item> {
-        self.item_use(sp, vis, P(ast::UseTree {
-            span: sp,
-            prefix: path,
-            kind: ast::UseTreeKind::Simple(rename, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
-        }))
-    }
-
-    pub fn item_use_list(&self, sp: Span, vis: ast::Visibility,
-                     path: Vec<ast::Ident>, imports: &[ast::Ident]) -> P<ast::Item> {
-        let imports = imports.iter().map(|id| {
-            (ast::UseTree {
-                span: sp,
-                prefix: self.path(sp, vec![*id]),
-                kind: ast::UseTreeKind::Simple(None, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
-            }, ast::DUMMY_NODE_ID)
-        }).collect();
-
-        self.item_use(sp, vis, P(ast::UseTree {
-            span: sp,
-            prefix: self.path(sp, path),
-            kind: ast::UseTreeKind::Nested(imports),
-        }))
-    }
-
-    pub fn item_use_glob(&self, sp: Span,
-                     vis: ast::Visibility, path: Vec<ast::Ident>) -> P<ast::Item> {
-        self.item_use(sp, vis, P(ast::UseTree {
-            span: sp,
-            prefix: self.path(sp, path),
-            kind: ast::UseTreeKind::Glob,
-        }))
-    }
 }
diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs
index 544ec789d80..dfec9ee2880 100644
--- a/src/libsyntax/ext/proc_macro_server.rs
+++ b/src/libsyntax/ext/proc_macro_server.rs
@@ -4,7 +4,7 @@ use crate::parse::{self, token, ParseSess};
 use crate::parse::lexer::comments;
 use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
 
-use errors::{Diagnostic, DiagnosticBuilder};
+use errors::Diagnostic;
 use rustc_data_structures::sync::Lrc;
 use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
 use syntax_pos::symbol::{kw, sym, Symbol};
@@ -650,7 +650,7 @@ impl server::Diagnostic for Rustc<'_> {
         diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
     }
     fn emit(&mut self, diag: Self::Diagnostic) {
-        DiagnosticBuilder::new_diagnostic(&self.sess.span_diagnostic, diag).emit()
+        self.sess.span_diagnostic.emit_diagnostic(&diag);
     }
 }
 
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 23735727fe8..f9c07e3a2e4 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -8,6 +8,7 @@ use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
 
 use smallvec::{smallvec, SmallVec};
 
+use errors::pluralise;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use syntax_pos::hygiene::{ExpnId, Transparency};
@@ -348,10 +349,10 @@ impl LockstepIterSize {
                         "meta-variable `{}` repeats {} time{}, but `{}` repeats {} time{}",
                         l_id,
                         l_len,
-                        if l_len != 1 { "s" } else { "" },
+                        pluralise!(l_len),
                         r_id,
                         r_len,
-                        if r_len != 1 { "s" } else { "" },
+                        pluralise!(r_len),
                     );
                     LockstepIterSize::Contradiction(msg)
                 }
diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs
index eff9f90a861..5538daf388e 100644
--- a/src/libsyntax/feature_gate/accepted.rs
+++ b/src/libsyntax/feature_gate/accepted.rs
@@ -243,6 +243,8 @@ declare_features! (
     (accepted, async_await, "1.39.0", Some(50547), None),
     /// Allows mixing bind-by-move in patterns and references to those identifiers in guards.
     (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
+    /// Allows attributes in formal function parameters.
+    (accepted, param_attrs, "1.39.0", Some(60406), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs
index dd78777b569..38c16dbac6a 100644
--- a/src/libsyntax/feature_gate/active.rs
+++ b/src/libsyntax/feature_gate/active.rs
@@ -489,9 +489,6 @@ declare_features! (
     /// Allows the user of associated type bounds.
     (active, associated_type_bounds, "1.34.0", Some(52662), None),
 
-    /// Attributes on formal function params.
-    (active, param_attrs, "1.36.0", Some(60406), None),
-
     /// Allows calling constructor functions in `const fn`.
     (active, const_constructor, "1.37.0", Some(61456), None),
 
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index b4491a87f06..b50ca1ad1cf 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -812,7 +812,6 @@ pub fn check_crate(krate: &ast::Crate,
         }
     }
 
-    gate_all!(param_attrs, "attributes on function parameters are unstable");
     gate_all!(let_chains, "`let` expressions in this position are experimental");
     gate_all!(async_closure, "async closures are unstable");
     gate_all!(yields, generators, "yield syntax is experimental");
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index ada46f7bc5a..5cdea3aabbe 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -12,7 +12,7 @@
 use crate::source_map::{SourceMap, FilePathMapping};
 
 use errors::registry::Registry;
-use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, SourceMapper};
+use errors::{SubDiagnostic, CodeSuggestion, SourceMapper};
 use errors::{DiagnosticId, Applicability};
 use errors::emitter::{Emitter, HumanReadableErrorType};
 
@@ -32,6 +32,7 @@ pub struct JsonEmitter {
     pretty: bool,
     ui_testing: bool,
     json_rendered: HumanReadableErrorType,
+    external_macro_backtrace: bool,
 }
 
 impl JsonEmitter {
@@ -40,6 +41,7 @@ impl JsonEmitter {
         source_map: Lrc<SourceMap>,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        external_macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
             dst: Box::new(io::stderr()),
@@ -48,13 +50,18 @@ impl JsonEmitter {
             pretty,
             ui_testing: false,
             json_rendered,
+            external_macro_backtrace,
         }
     }
 
-    pub fn basic(pretty: bool, json_rendered: HumanReadableErrorType) -> JsonEmitter {
+    pub fn basic(
+        pretty: bool,
+        json_rendered: HumanReadableErrorType,
+        external_macro_backtrace: bool,
+    ) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
         JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)),
-                            pretty, json_rendered)
+                            pretty, json_rendered, external_macro_backtrace)
     }
 
     pub fn new(
@@ -63,6 +70,7 @@ impl JsonEmitter {
         source_map: Lrc<SourceMap>,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        external_macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
             dst,
@@ -71,6 +79,7 @@ impl JsonEmitter {
             pretty,
             ui_testing: false,
             json_rendered,
+            external_macro_backtrace,
         }
     }
 
@@ -80,8 +89,8 @@ impl JsonEmitter {
 }
 
 impl Emitter for JsonEmitter {
-    fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) {
-        let data = Diagnostic::from_diagnostic_builder(db, self);
+    fn emit_diagnostic(&mut self, db: &errors::Diagnostic) {
+        let data = Diagnostic::from_errors_diagnostic(db, self);
         let result = if self.pretty {
             writeln!(&mut self.dst, "{}", as_pretty_json(&data))
         } else {
@@ -189,7 +198,7 @@ struct ArtifactNotification<'a> {
 }
 
 impl Diagnostic {
-    fn from_diagnostic_builder(db: &DiagnosticBuilder<'_>,
+    fn from_errors_diagnostic(db: &errors::Diagnostic,
                                je: &JsonEmitter)
                                -> Diagnostic {
         let sugg = db.suggestions.iter().map(|sugg| {
@@ -219,8 +228,9 @@ impl Diagnostic {
         }
         let buf = BufWriter::default();
         let output = buf.clone();
-        je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false, None)
-            .ui_testing(je.ui_testing).emit_diagnostic(db);
+        je.json_rendered.new_emitter(
+            Box::new(buf), Some(je.sm.clone()), false, None, je.external_macro_backtrace
+        ).ui_testing(je.ui_testing).emit_diagnostic(db);
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
         let output = String::from_utf8(output).unwrap();
 
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index aaf6f3e537e..b4ae1e87bca 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -60,12 +60,12 @@ macro_rules! panictry {
 macro_rules! panictry_buffer {
     ($handler:expr, $e:expr) => ({
         use std::result::Result::{Ok, Err};
-        use errors::{FatalError, DiagnosticBuilder};
+        use errors::FatalError;
         match $e {
             Ok(e) => e,
             Err(errs) => {
                 for e in errs {
-                    DiagnosticBuilder::new_diagnostic($handler, e).emit();
+                    $handler.emit_diagnostic(&e);
                 }
                 FatalError.raise()
             }
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 9aa1ec0b14f..cf6151d17b1 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -19,13 +19,6 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                      permitted in this context";
 
 impl<'a> Parser<'a> {
-    crate fn parse_param_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
-        let attrs = self.parse_outer_attributes()?;
-        self.sess.gated_spans.param_attrs.borrow_mut()
-            .extend(attrs.iter().map(|a| a.span));
-        Ok(attrs)
-    }
-
     /// Parses attributes that appear before an item.
     crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
         let mut attrs: Vec<ast::Attribute> = Vec::new();
@@ -309,14 +302,14 @@ impl<'a> Parser<'a> {
             Ok(lit) => {
                 return Ok(ast::NestedMetaItem::Literal(lit))
             }
-            Err(ref mut err) => self.diagnostic().cancel(err)
+            Err(ref mut err) => err.cancel(),
         }
 
         match self.parse_meta_item() {
             Ok(mi) => {
                 return Ok(ast::NestedMetaItem::MetaItem(mi))
             }
-            Err(ref mut err) => self.diagnostic().cancel(err)
+            Err(ref mut err) => err.cancel(),
         }
 
         let found = self.this_token_to_string();
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index b74f2492c35..59de5f14123 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -11,7 +11,7 @@ use crate::ptr::P;
 use crate::symbol::{kw, sym};
 use crate::ThinVec;
 use crate::util::parser::AssocOp;
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise};
 use rustc_data_structures::fx::FxHashSet;
 use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError};
 use log::{debug, trace};
@@ -197,10 +197,6 @@ impl<'a> Parser<'a> {
         self.sess.span_diagnostic.span_bug(sp, m)
     }
 
-    crate fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
-        self.sess.span_diagnostic.cancel(err)
-    }
-
     crate fn diagnostic(&self) -> &'a errors::Handler {
         &self.sess.span_diagnostic
     }
@@ -426,15 +422,13 @@ impl<'a> Parser<'a> {
     /// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
     /// passes through any errors encountered. Used for error recovery.
     crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
-        let handler = self.diagnostic();
-
         if let Err(ref mut err) = self.parse_seq_to_before_tokens(
             kets,
             SeqSep::none(),
             TokenExpectType::Expect,
             |p| Ok(p.parse_token_tree()),
         ) {
-            handler.cancel(err);
+            err.cancel();
         }
     }
 
@@ -532,15 +526,15 @@ impl<'a> Parser<'a> {
             self.eat_to_tokens(&[&end]);
             let span = lo.until(self.token.span);
 
-            let plural = number_of_gt > 1 || number_of_shr >= 1;
+            let total_num_of_gt = number_of_gt + number_of_shr * 2;
             self.diagnostic()
                 .struct_span_err(
                     span,
-                    &format!("unmatched angle bracket{}", if plural { "s" } else { "" }),
+                    &format!("unmatched angle bracket{}", pluralise!(total_num_of_gt)),
                 )
                 .span_suggestion(
                     span,
-                    &format!("remove extra angle bracket{}", if plural { "s" } else { "" }),
+                    &format!("remove extra angle bracket{}", pluralise!(total_num_of_gt)),
                     String::new(),
                     Applicability::MachineApplicable,
                 )
diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs
index c1ec41902e2..de301b1fc49 100644
--- a/src/libsyntax/parse/lexer/tests.rs
+++ b/src/libsyntax/parse/lexer/tests.rs
@@ -18,6 +18,7 @@ fn mk_sess(sm: Lrc<SourceMap>) -> ParseSess {
         false,
         false,
         None,
+        false,
     );
     ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm)
 }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 2441a027f99..fa4c1043122 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -49,8 +49,6 @@ static_assert_size!(PResult<'_, bool>, 16);
 /// used and should be feature gated accordingly in `check_crate`.
 #[derive(Default)]
 pub struct GatedSpans {
-    /// Spans collected for gating `param_attrs`, e.g. `fn foo(#[attr] x: u8) {}`.
-    pub param_attrs: Lock<Vec<Span>>,
     /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`.
     pub let_chains: Lock<Vec<Span>>,
     /// Spans collected for gating `async_closure`, e.g. `async || ..`.
@@ -306,7 +304,7 @@ fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option<Span>)
     match try_file_to_source_file(sess, path, spanopt) {
         Ok(source_file) => source_file,
         Err(d) => {
-            DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, d).emit();
+            sess.span_diagnostic.emit_diagnostic(&d);
             FatalError.raise();
         }
     }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fcebfa29962..b2b6504919e 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -979,7 +979,7 @@ impl<'a> Parser<'a> {
         is_name_required: impl Fn(&token::Token) -> bool,
     ) -> PResult<'a, Param> {
         let lo = self.token.span;
-        let attrs = self.parse_param_attributes()?;
+        let attrs = self.parse_outer_attributes()?;
         if let Some(mut param) = self.parse_self_param()? {
             param.attrs = attrs.into();
             return self.recover_bad_self_param(param, is_trait_item);
@@ -1362,7 +1362,7 @@ impl<'a> Parser<'a> {
     /// Returns the parsed optional self parameter with attributes and whether a self
     /// shortcut was used.
     fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option<Param>> {
-        let attrs = self.parse_param_attributes()?;
+        let attrs = self.parse_outer_attributes()?;
         let param_opt = self.parse_self_param()?;
         Ok(param_opt.map(|mut param| {
             param.attrs = attrs.into();
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index 31b28443abb..d0c865a7b8e 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -66,6 +66,10 @@ pub(super) enum LhsExpr {
 }
 
 impl From<Option<ThinVec<Attribute>>> for LhsExpr {
+    /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)`
+    /// and `None` into `LhsExpr::NotYetParsed`.
+    ///
+    /// This conversion does not allocate.
     fn from(o: Option<ThinVec<Attribute>>) -> Self {
         if let Some(attrs) = o {
             LhsExpr::AttributesParsed(attrs)
@@ -76,6 +80,9 @@ impl From<Option<ThinVec<Attribute>>> for LhsExpr {
 }
 
 impl From<P<Expr>> for LhsExpr {
+    /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
+    ///
+    /// This conversion does not allocate.
     fn from(expr: P<Expr>) -> Self {
         LhsExpr::AlreadyParsed(expr)
     }
@@ -770,7 +777,7 @@ impl<'a> Parser<'a> {
                         ex = ExprKind::Lit(literal);
                     }
                     Err(mut err) => {
-                        self.cancel(&mut err);
+                        err.cancel();
                         return Err(self.expected_expression_found());
                     }
                 }
@@ -1176,7 +1183,7 @@ impl<'a> Parser<'a> {
     /// Parses a parameter in a closure header (e.g., `|arg, arg|`).
     fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
         let lo = self.token.span;
-        let attrs = self.parse_param_attributes()?;
+        let attrs = self.parse_outer_attributes()?;
         let pat = self.parse_pat(PARAM_EXPECTED)?;
         let t = if self.eat(&token::Colon) {
             self.parse_ty()?
diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs
index 3e6118ad86f..2ecd9cca3c6 100644
--- a/src/libsyntax/parse/parser/generics.rs
+++ b/src/libsyntax/parse/parser/generics.rs
@@ -100,13 +100,31 @@ impl<'a> Parser<'a> {
             } else if self.check_ident() {
                 // Parse type parameter.
                 params.push(self.parse_ty_param(attrs)?);
+            } else if self.token.can_begin_type() {
+                // Trying to write an associated type bound? (#26271)
+                let snapshot = self.clone();
+                match self.parse_ty_where_predicate() {
+                    Ok(where_predicate) => {
+                        self.struct_span_err(
+                            where_predicate.span(),
+                            "bounds on associated types do not belong here",
+                        )
+                        .span_label(where_predicate.span(), "belongs in `where` clause")
+                        .emit();
+                    }
+                    Err(mut err) => {
+                        err.cancel();
+                        std::mem::replace(self, snapshot);
+                        break
+                    }
+                }
             } else {
                 // Check for trailing attributes and stop parsing.
                 if !attrs.is_empty() {
                     if !params.is_empty() {
                         self.struct_span_err(
                             attrs[0].span,
-                            &format!("trailing attribute after generic parameter"),
+                            "trailing attribute after generic parameter",
                         )
                         .span_label(attrs[0].span, "attributes must go before parameters")
                         .emit();
@@ -202,43 +220,7 @@ impl<'a> Parser<'a> {
                     }
                 ));
             } else if self.check_type() {
-                // Parse optional `for<'a, 'b>`.
-                // This `for` is parsed greedily and applies to the whole predicate,
-                // the bounded type can have its own `for` applying only to it.
-                // Examples:
-                // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
-                // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
-                // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
-                let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
-
-                // Parse type with mandatory colon and (possibly empty) bounds,
-                // or with mandatory equality sign and the second type.
-                let ty = self.parse_ty()?;
-                if self.eat(&token::Colon) {
-                    let bounds = self.parse_generic_bounds(Some(self.prev_span))?;
-                    where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
-                        ast::WhereBoundPredicate {
-                            span: lo.to(self.prev_span),
-                            bound_generic_params: lifetime_defs,
-                            bounded_ty: ty,
-                            bounds,
-                        }
-                    ));
-                // FIXME: Decide what should be used here, `=` or `==`.
-                // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
-                } else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
-                    let rhs_ty = self.parse_ty()?;
-                    where_clause.predicates.push(ast::WherePredicate::EqPredicate(
-                        ast::WhereEqPredicate {
-                            span: lo.to(self.prev_span),
-                            lhs_ty: ty,
-                            rhs_ty,
-                            id: ast::DUMMY_NODE_ID,
-                        }
-                    ));
-                } else {
-                    return self.unexpected();
-                }
+                where_clause.predicates.push(self.parse_ty_where_predicate()?);
             } else {
                 break
             }
@@ -252,6 +234,47 @@ impl<'a> Parser<'a> {
         Ok(where_clause)
     }
 
+    fn parse_ty_where_predicate(&mut self) -> PResult<'a, ast::WherePredicate> {
+        let lo = self.token.span;
+        // Parse optional `for<'a, 'b>`.
+        // This `for` is parsed greedily and applies to the whole predicate,
+        // the bounded type can have its own `for` applying only to it.
+        // Examples:
+        // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>`
+        // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>`
+        // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
+        let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+
+        // Parse type with mandatory colon and (possibly empty) bounds,
+        // or with mandatory equality sign and the second type.
+        let ty = self.parse_ty()?;
+        if self.eat(&token::Colon) {
+            let bounds = self.parse_generic_bounds(Some(self.prev_span))?;
+            Ok(ast::WherePredicate::BoundPredicate(
+                ast::WhereBoundPredicate {
+                    span: lo.to(self.prev_span),
+                    bound_generic_params: lifetime_defs,
+                    bounded_ty: ty,
+                    bounds,
+                }
+            ))
+        // FIXME: Decide what should be used here, `=` or `==`.
+        // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
+        } else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
+            let rhs_ty = self.parse_ty()?;
+            Ok(ast::WherePredicate::EqPredicate(
+                ast::WhereEqPredicate {
+                    span: lo.to(self.prev_span),
+                    lhs_ty: ty,
+                    rhs_ty,
+                    id: ast::DUMMY_NODE_ID,
+                }
+            ))
+        } else {
+            self.unexpected()
+        }
+    }
+
     pub(super) fn choose_generics_over_qpath(&self) -> bool {
         // There's an ambiguity between generic parameters and qualified paths in impls.
         // If we see `<` it may start both, so we have to inspect some following tokens.
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index 08ee3a6bd86..3c624959ead 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -537,7 +537,7 @@ impl<'a> Parser<'a> {
         mut err: DiagnosticBuilder<'a>,
         expected: Expected,
     ) -> PResult<'a, P<Pat>> {
-        self.cancel(&mut err);
+        err.cancel();
 
         let expected = expected.unwrap_or("pattern");
         let msg = format!("expected {}, found {}", expected, self.this_token_descr());
diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs
index d4b13cc2e01..87839f8c70e 100644
--- a/src/libsyntax/parse/parser/path.rs
+++ b/src/libsyntax/parse/parser/path.rs
@@ -9,7 +9,7 @@ use crate::symbol::kw;
 
 use std::mem;
 use log::debug;
-use errors::{Applicability};
+use errors::{Applicability, pluralise};
 
 /// Specifies how to parse a path.
 #[derive(Copy, Clone, PartialEq)]
@@ -129,10 +129,11 @@ impl<'a> Parser<'a> {
         self.parse_path(style)
     }
 
-    crate fn parse_path_segments(&mut self,
-                           segments: &mut Vec<PathSegment>,
-                           style: PathStyle)
-                           -> PResult<'a, ()> {
+    crate fn parse_path_segments(
+        &mut self,
+        segments: &mut Vec<PathSegment>,
+        style: PathStyle,
+    ) -> PResult<'a, ()> {
         loop {
             let segment = self.parse_path_segment(style)?;
             if style == PathStyle::Expr {
@@ -201,7 +202,7 @@ impl<'a> Parser<'a> {
             } else {
                 // `(T, U) -> R`
                 let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
-                let span = lo.to(self.prev_span);
+                let span = ident.span.to(self.prev_span);
                 let output = if self.eat(&token::RArrow) {
                     Some(self.parse_ty_common(false, false, false)?)
                 } else {
@@ -347,20 +348,19 @@ impl<'a> Parser<'a> {
                 let span = lo.with_hi(
                     lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)
                 );
-                let plural = snapshot.unmatched_angle_bracket_count > 1;
                 self.diagnostic()
                     .struct_span_err(
                         span,
                         &format!(
                             "unmatched angle bracket{}",
-                            if plural { "s" } else { "" }
+                            pluralise!(snapshot.unmatched_angle_bracket_count)
                         ),
                     )
                     .span_suggestion(
                         span,
                         &format!(
                             "remove extra angle bracket{}",
-                            if plural { "s" } else { "" }
+                            pluralise!(snapshot.unmatched_angle_bracket_count)
                         ),
                         String::new(),
                         Applicability::MachineApplicable,
diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs
index 04bd61a4cfb..02da56f6e35 100644
--- a/src/libsyntax/parse/parser/stmt.rs
+++ b/src/libsyntax/parse/parser/stmt.rs
@@ -361,7 +361,7 @@ impl<'a> Parser<'a> {
                 }
                 Err(mut e) => {
                     self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
-                    self.cancel(&mut e);
+                    e.cancel();
                 }
                 _ => ()
             }
diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs
index 465e31ac57e..5697edd8e48 100644
--- a/src/libsyntax/parse/parser/ty.rs
+++ b/src/libsyntax/parse/parser/ty.rs
@@ -11,7 +11,7 @@ use crate::symbol::{kw};
 
 use rustc_target::spec::abi::Abi;
 
-use errors::{Applicability};
+use errors::{Applicability, pluralise};
 
 /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
 /// `IDENT<<u8 as Trait>::AssocTy>`.
@@ -397,7 +397,7 @@ impl<'a> Parser<'a> {
         }
 
         if !negative_bounds.is_empty() || was_negative {
-            let plural = negative_bounds.len() > 1;
+            let negative_bounds_len = negative_bounds.len();
             let last_span = negative_bounds.last().map(|sp| *sp);
             let mut err = self.struct_span_err(
                 negative_bounds,
@@ -420,7 +420,7 @@ impl<'a> Parser<'a> {
                 }
                 err.span_suggestion_hidden(
                     bound_list,
-                    &format!("remove the trait bound{}", if plural { "s" } else { "" }),
+                    &format!("remove the trait bound{}", pluralise!(negative_bounds_len)),
                     new_bound_list,
                     Applicability::MachineApplicable,
                 );
diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs
index 540881b0a54..f510ac9273d 100644
--- a/src/libsyntax/tests.rs
+++ b/src/libsyntax/tests.rs
@@ -147,6 +147,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
             false,
             false,
             None,
+            false,
         );
         let handler = Handler::with_emitter(true, None, Box::new(emitter));
         handler.span_err(msp, "foo");