diff --git a/src/doc/grammar.md b/src/doc/grammar.md
index ee9135b6578f6..4501d74073e90 100644
--- a/src/doc/grammar.md
+++ b/src/doc/grammar.md
@@ -1,812 +1,7 @@
 % Grammar
 
-# Introduction
+The Rust grammar may now be found in the [reference]. Additionally, the [grammar
+working group] is working on producing a testable grammar.
 
-This document is the primary reference for the Rust programming language grammar. It
-provides only one kind of material:
-
-  - Chapters that formally define the language grammar.
-
-This document does not serve as an introduction to the language. Background
-familiarity with the language is assumed. A separate [guide] is available to
-help acquire such background.
-
-This document also does not serve as a reference to the [standard] library
-included in the language distribution. Those libraries are documented
-separately by extracting documentation attributes from their source code. Many
-of the features that one might expect to be language features are library
-features in Rust, so what you're looking for may be there, not here.
-
-[guide]: guide.html
-[standard]: std/index.html
-
-# Notation
-
-Rust's grammar is defined over Unicode codepoints, each conventionally denoted
-`U+XXXX`, for 4 or more hexadecimal digits `X`. _Most_ of Rust's grammar is
-confined to the ASCII range of Unicode, and is described in this document by a
-dialect of Extended Backus-Naur Form (EBNF), specifically a dialect of EBNF
-supported by common automated LL(k) parsing tools such as `llgen`, rather than
-the dialect given in ISO 14977. The dialect can be defined self-referentially
-as follows:
-
-```antlr
-grammar : rule + ;
-rule    : nonterminal ':' productionrule ';' ;
-productionrule : production [ '|' production ] * ;
-production : term * ;
-term : element repeats ;
-element : LITERAL | IDENTIFIER | '[' productionrule ']' ;
-repeats : [ '*' | '+' ] NUMBER ? | NUMBER ? | '?' ;
-```
-
-Where:
-
-- Whitespace in the grammar is ignored.
-- Square brackets are used to group rules.
-- `LITERAL` is a single printable ASCII character, or an escaped hexadecimal
-  ASCII code of the form `\xQQ`, in single quotes, denoting the corresponding
-  Unicode codepoint `U+00QQ`.
-- `IDENTIFIER` is a nonempty string of ASCII letters and underscores.
-- The `repeat` forms apply to the adjacent `element`, and are as follows:
-  - `?` means zero or one repetition
-  - `*` means zero or more repetitions
-  - `+` means one or more repetitions
-  - NUMBER trailing a repeat symbol gives a maximum repetition count
-  - NUMBER on its own gives an exact repetition count
-
-This EBNF dialect should hopefully be familiar to many readers.
-
-## Unicode productions
-
-A few productions in Rust's grammar permit Unicode codepoints outside the ASCII
-range. We define these productions in terms of character properties specified
-in the Unicode standard, rather than in terms of ASCII-range codepoints. The
-section [Special Unicode Productions](#special-unicode-productions) lists these
-productions.
-
-## String table productions
-
-Some rules in the grammar — notably [unary
-operators](#unary-operator-expressions), [binary
-operators](#binary-operator-expressions), and [keywords](#keywords) — are
-given in a simplified form: as a listing of a table of unquoted, printable
-whitespace-separated strings. These cases form a subset of the rules regarding
-the [token](#tokens) rule, and are assumed to be the result of a
-lexical-analysis phase feeding the parser, driven by a DFA, operating over the
-disjunction of all such string table entries.
-
-When such a string enclosed in double-quotes (`"`) occurs inside the grammar,
-it is an implicit reference to a single member of such a string table
-production. See [tokens](#tokens) for more information.
-
-# Lexical structure
-
-## Input format
-
-Rust input is interpreted as a sequence of Unicode codepoints encoded in UTF-8.
-Most Rust grammar rules are defined in terms of printable ASCII-range
-codepoints, but a small number are defined in terms of Unicode properties or
-explicit codepoint lists. [^inputformat]
-
-[^inputformat]: Substitute definitions for the special Unicode productions are
-  provided to the grammar verifier, restricted to ASCII range, when verifying the
-  grammar in this document.
-
-## Special Unicode Productions
-
-The following productions in the Rust grammar are defined in terms of Unicode
-properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and
-`non_double_quote`.
-
-### Identifiers
-
-The `ident` production is any nonempty Unicode string of
-the following form:
-
-- The first character is in one of the following ranges `U+0041` to `U+005A`
-("A" to "Z"), `U+0061` to `U+007A` ("a" to "z"), or `U+005F` ("\_").
-- The remaining characters are in the range `U+0030` to `U+0039` ("0" to "9"),
-or any of the prior valid initial characters.
-
-as long as the identifier does _not_ occur in the set of [keywords](#keywords).
-
-### Delimiter-restricted productions
-
-Some productions are defined by exclusion of particular Unicode characters:
-
-- `non_null` is any single Unicode character aside from `U+0000` (null)
-- `non_eol` is any single Unicode character aside from `U+000A` (`'\n'`)
-- `non_single_quote` is any single Unicode character aside from `U+0027`  (`'`)
-- `non_double_quote` is any single Unicode character aside from `U+0022` (`"`)
-
-## Comments
-
-```antlr
-comment : block_comment | line_comment ;
-block_comment : "/*" block_comment_body * "*/" ;
-block_comment_body : [block_comment | character] * ;
-line_comment : "//" non_eol * ;
-```
-
-**FIXME:** add doc grammar?
-
-## Whitespace
-
-```antlr
-whitespace_char : '\x20' | '\x09' | '\x0a' | '\x0d' ;
-whitespace : [ whitespace_char | comment ] + ;
-```
-
-## Tokens
-
-```antlr
-simple_token : keyword | unop | binop ;
-token : simple_token | ident | literal | symbol | whitespace token ;
-```
-
-### Keywords
-
-<p id="keyword-table-marker"></p>
-
-|          |          |          |          |          |
-|----------|----------|----------|----------|----------|
-| _        | abstract | alignof  | as       | become   |
-| box      | break    | const    | continue | crate    |
-| do       | else     | enum     | extern   | false    |
-| final    | fn       | for      | if       | impl     |
-| in       | let      | loop     | macro    | match    |
-| mod      | move     | mut      | offsetof | override |
-| priv     | proc     | pub      | pure     | ref      |
-| return   | Self     | self     | sizeof   | static   |
-| struct   | super    | trait    | true     | type     |
-| typeof   | unsafe   | unsized  | use      | virtual  |
-| where    | while    | yield    |          |          |
-
-
-Each of these keywords has special meaning in its grammar, and all of them are
-excluded from the `ident` rule.
-
-Not all of these keywords are used by the language. Some of them were used
-before Rust 1.0, and were left reserved once their implementations were
-removed. Some of them were reserved before 1.0 to make space for possible
-future features.
-
-### Literals
-
-```antlr
-lit_suffix : ident;
-literal : [ string_lit | char_lit | byte_string_lit | byte_lit | num_lit | bool_lit ] lit_suffix ?;
-```
-
-The optional `lit_suffix` production is only used for certain numeric literals,
-but is reserved for future extension. That is, the above gives the lexical
-grammar, but a Rust parser will reject everything but the 12 special cases
-mentioned in [Number literals](reference/tokens.html#number-literals) in the
-reference.
-
-#### Character and string literals
-
-```antlr
-char_lit : '\x27' char_body '\x27' ;
-string_lit : '"' string_body * '"' | 'r' raw_string ;
-
-char_body : non_single_quote
-          | '\x5c' [ '\x27' | common_escape | unicode_escape ] ;
-
-string_body : non_double_quote
-            | '\x5c' [ '\x22' | common_escape | unicode_escape ] ;
-raw_string : '"' raw_string_body '"' | '#' raw_string '#' ;
-
-common_escape : '\x5c'
-              | 'n' | 'r' | 't' | '0'
-              | 'x' hex_digit 2
-unicode_escape : 'u' '{' hex_digit+ 6 '}';
-
-hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
-          | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
-          | dec_digit ;
-oct_digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' ;
-dec_digit : '0' | nonzero_dec ;
-nonzero_dec: '1' | '2' | '3' | '4'
-           | '5' | '6' | '7' | '8' | '9' ;
-```
-
-#### Byte and byte string literals
-
-```antlr
-byte_lit : "b\x27" byte_body '\x27' ;
-byte_string_lit : "b\x22" string_body * '\x22' | "br" raw_byte_string ;
-
-byte_body : ascii_non_single_quote
-          | '\x5c' [ '\x27' | common_escape ] ;
-
-byte_string_body : ascii_non_double_quote
-            | '\x5c' [ '\x22' | common_escape ] ;
-raw_byte_string : '"' raw_byte_string_body '"' | '#' raw_byte_string '#' ;
-
-```
-
-#### Number literals
-
-```antlr
-num_lit : nonzero_dec [ dec_digit | '_' ] * float_suffix ?
-        | '0' [       [ dec_digit | '_' ] * float_suffix ?
-              | 'b'   [ '1' | '0' | '_' ] +
-              | 'o'   [ oct_digit | '_' ] +
-              | 'x'   [ hex_digit | '_' ] +  ] ;
-
-float_suffix : [ exponent | '.' dec_lit exponent ? ] ? ;
-
-exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ;
-dec_lit : [ dec_digit | '_' ] + ;
-```
-
-#### Boolean literals
-
-```antlr
-bool_lit : [ "true" | "false" ] ;
-```
-
-The two values of the boolean type are written `true` and `false`.
-
-### Symbols
-
-```antlr
-symbol : "::" | "->"
-       | '#' | '[' | ']' | '(' | ')' | '{' | '}'
-       | ',' | ';' ;
-```
-
-Symbols are a general class of printable [tokens](#tokens) that play structural
-roles in a variety of grammar productions. They are cataloged here for
-completeness as the set of remaining miscellaneous printable tokens that do not
-otherwise appear as [unary operators](#unary-operator-expressions), [binary
-operators](#binary-operator-expressions), or [keywords](#keywords).
-
-## Paths
-
-```antlr
-expr_path : [ "::" ] ident [ "::" expr_path_tail ] + ;
-expr_path_tail : '<' type_expr [ ',' type_expr ] + '>'
-               | expr_path ;
-
-type_path : ident [ type_path_tail ] + ;
-type_path_tail : '<' type_expr [ ',' type_expr ] + '>'
-               | "::" type_path ;
-```
-
-# Syntax extensions
-
-## Macros
-
-```antlr
-expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ';'
-                 | "macro_rules" '!' ident '{' macro_rule * '}' ;
-macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ;
-matcher : '(' matcher * ')' | '[' matcher * ']'
-        | '{' matcher * '}' | '$' ident ':' ident
-        | '$' '(' matcher * ')' sep_token? [ '*' | '+' ]
-        | non_special_token ;
-transcriber : '(' transcriber * ')' | '[' transcriber * ']'
-            | '{' transcriber * '}' | '$' ident
-            | '$' '(' transcriber * ')' sep_token? [ '*' | '+' ]
-            | non_special_token ;
-```
-
-# Crates and source files
-
-**FIXME:** grammar? What production covers #![crate_id = "foo"] ?
-
-# Items and attributes
-
-**FIXME:** grammar?
-
-## Items
-
-```antlr
-item : vis ? mod_item | fn_item | type_item | struct_item | enum_item
-     | const_item | static_item | trait_item | impl_item | extern_block_item ;
-```
-
-### Type Parameters
-
-**FIXME:** grammar?
-
-### Modules
-
-```antlr
-mod_item : "mod" ident ( ';' | '{' mod '}' );
-mod : [ view_item | item ] * ;
-```
-
-#### View items
-
-```antlr
-view_item : extern_crate_decl | use_decl ';' ;
-```
-
-##### Extern crate declarations
-
-```antlr
-extern_crate_decl : "extern" "crate" crate_name
-crate_name: ident | ( ident "as" ident )
-```
-
-##### Use declarations
-
-```antlr
-use_decl : vis ? "use" [ path "as" ident
-                        | path_glob ] ;
-
-path_glob : ident [ "::" [ path_glob
-                          | '*' ] ] ?
-          | '{' path_item [ ',' path_item ] * '}' ;
-
-path_item : ident | "self" ;
-```
-
-### Functions
-
-**FIXME:** grammar?
-
-#### Generic functions
-
-**FIXME:** grammar?
-
-#### Unsafety
-
-**FIXME:** grammar?
-
-##### Unsafe functions
-
-**FIXME:** grammar?
-
-##### Unsafe blocks
-
-**FIXME:** grammar?
-
-#### Diverging functions
-
-**FIXME:** grammar?
-
-### Type definitions
-
-**FIXME:** grammar?
-
-### Structures
-
-**FIXME:** grammar?
-
-### Enumerations
-
-**FIXME:** grammar?
-
-### Constant items
-
-```antlr
-const_item : "const" ident ':' type '=' expr ';' ;
-```
-
-### Static items
-
-```antlr
-static_item : "static" ident ':' type '=' expr ';' ;
-```
-
-#### Mutable statics
-
-**FIXME:** grammar?
-
-### Traits
-
-**FIXME:** grammar?
-
-### Implementations
-
-**FIXME:** grammar?
-
-### External blocks
-
-```antlr
-extern_block_item : "extern" '{' extern_block '}' ;
-extern_block : [ foreign_fn ] * ;
-```
-
-## Visibility and Privacy
-
-```antlr
-vis : "pub" ;
-```
-### Re-exporting and Visibility
-
-See [Use declarations](#use-declarations).
-
-## Attributes
-
-```antlr
-attribute : '#' '!' ? '[' meta_item ']' ;
-meta_item : ident [ '=' literal
-                  | '(' meta_seq ')' ] ? ;
-meta_seq : meta_item [ ',' meta_seq ] ? ;
-```
-
-# Statements and expressions
-
-## Statements
-
-```antlr
-stmt : decl_stmt | expr_stmt | ';' ;
-```
-
-### Declaration statements
-
-```antlr
-decl_stmt : item | let_decl ;
-```
-
-#### Item declarations
-
-See [Items](#items).
-
-#### Variable declarations
-
-```antlr
-let_decl : "let" pat [':' type ] ? [ init ] ? ';' ;
-init : [ '=' ] expr ;
-```
-
-### Expression statements
-
-```antlr
-expr_stmt : expr ';' ;
-```
-
-## Expressions
-
-```antlr
-expr : literal | path | tuple_expr | unit_expr | struct_expr
-     | block_expr | method_call_expr | field_expr | array_expr
-     | idx_expr | range_expr | unop_expr | binop_expr
-     | paren_expr | call_expr | lambda_expr | while_expr
-     | loop_expr | break_expr | continue_expr | for_expr
-     | if_expr | match_expr | if_let_expr | while_let_expr
-     | return_expr ;
-```
-
-#### Lvalues, rvalues and temporaries
-
-**FIXME:** grammar?
-
-#### Moved and copied types
-
-**FIXME:** Do we want to capture this in the grammar as different productions?
-
-### Literal expressions
-
-See [Literals](#literals).
-
-### Path expressions
-
-See [Paths](#paths).
-
-### Tuple expressions
-
-```antlr
-tuple_expr : '(' [ expr [ ',' expr ] * | expr ',' ] ? ')' ;
-```
-
-### Unit expressions
-
-```antlr
-unit_expr : "()" ;
-```
-
-### Structure expressions
-
-```antlr
-struct_expr_field_init : ident | ident ':' expr ;
-struct_expr : expr_path '{' struct_expr_field_init
-                      [ ',' struct_expr_field_init ] *
-                      [ ".." expr ] '}' |
-              expr_path '(' expr
-                      [ ',' expr ] * ')' |
-              expr_path ;
-```
-
-### Block expressions
-
-```antlr
-block_expr : '{' [ stmt | item ] *
-                 [ expr ] '}' ;
-```
-
-### Method-call expressions
-
-```antlr
-method_call_expr : expr '.' ident paren_expr_list ;
-```
-
-### Field expressions
-
-```antlr
-field_expr : expr '.' ident ;
-```
-
-### Array expressions
-
-```antlr
-array_expr : '[' "mut" ? array_elems? ']' ;
-
-array_elems : [expr [',' expr]*] | [expr ';' expr] ;
-```
-
-### Index expressions
-
-```antlr
-idx_expr : expr '[' expr ']' ;
-```
-
-### Range expressions
-
-```antlr
-range_expr : expr ".." expr |
-             expr ".." |
-             ".." expr |
-             ".." ;
-```
-
-### Unary operator expressions
-
-```antlr
-unop_expr : unop expr ;
-unop : '-' | '*' | '!' ;
-```
-
-### Binary operator expressions
-
-```antlr
-binop_expr : expr binop expr | type_cast_expr
-           | assignment_expr | compound_assignment_expr ;
-binop : arith_op | bitwise_op | lazy_bool_op | comp_op
-```
-
-#### Arithmetic operators
-
-```antlr
-arith_op : '+' | '-' | '*' | '/' | '%' ;
-```
-
-#### Bitwise operators
-
-```antlr
-bitwise_op : '&' | '|' | '^' | "<<" | ">>" ;
-```
-
-#### Lazy boolean operators
-
-```antlr
-lazy_bool_op : "&&" | "||" ;
-```
-
-#### Comparison operators
-
-```antlr
-comp_op : "==" | "!=" | '<' | '>' | "<=" | ">=" ;
-```
-
-#### Type cast expressions
-
-```antlr
-type_cast_expr : value "as" type ;
-```
-
-#### Assignment expressions
-
-```antlr
-assignment_expr : expr '=' expr ;
-```
-
-#### Compound assignment expressions
-
-```antlr
-compound_assignment_expr : expr [ arith_op | bitwise_op ] '=' expr ;
-```
-
-### Grouped expressions
-
-```antlr
-paren_expr : '(' expr ')' ;
-```
-
-### Call expressions
-
-```antlr
-expr_list : [ expr [ ',' expr ]* ] ? ;
-paren_expr_list : '(' expr_list ')' ;
-call_expr : expr paren_expr_list ;
-```
-
-### Lambda expressions
-
-```antlr
-ident_list : [ ident [ ',' ident ]* ] ? ;
-lambda_expr : '|' ident_list '|' expr ;
-```
-
-### While loops
-
-```antlr
-while_expr : [ lifetime ':' ] ? "while" no_struct_literal_expr '{' block '}' ;
-```
-
-### Infinite loops
-
-```antlr
-loop_expr : [ lifetime ':' ] ? "loop" '{' block '}';
-```
-
-### Break expressions
-
-```antlr
-break_expr : "break" [ lifetime ] ?;
-```
-
-### Continue expressions
-
-```antlr
-continue_expr : "continue" [ lifetime ] ?;
-```
-
-### For expressions
-
-```antlr
-for_expr : [ lifetime ':' ] ? "for" pat "in" no_struct_literal_expr '{' block '}' ;
-```
-
-### If expressions
-
-```antlr
-if_expr : "if" no_struct_literal_expr '{' block '}'
-          else_tail ? ;
-
-else_tail : "else" [ if_expr | if_let_expr
-                   | '{' block '}' ] ;
-```
-
-### Match expressions
-
-```antlr
-match_expr : "match" no_struct_literal_expr '{' match_arm * '}' ;
-
-match_arm : attribute * match_pat "=>" [ expr "," | '{' block '}' ] ;
-
-match_pat : pat [ '|' pat ] * [ "if" expr ] ? ;
-```
-
-### If let expressions
-
-```antlr
-if_let_expr : "if" "let" pat '=' expr '{' block '}'
-               else_tail ? ;
-```
-
-### While let loops
-
-```antlr
-while_let_expr : [ lifetime ':' ] ? "while" "let" pat '=' expr '{' block '}' ;
-```
-
-### Return expressions
-
-```antlr
-return_expr : "return" expr ? ;
-```
-
-# Type system
-
-**FIXME:** is this entire chapter relevant here? Or should it all have been covered by some production already?
-
-## Types
-
-### Primitive types
-
-**FIXME:** grammar?
-
-#### Machine types
-
-**FIXME:** grammar?
-
-#### Machine-dependent integer types
-
-**FIXME:** grammar?
-
-### Textual types
-
-**FIXME:** grammar?
-
-### Tuple types
-
-**FIXME:** grammar?
-
-### Array, and Slice types
-
-**FIXME:** grammar?
-
-### Structure types
-
-**FIXME:** grammar?
-
-### Enumerated types
-
-**FIXME:** grammar?
-
-### Pointer types
-
-**FIXME:** grammar?
-
-### Function types
-
-**FIXME:** grammar?
-
-### Closure types
-
-```antlr
-closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
-                [ ':' bound-list ] [ '->' type ]
-lifetime-list := lifetime | lifetime ',' lifetime-list
-arg-list := ident ':' type | ident ':' type ',' arg-list
-```
-
-### Never type
-An empty type
-
-```antlr
-never_type : "!" ;
-```
-
-### Object types
-
-**FIXME:** grammar?
-
-### Type parameters
-
-**FIXME:** grammar?
-
-### Type parameter bounds
-
-```antlr
-bound-list := bound | bound '+' bound-list '+' ?
-bound := ty_bound | lt_bound
-lt_bound := lifetime
-ty_bound := ty_bound_noparen | (ty_bound_noparen)
-ty_bound_noparen := [?] [ for<lt_param_defs> ] simple_path
-```
-
-### Self types
-
-**FIXME:** grammar?
-
-## Type kinds
-
-**FIXME:** this is probably not relevant to the grammar...
-
-# Memory and concurrency models
-
-**FIXME:** is this entire chapter relevant here? Or should it all have been covered by some production already?
-
-## Memory model
-
-### Memory allocation and lifetime
-
-### Memory ownership
-
-### Variables
-
-### Boxes
-
-## Threads
-
-### Communication between threads
-
-### Thread lifecycle
+[reference]: https://doc.rust-lang.org/reference/
+[grammar working group]: https://github.com/rust-lang/wg-grammar
diff --git a/src/grammar/.gitignore b/src/grammar/.gitignore
deleted file mode 100644
index 3e4498759434f..0000000000000
--- a/src/grammar/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.class
-*.java
-*.tokens
diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l
deleted file mode 100644
index 1feb781b2b39f..0000000000000
--- a/src/grammar/lexer.l
+++ /dev/null
@@ -1,350 +0,0 @@
-%{
-#include <stdio.h>
-#include <ctype.h>
-
-static int num_hashes;
-static int end_hashes;
-static int saw_non_hash;
-
-%}
-
-%option stack
-%option yylineno
-
-%x str
-%x rawstr
-%x rawstr_esc_begin
-%x rawstr_esc_body
-%x rawstr_esc_end
-%x byte
-%x bytestr
-%x rawbytestr
-%x rawbytestr_nohash
-%x pound
-%x shebang_or_attr
-%x ltorchar
-%x linecomment
-%x doc_line
-%x blockcomment
-%x doc_block
-%x suffix
-
-ident [a-zA-Z\x80-\xff_][a-zA-Z0-9\x80-\xff_]*
-
-%%
-
-<suffix>{ident}            { BEGIN(INITIAL); }
-<suffix>(.|\n)  { yyless(0); BEGIN(INITIAL); }
-
-[ \n\t\r]             { }
-
-\xef\xbb\xbf {
-  // UTF-8 byte order mark (BOM), ignore if in line 1, error otherwise
-  if (yyget_lineno() != 1) {
-    return -1;
-  }
-}
-
-\/\/(\/|\!)           { BEGIN(doc_line); yymore(); }
-<doc_line>\n          { BEGIN(INITIAL);
-                        yyleng--;
-                        yytext[yyleng] = 0;
-                        return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT);
-                      }
-<doc_line>[^\n]*      { yymore(); }
-
-\/\/|\/\/\/\/         { BEGIN(linecomment); }
-<linecomment>\n       { BEGIN(INITIAL); }
-<linecomment>[^\n]*   { }
-
-\/\*(\*|\!)[^*]       { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); }
-<doc_block>\/\*       { yy_push_state(doc_block); yymore(); }
-<doc_block>\*\/       {
-    yy_pop_state();
-    if (yy_top_state() == doc_block) {
-        yymore();
-    } else {
-        return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT);
-    }
-}
-<doc_block>(.|\n)     { yymore(); }
-
-\/\*                  { yy_push_state(blockcomment); }
-<blockcomment>\/\*    { yy_push_state(blockcomment); }
-<blockcomment>\*\/    { yy_pop_state(); }
-<blockcomment>(.|\n)   { }
-
-_        { return UNDERSCORE; }
-abstract { return ABSTRACT; }
-alignof  { return ALIGNOF; }
-as       { return AS; }
-become   { return BECOME; }
-box      { return BOX; }
-break    { return BREAK; }
-catch    { return CATCH; }
-const    { return CONST; }
-continue { return CONTINUE; }
-crate    { return CRATE; }
-default  { return DEFAULT; }
-do       { return DO; }
-else     { return ELSE; }
-enum     { return ENUM; }
-extern   { return EXTERN; }
-false    { return FALSE; }
-final    { return FINAL; }
-fn       { return FN; }
-for      { return FOR; }
-if       { return IF; }
-impl     { return IMPL; }
-in       { return IN; }
-let      { return LET; }
-loop     { return LOOP; }
-macro    { return MACRO; }
-match    { return MATCH; }
-mod      { return MOD; }
-move     { return MOVE; }
-mut      { return MUT; }
-offsetof { return OFFSETOF; }
-override { return OVERRIDE; }
-priv     { return PRIV; }
-proc     { return PROC; }
-pure     { return PURE; }
-pub      { return PUB; }
-ref      { return REF; }
-return   { return RETURN; }
-self     { return SELF; }
-sizeof   { return SIZEOF; }
-static   { return STATIC; }
-struct   { return STRUCT; }
-super    { return SUPER; }
-trait    { return TRAIT; }
-true     { return TRUE; }
-type     { return TYPE; }
-typeof   { return TYPEOF; }
-union    { return UNION; }
-unsafe   { return UNSAFE; }
-unsized  { return UNSIZED; }
-use      { return USE; }
-virtual  { return VIRTUAL; }
-where    { return WHERE; }
-while    { return WHILE; }
-yield    { return YIELD; }
-
-{ident}  { return IDENT; }
-
-0x[0-9a-fA-F_]+                                    { BEGIN(suffix); return LIT_INTEGER; }
-0o[0-7_]+                                          { BEGIN(suffix); return LIT_INTEGER; }
-0b[01_]+                                           { BEGIN(suffix); return LIT_INTEGER; }
-[0-9][0-9_]*                                       { BEGIN(suffix); return LIT_INTEGER; }
-[0-9][0-9_]*\.(\.|[a-zA-Z])    { yyless(yyleng - 2); BEGIN(suffix); return LIT_INTEGER; }
-
-[0-9][0-9_]*\.[0-9_]*([eE][-\+]?[0-9_]+)?          { BEGIN(suffix); return LIT_FLOAT; }
-[0-9][0-9_]*(\.[0-9_]*)?[eE][-\+]?[0-9_]+          { BEGIN(suffix); return LIT_FLOAT; }
-
-;      { return ';'; }
-,      { return ','; }
-\.\.\. { return DOTDOTDOT; }
-\.\.   { return DOTDOT; }
-\.     { return '.'; }
-\(     { return '('; }
-\)     { return ')'; }
-\{     { return '{'; }
-\}     { return '}'; }
-\[     { return '['; }
-\]     { return ']'; }
-@      { return '@'; }
-#      { BEGIN(pound); yymore(); }
-<pound>\! { BEGIN(shebang_or_attr); yymore(); }
-<shebang_or_attr>\[ {
-  BEGIN(INITIAL);
-  yyless(2);
-  return SHEBANG;
-}
-<shebang_or_attr>[^\[\n]*\n {
-  // Since the \n was eaten as part of the token, yylineno will have
-  // been incremented to the value 2 if the shebang was on the first
-  // line. This yyless undoes that, setting yylineno back to 1.
-  yyless(yyleng - 1);
-  if (yyget_lineno() == 1) {
-    BEGIN(INITIAL);
-    return SHEBANG_LINE;
-  } else {
-    BEGIN(INITIAL);
-    yyless(2);
-    return SHEBANG;
-  }
-}
-<pound>. { BEGIN(INITIAL); yyless(1); return '#'; }
-
-\~     { return '~'; }
-::     { return MOD_SEP; }
-:      { return ':'; }
-\$     { return '$'; }
-\?     { return '?'; }
-
-==    { return EQEQ; }
-=>    { return FAT_ARROW; }
-=     { return '='; }
-\!=   { return NE; }
-\!    { return '!'; }
-\<=   { return LE; }
-\<\<  { return SHL; }
-\<\<= { return SHLEQ; }
-\<    { return '<'; }
-\>=   { return GE; }
-\>\>  { return SHR; }
-\>\>= { return SHREQ; }
-\>    { return '>'; }
-
-\x27                                      { BEGIN(ltorchar); yymore(); }
-<ltorchar>static                          { BEGIN(INITIAL); return STATIC_LIFETIME; }
-<ltorchar>{ident}                         { BEGIN(INITIAL); return LIFETIME; }
-<ltorchar>\\[nrt\\\x27\x220]\x27          { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>\\x[0-9a-fA-F]{2}\x27           { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>\\u\{([0-9a-fA-F]_*){1,6}\}\x27 { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>.\x27                           { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>[\x80-\xff]{2,4}\x27            { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar><<EOF>>                         { BEGIN(INITIAL); return -1; }
-
-b\x22              { BEGIN(bytestr); yymore(); }
-<bytestr>\x22      { BEGIN(suffix); return LIT_BYTE_STR; }
-
-<bytestr><<EOF>>                     { return -1; }
-<bytestr>\\[n\nrt\\\x27\x220]        { yymore(); }
-<bytestr>\\x[0-9a-fA-F]{2}           { yymore(); }
-<bytestr>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); }
-<bytestr>\\[^n\nrt\\\x27\x220]       { return -1; }
-<bytestr>(.|\n)                      { yymore(); }
-
-br\x22                      { BEGIN(rawbytestr_nohash); yymore(); }
-<rawbytestr_nohash>\x22     { BEGIN(suffix); return LIT_BYTE_STR_RAW; }
-<rawbytestr_nohash>(.|\n)   { yymore(); }
-<rawbytestr_nohash><<EOF>>  { return -1; }
-
-br/# {
-    BEGIN(rawbytestr);
-    yymore();
-    num_hashes = 0;
-    saw_non_hash = 0;
-    end_hashes = 0;
-}
-<rawbytestr># {
-    if (!saw_non_hash) {
-        num_hashes++;
-    } else if (end_hashes != 0) {
-        end_hashes++;
-        if (end_hashes == num_hashes) {
-            BEGIN(INITIAL);
-            return LIT_BYTE_STR_RAW;
-        }
-    }
-    yymore();
-}
-<rawbytestr>\x22# {
-    end_hashes = 1;
-    if (end_hashes == num_hashes) {
-        BEGIN(INITIAL);
-        return LIT_BYTE_STR_RAW;
-    }
-    yymore();
-}
-<rawbytestr>(.|\n) {
-    if (!saw_non_hash) {
-        saw_non_hash = 1;
-    }
-    if (end_hashes != 0) {
-        end_hashes = 0;
-    }
-    yymore();
-}
-<rawbytestr><<EOF>> { return -1; }
-
-b\x27                           { BEGIN(byte); yymore(); }
-<byte>\\[nrt\\\x27\x220]\x27    { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>\\x[0-9a-fA-F]{2}\x27     { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>\\u([0-9a-fA-F]_*){4}\x27 { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>\\U([0-9a-fA-F]_*){8}\x27 { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>.\x27                     { BEGIN(INITIAL); return LIT_BYTE; }
-<byte><<EOF>>                   { BEGIN(INITIAL); return -1; }
-
-r\x22           { BEGIN(rawstr); yymore(); }
-<rawstr>\x22    { BEGIN(suffix); return LIT_STR_RAW; }
-<rawstr>(.|\n)  { yymore(); }
-<rawstr><<EOF>> { return -1; }
-
-r/#             {
-    BEGIN(rawstr_esc_begin);
-    yymore();
-    num_hashes = 0;
-    saw_non_hash = 0;
-    end_hashes = 0;
-}
-
-<rawstr_esc_begin># {
-    num_hashes++;
-    yymore();
-}
-<rawstr_esc_begin>\x22 {
-    BEGIN(rawstr_esc_body);
-    yymore();
-}
-<rawstr_esc_begin>(.|\n) { return -1; }
-
-<rawstr_esc_body>\x22/# {
-  BEGIN(rawstr_esc_end);
-  yymore();
- }
-<rawstr_esc_body>(.|\n) {
-  yymore();
- }
-
-<rawstr_esc_end># {
-  end_hashes++;
-  if (end_hashes == num_hashes) {
-    BEGIN(INITIAL);
-    return LIT_STR_RAW;
-  }
-  yymore();
- }
-<rawstr_esc_end>[^#] {
-  end_hashes = 0;
-  BEGIN(rawstr_esc_body);
-  yymore();
- }
-
-<rawstr_esc_begin,rawstr_esc_body,rawstr_esc_end><<EOF>> { return -1; }
-
-\x22                     { BEGIN(str); yymore(); }
-<str>\x22                { BEGIN(suffix); return LIT_STR; }
-
-<str><<EOF>>                     { return -1; }
-<str>\\[n\nr\rt\\\x27\x220]      { yymore(); }
-<str>\\x[0-9a-fA-F]{2}           { yymore(); }
-<str>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); }
-<str>\\[^n\nrt\\\x27\x220]       { return -1; }
-<str>(.|\n)                      { yymore(); }
-
-\<-  { return LARROW; }
--\>  { return RARROW; }
--    { return '-'; }
--=   { return MINUSEQ; }
-&&   { return ANDAND; }
-&    { return '&'; }
-&=   { return ANDEQ; }
-\|\| { return OROR; }
-\|   { return '|'; }
-\|=  { return OREQ; }
-\+   { return '+'; }
-\+=  { return PLUSEQ; }
-\*   { return '*'; }
-\*=  { return STAREQ; }
-\/   { return '/'; }
-\/=  { return SLASHEQ; }
-\^   { return '^'; }
-\^=  { return CARETEQ; }
-%    { return '%'; }
-%=   { return PERCENTEQ; }
-
-<<EOF>> { return 0; }
-
-%%
diff --git a/src/grammar/parser-lalr-main.c b/src/grammar/parser-lalr-main.c
deleted file mode 100644
index 6348190cc140b..0000000000000
--- a/src/grammar/parser-lalr-main.c
+++ /dev/null
@@ -1,193 +0,0 @@
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-extern int yylex();
-extern int rsparse();
-
-#define PUSHBACK_LEN 4
-
-static char pushback[PUSHBACK_LEN];
-static int verbose;
-
-void print(const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  if (verbose) {
-    vprintf(format, args);
-  }
-  va_end(args);
-}
-
-// If there is a non-null char at the head of the pushback queue,
-// dequeue it and shift the rest of the queue forwards. Otherwise,
-// return the token from calling yylex.
-int rslex() {
-  if (pushback[0] == '\0') {
-    return yylex();
-  } else {
-    char c = pushback[0];
-    memmove(pushback, pushback + 1, PUSHBACK_LEN - 1);
-    pushback[PUSHBACK_LEN - 1] = '\0';
-    return c;
-  }
-}
-
-// Note: this does nothing if the pushback queue is full. As long as
-// there aren't more than PUSHBACK_LEN consecutive calls to push_back
-// in an action, this shouldn't be a problem.
-void push_back(char c) {
-  for (int i = 0; i < PUSHBACK_LEN; ++i) {
-    if (pushback[i] == '\0') {
-      pushback[i] = c;
-      break;
-    }
-  }
-}
-
-extern int rsdebug;
-
-struct node {
-  struct node *next;
-  struct node *prev;
-  int own_string;
-  char const *name;
-  int n_elems;
-  struct node *elems[];
-};
-
-struct node *nodes = NULL;
-int n_nodes;
-
-struct node *mk_node(char const *name, int n, ...) {
-  va_list ap;
-  int i = 0;
-  unsigned sz = sizeof(struct node) + (n * sizeof(struct node *));
-  struct node *nn, *nd = (struct node *)malloc(sz);
-
-  print("# New %d-ary node: %s = %p\n", n, name, nd);
-
-  nd->own_string = 0;
-  nd->prev = NULL;
-  nd->next = nodes;
-  if (nodes) {
-    nodes->prev = nd;
-  }
-  nodes = nd;
-
-  nd->name = name;
-  nd->n_elems = n;
-
-  va_start(ap, n);
-  while (i < n) {
-    nn = va_arg(ap, struct node *);
-    print("#   arg[%d]: %p\n", i, nn);
-    print("#            (%s ...)\n", nn->name);
-    nd->elems[i++] = nn;
-  }
-  va_end(ap);
-  n_nodes++;
-  return nd;
-}
-
-struct node *mk_atom(char *name) {
-  struct node *nd = mk_node((char const *)strdup(name), 0);
-  nd->own_string = 1;
-  return nd;
-}
-
-struct node *mk_none() {
-  return mk_atom("<none>");
-}
-
-struct node *ext_node(struct node *nd, int n, ...) {
-  va_list ap;
-  int i = 0, c = nd->n_elems + n;
-  unsigned sz = sizeof(struct node) + (c * sizeof(struct node *));
-  struct node *nn;
-
-  print("# Extending %d-ary node by %d nodes: %s = %p",
-        nd->n_elems, c, nd->name, nd);
-
-  if (nd->next) {
-    nd->next->prev = nd->prev;
-  }
-  if (nd->prev) {
-    nd->prev->next = nd->next;
-  }
-  nd = realloc(nd, sz);
-  nd->prev = NULL;
-  nd->next = nodes;
-  nodes->prev = nd;
-  nodes = nd;
-
-  print(" ==> %p\n", nd);
-
-  va_start(ap, n);
-  while (i < n) {
-    nn = va_arg(ap, struct node *);
-    print("#   arg[%d]: %p\n", i, nn);
-    print("#            (%s ...)\n", nn->name);
-    nd->elems[nd->n_elems++] = nn;
-    ++i;
-  }
-  va_end(ap);
-  return nd;
-}
-
-int const indent_step = 4;
-
-void print_indent(int depth) {
-  while (depth) {
-    if (depth-- % indent_step == 0) {
-      print("|");
-    } else {
-      print(" ");
-    }
-  }
-}
-
-void print_node(struct node *n, int depth) {
-  int i = 0;
-  print_indent(depth);
-  if (n->n_elems == 0) {
-    print("%s\n", n->name);
-  } else {
-    print("(%s\n", n->name);
-    for (i = 0; i < n->n_elems; ++i) {
-      print_node(n->elems[i], depth + indent_step);
-    }
-    print_indent(depth);
-    print(")\n");
-  }
-}
-
-int main(int argc, char **argv) {
-  if (argc == 2 && strcmp(argv[1], "-v") == 0) {
-    verbose = 1;
-  } else {
-    verbose = 0;
-  }
-  int ret = 0;
-  struct node *tmp;
-  memset(pushback, '\0', PUSHBACK_LEN);
-  ret = rsparse();
-  print("--- PARSE COMPLETE: ret:%d, n_nodes:%d ---\n", ret, n_nodes);
-  if (nodes) {
-    print_node(nodes, 0);
-  }
-  while (nodes) {
-    tmp = nodes;
-    nodes = tmp->next;
-    if (tmp->own_string) {
-      free((void*)tmp->name);
-    }
-    free(tmp);
-  }
-  return ret;
-}
-
-void rserror(char const *s) {
-  fprintf(stderr, "%s\n", s);
-}
diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y
deleted file mode 100644
index 5585c95a5a63a..0000000000000
--- a/src/grammar/parser-lalr.y
+++ /dev/null
@@ -1,1982 +0,0 @@
-%{
-#define YYERROR_VERBOSE
-#define YYSTYPE struct node *
-struct node;
-extern int yylex();
-extern void yyerror(char const *s);
-extern struct node *mk_node(char const *name, int n, ...);
-extern struct node *mk_atom(char *text);
-extern struct node *mk_none();
-extern struct node *ext_node(struct node *nd, int n, ...);
-extern void push_back(char c);
-extern char *yytext;
-%}
-%debug
-
-%token SHL
-%token SHR
-%token LE
-%token EQEQ
-%token NE
-%token GE
-%token ANDAND
-%token OROR
-%token SHLEQ
-%token SHREQ
-%token MINUSEQ
-%token ANDEQ
-%token OREQ
-%token PLUSEQ
-%token STAREQ
-%token SLASHEQ
-%token CARETEQ
-%token PERCENTEQ
-%token DOTDOT
-%token DOTDOTDOT
-%token MOD_SEP
-%token RARROW
-%token LARROW
-%token FAT_ARROW
-%token LIT_BYTE
-%token LIT_CHAR
-%token LIT_INTEGER
-%token LIT_FLOAT
-%token LIT_STR
-%token LIT_STR_RAW
-%token LIT_BYTE_STR
-%token LIT_BYTE_STR_RAW
-%token IDENT
-%token UNDERSCORE
-%token LIFETIME
-
-// keywords
-%token SELF
-%token STATIC
-%token ABSTRACT
-%token ALIGNOF
-%token AS
-%token BECOME
-%token BREAK
-%token CATCH
-%token CRATE
-%token DO
-%token ELSE
-%token ENUM
-%token EXTERN
-%token FALSE
-%token FINAL
-%token FN
-%token FOR
-%token IF
-%token IMPL
-%token IN
-%token LET
-%token LOOP
-%token MACRO
-%token MATCH
-%token MOD
-%token MOVE
-%token MUT
-%token OFFSETOF
-%token OVERRIDE
-%token PRIV
-%token PUB
-%token PURE
-%token REF
-%token RETURN
-%token SIZEOF
-%token STRUCT
-%token SUPER
-%token UNION
-%token UNSIZED
-%token TRUE
-%token TRAIT
-%token TYPE
-%token UNSAFE
-%token VIRTUAL
-%token YIELD
-%token DEFAULT
-%token USE
-%token WHILE
-%token CONTINUE
-%token PROC
-%token BOX
-%token CONST
-%token WHERE
-%token TYPEOF
-%token INNER_DOC_COMMENT
-%token OUTER_DOC_COMMENT
-
-%token SHEBANG
-%token SHEBANG_LINE
-%token STATIC_LIFETIME
-
- /*
-   Quoting from the Bison manual:
-
-   "Finally, the resolution of conflicts works by comparing the precedence
-   of the rule being considered with that of the lookahead token. If the
-   token's precedence is higher, the choice is to shift. If the rule's
-   precedence is higher, the choice is to reduce. If they have equal
-   precedence, the choice is made based on the associativity of that
-   precedence level. The verbose output file made by ā€˜-v’ (see Invoking
-   Bison) says how each conflict was resolved"
- */
-
-// We expect no shift/reduce or reduce/reduce conflicts in this grammar;
-// all potential ambiguities are scrutinized and eliminated manually.
-%expect 0
-
-// fake-precedence symbol to cause '|' bars in lambda context to parse
-// at low precedence, permit things like |x| foo = bar, where '=' is
-// otherwise lower-precedence than '|'. Also used for proc() to cause
-// things like proc() a + b to parse as proc() { a + b }.
-%precedence LAMBDA
-
-%precedence SELF
-
-// MUT should be lower precedence than IDENT so that in the pat rule,
-// "& MUT pat" has higher precedence than "binding_mode ident [@ pat]"
-%precedence MUT
-
-// IDENT needs to be lower than '{' so that 'foo {' is shifted when
-// trying to decide if we've got a struct-construction expr (esp. in
-// contexts like 'if foo { .')
-//
-// IDENT also needs to be lower precedence than '<' so that '<' in
-// 'foo:bar . <' is shifted (in a trait reference occurring in a
-// bounds list), parsing as foo:(bar<baz>) rather than (foo:bar)<baz>.
-%precedence IDENT
- // Put the weak keywords that can be used as idents here as well
-%precedence CATCH
-%precedence DEFAULT
-%precedence UNION
-
-// A couple fake-precedence symbols to use in rules associated with +
-// and < in trailing type contexts. These come up when you have a type
-// in the RHS of operator-AS, such as "foo as bar<baz>". The "<" there
-// has to be shifted so the parser keeps trying to parse a type, even
-// though it might well consider reducing the type "bar" and then
-// going on to "<" as a subsequent binop. The "+" case is with
-// trailing type-bounds ("foo as bar:A+B"), for the same reason.
-%precedence SHIFTPLUS
-
-%precedence MOD_SEP
-%precedence RARROW ':'
-
-// In where clauses, "for" should have greater precedence when used as
-// a higher ranked constraint than when used as the beginning of a
-// for_in_type (which is a ty)
-%precedence FORTYPE
-%precedence FOR
-
-// Binops & unops, and their precedences
-%precedence '?'
-%precedence BOX
-%nonassoc DOTDOT
-
-// RETURN needs to be lower-precedence than tokens that start
-// prefix_exprs
-%precedence RETURN YIELD
-
-%right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ
-%right LARROW
-%left OROR
-%left ANDAND
-%left EQEQ NE
-%left '<' '>' LE GE
-%left '|'
-%left '^'
-%left '&'
-%left SHL SHR
-%left '+' '-'
-%precedence AS
-%left '*' '/' '%'
-%precedence '!'
-
-%precedence '{' '[' '(' '.'
-
-%precedence RANGE
-
-%start crate
-
-%%
-
-////////////////////////////////////////////////////////////////////////
-// Part 1: Items and attributes
-////////////////////////////////////////////////////////////////////////
-
-crate
-: maybe_shebang inner_attrs maybe_mod_items  { mk_node("crate", 2, $2, $3); }
-| maybe_shebang maybe_mod_items  { mk_node("crate", 1, $2); }
-;
-
-maybe_shebang
-: SHEBANG_LINE
-| %empty
-;
-
-maybe_inner_attrs
-: inner_attrs
-| %empty                   { $$ = mk_none(); }
-;
-
-inner_attrs
-: inner_attr               { $$ = mk_node("InnerAttrs", 1, $1); }
-| inner_attrs inner_attr   { $$ = ext_node($1, 1, $2); }
-;
-
-inner_attr
-: SHEBANG '[' meta_item ']'   { $$ = mk_node("InnerAttr", 1, $3); }
-| INNER_DOC_COMMENT           { $$ = mk_node("InnerAttr", 1, mk_node("doc-comment", 1, mk_atom(yytext))); }
-;
-
-maybe_outer_attrs
-: outer_attrs
-| %empty                   { $$ = mk_none(); }
-;
-
-outer_attrs
-: outer_attr               { $$ = mk_node("OuterAttrs", 1, $1); }
-| outer_attrs outer_attr   { $$ = ext_node($1, 1, $2); }
-;
-
-outer_attr
-: '#' '[' meta_item ']'    { $$ = $3; }
-| OUTER_DOC_COMMENT        { $$ = mk_node("doc-comment", 1, mk_atom(yytext)); }
-;
-
-meta_item
-: ident                      { $$ = mk_node("MetaWord", 1, $1); }
-| ident '=' lit              { $$ = mk_node("MetaNameValue", 2, $1, $3); }
-| ident '(' meta_seq ')'     { $$ = mk_node("MetaList", 2, $1, $3); }
-| ident '(' meta_seq ',' ')' { $$ = mk_node("MetaList", 2, $1, $3); }
-;
-
-meta_seq
-: %empty                   { $$ = mk_none(); }
-| meta_item                { $$ = mk_node("MetaItems", 1, $1); }
-| meta_seq ',' meta_item   { $$ = ext_node($1, 1, $3); }
-;
-
-maybe_mod_items
-: mod_items
-| %empty             { $$ = mk_none(); }
-;
-
-mod_items
-: mod_item                               { $$ = mk_node("Items", 1, $1); }
-| mod_items mod_item                     { $$ = ext_node($1, 1, $2); }
-;
-
-attrs_and_vis
-: maybe_outer_attrs visibility           { $$ = mk_node("AttrsAndVis", 2, $1, $2); }
-;
-
-mod_item
-: attrs_and_vis item    { $$ = mk_node("Item", 2, $1, $2); }
-;
-
-// items that can appear outside of a fn block
-item
-: stmt_item
-| item_macro
-;
-
-// items that can appear in "stmts"
-stmt_item
-: item_static
-| item_const
-| item_type
-| block_item
-| view_item
-;
-
-item_static
-: STATIC ident ':' ty '=' expr ';'  { $$ = mk_node("ItemStatic", 3, $2, $4, $6); }
-| STATIC MUT ident ':' ty '=' expr ';'  { $$ = mk_node("ItemStatic", 3, $3, $5, $7); }
-;
-
-item_const
-: CONST ident ':' ty '=' expr ';'  { $$ = mk_node("ItemConst", 3, $2, $4, $6); }
-;
-
-item_macro
-: path_expr '!' maybe_ident parens_delimited_token_trees ';'  { $$ = mk_node("ItemMacro", 3, $1, $3, $4); }
-| path_expr '!' maybe_ident braces_delimited_token_trees      { $$ = mk_node("ItemMacro", 3, $1, $3, $4); }
-| path_expr '!' maybe_ident brackets_delimited_token_trees ';'{ $$ = mk_node("ItemMacro", 3, $1, $3, $4); }
-;
-
-view_item
-: use_item
-| extern_fn_item
-| EXTERN CRATE ident ';'                      { $$ = mk_node("ViewItemExternCrate", 1, $3); }
-| EXTERN CRATE ident AS ident ';'             { $$ = mk_node("ViewItemExternCrate", 2, $3, $5); }
-;
-
-extern_fn_item
-: EXTERN maybe_abi item_fn                    { $$ = mk_node("ViewItemExternFn", 2, $2, $3); }
-;
-
-use_item
-: USE view_path ';'                           { $$ = mk_node("ViewItemUse", 1, $2); }
-;
-
-view_path
-: path_no_types_allowed                                    { $$ = mk_node("ViewPathSimple", 1, $1); }
-| path_no_types_allowed MOD_SEP '{'                '}'     { $$ = mk_node("ViewPathList", 2, $1, mk_atom("ViewPathListEmpty")); }
-|                       MOD_SEP '{'                '}'     { $$ = mk_node("ViewPathList", 1, mk_atom("ViewPathListEmpty")); }
-| path_no_types_allowed MOD_SEP '{' idents_or_self '}'     { $$ = mk_node("ViewPathList", 2, $1, $4); }
-|                       MOD_SEP '{' idents_or_self '}'     { $$ = mk_node("ViewPathList", 1, $3); }
-| path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); }
-|                       MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); }
-| path_no_types_allowed MOD_SEP '*'                        { $$ = mk_node("ViewPathGlob", 1, $1); }
-|                       MOD_SEP '*'                        { $$ = mk_atom("ViewPathGlob"); }
-|                               '*'                        { $$ = mk_atom("ViewPathGlob"); }
-|                               '{'                '}'     { $$ = mk_atom("ViewPathListEmpty"); }
-|                               '{' idents_or_self '}'     { $$ = mk_node("ViewPathList", 1, $2); }
-|                               '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); }
-| path_no_types_allowed AS ident                           { $$ = mk_node("ViewPathSimple", 2, $1, $3); }
-;
-
-block_item
-: item_fn
-| item_unsafe_fn
-| item_mod
-| item_foreign_mod          { $$ = mk_node("ItemForeignMod", 1, $1); }
-| item_struct
-| item_enum
-| item_union
-| item_trait
-| item_impl
-;
-
-maybe_ty_ascription
-: ':' ty_sum { $$ = $2; }
-| %empty { $$ = mk_none(); }
-;
-
-maybe_init_expr
-: '=' expr { $$ = $2; }
-| %empty   { $$ = mk_none(); }
-;
-
-// structs
-item_struct
-: STRUCT ident generic_params maybe_where_clause struct_decl_args
-{
-  $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5);
-}
-| STRUCT ident generic_params struct_tuple_args maybe_where_clause ';'
-{
-  $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5);
-}
-| STRUCT ident generic_params maybe_where_clause ';'
-{
-  $$ = mk_node("ItemStruct", 3, $2, $3, $4);
-}
-;
-
-struct_decl_args
-: '{' struct_decl_fields '}'                  { $$ = $2; }
-| '{' struct_decl_fields ',' '}'              { $$ = $2; }
-;
-
-struct_tuple_args
-: '(' struct_tuple_fields ')'                 { $$ = $2; }
-| '(' struct_tuple_fields ',' ')'             { $$ = $2; }
-;
-
-struct_decl_fields
-: struct_decl_field                           { $$ = mk_node("StructFields", 1, $1); }
-| struct_decl_fields ',' struct_decl_field    { $$ = ext_node($1, 1, $3); }
-| %empty                                      { $$ = mk_none(); }
-;
-
-struct_decl_field
-: attrs_and_vis ident ':' ty_sum              { $$ = mk_node("StructField", 3, $1, $2, $4); }
-;
-
-struct_tuple_fields
-: struct_tuple_field                          { $$ = mk_node("StructFields", 1, $1); }
-| struct_tuple_fields ',' struct_tuple_field  { $$ = ext_node($1, 1, $3); }
-| %empty                                      { $$ = mk_none(); }
-;
-
-struct_tuple_field
-: attrs_and_vis ty_sum                    { $$ = mk_node("StructField", 2, $1, $2); }
-;
-
-// enums
-item_enum
-: ENUM ident generic_params maybe_where_clause '{' enum_defs '}'     { $$ = mk_node("ItemEnum", 0); }
-| ENUM ident generic_params maybe_where_clause '{' enum_defs ',' '}' { $$ = mk_node("ItemEnum", 0); }
-;
-
-enum_defs
-: enum_def               { $$ = mk_node("EnumDefs", 1, $1); }
-| enum_defs ',' enum_def { $$ = ext_node($1, 1, $3); }
-| %empty                 { $$ = mk_none(); }
-;
-
-enum_def
-: attrs_and_vis ident enum_args { $$ = mk_node("EnumDef", 3, $1, $2, $3); }
-;
-
-enum_args
-: '{' struct_decl_fields '}'     { $$ = mk_node("EnumArgs", 1, $2); }
-| '{' struct_decl_fields ',' '}' { $$ = mk_node("EnumArgs", 1, $2); }
-| '(' maybe_ty_sums ')'          { $$ = mk_node("EnumArgs", 1, $2); }
-| '=' expr                       { $$ = mk_node("EnumArgs", 1, $2); }
-| %empty                         { $$ = mk_none(); }
-;
-
-// unions
-item_union
-: UNION ident generic_params maybe_where_clause '{' struct_decl_fields '}'     { $$ = mk_node("ItemUnion", 0); }
-| UNION ident generic_params maybe_where_clause '{' struct_decl_fields ',' '}' { $$ = mk_node("ItemUnion", 0); }
-
-item_mod
-: MOD ident ';'                                 { $$ = mk_node("ItemMod", 1, $2); }
-| MOD ident '{' maybe_mod_items '}'             { $$ = mk_node("ItemMod", 2, $2, $4); }
-| MOD ident '{' inner_attrs maybe_mod_items '}' { $$ = mk_node("ItemMod", 3, $2, $4, $5); }
-;
-
-item_foreign_mod
-: EXTERN maybe_abi '{' maybe_foreign_items '}'             { $$ = mk_node("ItemForeignMod", 1, $4); }
-| EXTERN maybe_abi '{' inner_attrs maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 2, $4, $5); }
-;
-
-maybe_abi
-: str
-| %empty { $$ = mk_none(); }
-;
-
-maybe_foreign_items
-: foreign_items
-| %empty { $$ = mk_none(); }
-;
-
-foreign_items
-: foreign_item               { $$ = mk_node("ForeignItems", 1, $1); }
-| foreign_items foreign_item { $$ = ext_node($1, 1, $2); }
-;
-
-foreign_item
-: attrs_and_vis STATIC item_foreign_static { $$ = mk_node("ForeignItem", 2, $1, $3); }
-| attrs_and_vis item_foreign_fn            { $$ = mk_node("ForeignItem", 2, $1, $2); }
-| attrs_and_vis UNSAFE item_foreign_fn     { $$ = mk_node("ForeignItem", 2, $1, $3); }
-;
-
-item_foreign_static
-: maybe_mut ident ':' ty ';'               { $$ = mk_node("StaticItem", 3, $1, $2, $4); }
-;
-
-item_foreign_fn
-: FN ident generic_params fn_decl_allow_variadic maybe_where_clause ';' { $$ = mk_node("ForeignFn", 4, $2, $3, $4, $5); }
-;
-
-fn_decl_allow_variadic
-: fn_params_allow_variadic ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); }
-;
-
-fn_params_allow_variadic
-: '(' ')'                      { $$ = mk_none(); }
-| '(' params ')'               { $$ = $2; }
-| '(' params ',' ')'           { $$ = $2; }
-| '(' params ',' DOTDOTDOT ')' { $$ = $2; }
-;
-
-visibility
-: PUB      { $$ = mk_atom("Public"); }
-| %empty   { $$ = mk_atom("Inherited"); }
-;
-
-idents_or_self
-: ident_or_self                    { $$ = mk_node("IdentsOrSelf", 1, $1); }
-| idents_or_self AS ident          { $$ = mk_node("IdentsOrSelf", 2, $1, $3); }
-| idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); }
-;
-
-ident_or_self
-: ident
-| SELF  { $$ = mk_atom(yytext); }
-;
-
-item_type
-: TYPE ident generic_params maybe_where_clause '=' ty_sum ';'  { $$ = mk_node("ItemTy", 4, $2, $3, $4, $6); }
-;
-
-for_sized
-: FOR '?' ident { $$ = mk_node("ForSized", 1, $3); }
-| FOR ident '?' { $$ = mk_node("ForSized", 1, $2); }
-| %empty        { $$ = mk_none(); }
-;
-
-item_trait
-: maybe_unsafe TRAIT ident generic_params for_sized maybe_ty_param_bounds maybe_where_clause '{' maybe_trait_items '}'
-{
-  $$ = mk_node("ItemTrait", 7, $1, $3, $4, $5, $6, $7, $9);
-}
-;
-
-maybe_trait_items
-: trait_items
-| %empty { $$ = mk_none(); }
-;
-
-trait_items
-: trait_item               { $$ = mk_node("TraitItems", 1, $1); }
-| trait_items trait_item   { $$ = ext_node($1, 1, $2); }
-;
-
-trait_item
-: trait_const
-| trait_type
-| trait_method
-| maybe_outer_attrs item_macro { $$ = mk_node("TraitMacroItem", 2, $1, $2); }
-;
-
-trait_const
-: maybe_outer_attrs CONST ident maybe_ty_ascription maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 4, $1, $3, $4, $5); }
-;
-
-maybe_const_default
-: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
-| %empty   { $$ = mk_none(); }
-;
-
-trait_type
-: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
-;
-
-maybe_unsafe
-: UNSAFE { $$ = mk_atom("Unsafe"); }
-| %empty { $$ = mk_none(); }
-;
-
-maybe_default_maybe_unsafe
-: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); }
-| DEFAULT        { $$ = mk_atom("Default"); }
-|         UNSAFE { $$ = mk_atom("Unsafe"); }
-| %empty { $$ = mk_none(); }
-
-trait_method
-: type_method { $$ = mk_node("Required", 1, $1); }
-| method      { $$ = mk_node("Provided", 1, $1); }
-;
-
-type_method
-: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
-{
-  $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7);
-}
-| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
-{
-  $$ = mk_node("TypeMethod", 6, $1, $3, $5, $6, $7, $8);
-}
-| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
-{
-  $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9);
-}
-;
-
-method
-: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8);
-}
-| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("Method", 7, $1, $3, $5, $6, $7, $8, $9);
-}
-| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10);
-}
-;
-
-impl_method
-: attrs_and_vis maybe_default maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("Method", 8, $1, $2, $3, $5, $6, $7, $8, $9);
-}
-| attrs_and_vis maybe_default CONST maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10);
-}
-| attrs_and_vis maybe_default maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("Method", 9, $1, $2, $3, $5, $7, $8, $9, $10, $11);
-}
-;
-
-// There are two forms of impl:
-//
-// impl (<...>)? TY { ... }
-// impl (<...>)? TRAIT for TY { ... }
-//
-// Unfortunately since TY can begin with '<' itself -- as part of a
-// TyQualifiedPath type -- there's an s/r conflict when we see '<' after IMPL:
-// should we reduce one of the early rules of TY (such as maybe_once)
-// or shall we continue shifting into the generic_params list for the
-// impl?
-//
-// The production parser disambiguates a different case here by
-// permitting / requiring the user to provide parens around types when
-// they are ambiguous with traits. We do the same here, regrettably,
-// by splitting ty into ty and ty_prim.
-item_impl
-: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
-{
-  $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8);
-}
-| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
-{
-  $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10);
-}
-| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
-{
-  $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10);
-}
-| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
-{
-  $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11);
-}
-| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}'
-{
-  $$ = mk_node("ItemImplDefault", 3, $1, $3, $4);
-}
-| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}'
-{
-  $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4);
-}
-;
-
-maybe_impl_items
-: impl_items
-| %empty { $$ = mk_none(); }
-;
-
-impl_items
-: impl_item               { $$ = mk_node("ImplItems", 1, $1); }
-| impl_item impl_items    { $$ = ext_node($1, 1, $2); }
-;
-
-impl_item
-: impl_method
-| attrs_and_vis item_macro { $$ = mk_node("ImplMacroItem", 2, $1, $2); }
-| impl_const
-| impl_type
-;
-
-maybe_default
-: DEFAULT { $$ = mk_atom("Default"); }
-| %empty { $$ = mk_none(); }
-;
-
-impl_const
-: attrs_and_vis maybe_default item_const { $$ = mk_node("ImplConst", 3, $1, $2, $3); }
-;
-
-impl_type
-: attrs_and_vis maybe_default TYPE ident generic_params '=' ty_sum ';'  { $$ = mk_node("ImplType", 5, $1, $2, $4, $5, $7); }
-;
-
-item_fn
-: FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6);
-}
-| CONST FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("ItemFn", 5, $3, $4, $5, $6, $7);
-}
-;
-
-item_unsafe_fn
-: UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7);
-}
-| CONST UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("ItemUnsafeFn", 5, $4, $5, $6, $7, $8);
-}
-| UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
-{
-  $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9);
-}
-;
-
-fn_decl
-: fn_params ret_ty   { $$ = mk_node("FnDecl", 2, $1, $2); }
-;
-
-fn_decl_with_self
-: fn_params_with_self ret_ty   { $$ = mk_node("FnDecl", 2, $1, $2); }
-;
-
-fn_decl_with_self_allow_anon_params
-: fn_anon_params_with_self ret_ty   { $$ = mk_node("FnDecl", 2, $1, $2); }
-;
-
-fn_params
-: '(' maybe_params ')'  { $$ = $2; }
-;
-
-fn_anon_params
-: '(' anon_param anon_params_allow_variadic_tail ')' { $$ = ext_node($2, 1, $3); }
-| '(' ')'                                            { $$ = mk_none(); }
-;
-
-fn_params_with_self
-: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')'              { $$ = mk_node("SelfLower", 3, $2, $4, $5); }
-| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')'          { $$ = mk_node("SelfRegion", 3, $3, $5, $6); }
-| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); }
-| '(' maybe_params ')'                                                       { $$ = mk_node("SelfStatic", 1, $2); }
-;
-
-fn_anon_params_with_self
-: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')'              { $$ = mk_node("SelfLower", 3, $2, $4, $5); }
-| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')'          { $$ = mk_node("SelfRegion", 3, $3, $5, $6); }
-| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); }
-| '(' maybe_anon_params ')'                                                       { $$ = mk_node("SelfStatic", 1, $2); }
-;
-
-maybe_params
-: params
-| params ','
-| %empty  { $$ = mk_none(); }
-;
-
-params
-: param                { $$ = mk_node("Args", 1, $1); }
-| params ',' param     { $$ = ext_node($1, 1, $3); }
-;
-
-param
-: pat ':' ty_sum   { $$ = mk_node("Arg", 2, $1, $3); }
-;
-
-inferrable_params
-: inferrable_param                       { $$ = mk_node("InferrableParams", 1, $1); }
-| inferrable_params ',' inferrable_param { $$ = ext_node($1, 1, $3); }
-;
-
-inferrable_param
-: pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); }
-;
-
-maybe_comma_params
-: ','            { $$ = mk_none(); }
-| ',' params     { $$ = $2; }
-| ',' params ',' { $$ = $2; }
-| %empty         { $$ = mk_none(); }
-;
-
-maybe_comma_anon_params
-: ','                 { $$ = mk_none(); }
-| ',' anon_params     { $$ = $2; }
-| ',' anon_params ',' { $$ = $2; }
-| %empty              { $$ = mk_none(); }
-;
-
-maybe_anon_params
-: anon_params
-| anon_params ','
-| %empty      { $$ = mk_none(); }
-;
-
-anon_params
-: anon_param                 { $$ = mk_node("Args", 1, $1); }
-| anon_params ',' anon_param { $$ = ext_node($1, 1, $3); }
-;
-
-// anon means it's allowed to be anonymous (type-only), but it can
-// still have a name
-anon_param
-: named_arg ':' ty   { $$ = mk_node("Arg", 2, $1, $3); }
-| ty
-;
-
-anon_params_allow_variadic_tail
-: ',' DOTDOTDOT                                  { $$ = mk_none(); }
-| ',' anon_param anon_params_allow_variadic_tail { $$ = mk_node("Args", 2, $2, $3); }
-| %empty                                         { $$ = mk_none(); }
-;
-
-named_arg
-: ident
-| UNDERSCORE        { $$ = mk_atom("PatWild"); }
-| '&' ident         { $$ = $2; }
-| '&' UNDERSCORE    { $$ = mk_atom("PatWild"); }
-| ANDAND ident      { $$ = $2; }
-| ANDAND UNDERSCORE { $$ = mk_atom("PatWild"); }
-| MUT ident         { $$ = $2; }
-;
-
-ret_ty
-: RARROW '!'         { $$ = mk_none(); }
-| RARROW ty          { $$ = mk_node("ret-ty", 1, $2); }
-| %prec IDENT %empty { $$ = mk_none(); }
-;
-
-generic_params
-: '<' '>'                             { $$ = mk_node("Generics", 2, mk_none(), mk_none()); }
-| '<' lifetimes '>'                   { $$ = mk_node("Generics", 2, $2, mk_none()); }
-| '<' lifetimes ',' '>'               { $$ = mk_node("Generics", 2, $2, mk_none()); }
-| '<' lifetimes SHR                   { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); }
-| '<' lifetimes ',' SHR               { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); }
-| '<' lifetimes ',' ty_params '>'     { $$ = mk_node("Generics", 2, $2, $4); }
-| '<' lifetimes ',' ty_params ',' '>' { $$ = mk_node("Generics", 2, $2, $4); }
-| '<' lifetimes ',' ty_params SHR     { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); }
-| '<' lifetimes ',' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); }
-| '<' ty_params '>'                   { $$ = mk_node("Generics", 2, mk_none(), $2); }
-| '<' ty_params ',' '>'               { $$ = mk_node("Generics", 2, mk_none(), $2); }
-| '<' ty_params SHR                   { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); }
-| '<' ty_params ',' SHR               { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); }
-| %empty                              { $$ = mk_none(); }
-;
-
-maybe_where_clause
-: %empty                              { $$ = mk_none(); }
-| where_clause
-;
-
-where_clause
-: WHERE where_predicates              { $$ = mk_node("WhereClause", 1, $2); }
-| WHERE where_predicates ','          { $$ = mk_node("WhereClause", 1, $2); }
-;
-
-where_predicates
-: where_predicate                      { $$ = mk_node("WherePredicates", 1, $1); }
-| where_predicates ',' where_predicate { $$ = ext_node($1, 1, $3); }
-;
-
-where_predicate
-: maybe_for_lifetimes lifetime ':' bounds    { $$ = mk_node("WherePredicate", 3, $1, $2, $4); }
-| maybe_for_lifetimes ty ':' ty_param_bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); }
-;
-
-maybe_for_lifetimes
-: FOR '<' lifetimes '>' { $$ = mk_none(); }
-| %prec FORTYPE %empty  { $$ = mk_none(); }
-
-ty_params
-: ty_param               { $$ = mk_node("TyParams", 1, $1); }
-| ty_params ',' ty_param { $$ = ext_node($1, 1, $3); }
-;
-
-// A path with no type parameters; e.g. `foo::bar::Baz`
-//
-// These show up in 'use' view-items, because these are processed
-// without respect to types.
-path_no_types_allowed
-: ident                               { $$ = mk_node("ViewPath", 1, $1); }
-| MOD_SEP ident                       { $$ = mk_node("ViewPath", 1, $2); }
-| SELF                                { $$ = mk_node("ViewPath", 1, mk_atom("Self")); }
-| MOD_SEP SELF                        { $$ = mk_node("ViewPath", 1, mk_atom("Self")); }
-| SUPER                               { $$ = mk_node("ViewPath", 1, mk_atom("Super")); }
-| MOD_SEP SUPER                       { $$ = mk_node("ViewPath", 1, mk_atom("Super")); }
-| path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); }
-;
-
-// A path with a lifetime and type parameters, with no double colons
-// before the type parameters; e.g. `foo::bar<'a>::Baz<T>`
-//
-// These show up in "trait references", the components of
-// type-parameter bounds lists, as well as in the prefix of the
-// path_generic_args_and_bounds rule, which is the full form of a
-// named typed expression.
-//
-// They do not have (nor need) an extra '::' before '<' because
-// unlike in expr context, there are no "less-than" type exprs to
-// be ambiguous with.
-path_generic_args_without_colons
-: %prec IDENT
-  ident                                                                       { $$ = mk_node("components", 1, $1); }
-| %prec IDENT
-  ident generic_args                                                          { $$ = mk_node("components", 2, $1, $2); }
-| %prec IDENT
-  ident '(' maybe_ty_sums ')' ret_ty                                          { $$ = mk_node("components", 2, $1, $3); }
-| %prec IDENT
-  path_generic_args_without_colons MOD_SEP ident                              { $$ = ext_node($1, 1, $3); }
-| %prec IDENT
-  path_generic_args_without_colons MOD_SEP ident generic_args                 { $$ = ext_node($1, 2, $3, $4); }
-| %prec IDENT
-  path_generic_args_without_colons MOD_SEP ident '(' maybe_ty_sums ')' ret_ty { $$ = ext_node($1, 2, $3, $5); }
-;
-
-generic_args
-: '<' generic_values '>'   { $$ = $2; }
-| '<' generic_values SHR   { push_back('>'); $$ = $2; }
-| '<' generic_values GE    { push_back('='); $$ = $2; }
-| '<' generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; }
-// If generic_args starts with "<<", the first arg must be a
-// TyQualifiedPath because that's the only type that can start with a
-// '<'. This rule parses that as the first ty_sum and then continues
-// with the rest of generic_values.
-| SHL ty_qualified_path_and_generic_values '>'   { $$ = $2; }
-| SHL ty_qualified_path_and_generic_values SHR   { push_back('>'); $$ = $2; }
-| SHL ty_qualified_path_and_generic_values GE    { push_back('='); $$ = $2; }
-| SHL ty_qualified_path_and_generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; }
-;
-
-generic_values
-: maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 1, $1); }
-;
-
-maybe_ty_sums_and_or_bindings
-: ty_sums
-| ty_sums ','
-| ty_sums ',' bindings { $$ = mk_node("TySumsAndBindings", 2, $1, $3); }
-| bindings
-| bindings ','
-| %empty               { $$ = mk_none(); }
-;
-
-maybe_bindings
-: ',' bindings { $$ = $2; }
-| %empty       { $$ = mk_none(); }
-;
-
-////////////////////////////////////////////////////////////////////////
-// Part 2: Patterns
-////////////////////////////////////////////////////////////////////////
-
-pat
-: UNDERSCORE                                      { $$ = mk_atom("PatWild"); }
-| '&' pat                                         { $$ = mk_node("PatRegion", 1, $2); }
-| '&' MUT pat                                     { $$ = mk_node("PatRegion", 1, $3); }
-| ANDAND pat                                      { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); }
-| '(' ')'                                         { $$ = mk_atom("PatUnit"); }
-| '(' pat_tup ')'                                 { $$ = mk_node("PatTup", 1, $2); }
-| '[' pat_vec ']'                                 { $$ = mk_node("PatVec", 1, $2); }
-| lit_or_path
-| lit_or_path DOTDOTDOT lit_or_path               { $$ = mk_node("PatRange", 2, $1, $3); }
-| path_expr '{' pat_struct '}'                    { $$ = mk_node("PatStruct", 2, $1, $3); }
-| path_expr '(' ')'                               { $$ = mk_node("PatEnum", 2, $1, mk_none()); }
-| path_expr '(' pat_tup ')'                       { $$ = mk_node("PatEnum", 2, $1, $3); }
-| path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); }
-| binding_mode ident                              { $$ = mk_node("PatIdent", 2, $1, $2); }
-|              ident '@' pat                      { $$ = mk_node("PatIdent", 3, mk_node("BindByValue", 1, mk_atom("MutImmutable")), $1, $3); }
-| binding_mode ident '@' pat                      { $$ = mk_node("PatIdent", 3, $1, $2, $4); }
-| BOX pat                                         { $$ = mk_node("PatUniq", 1, $2); }
-| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("PatQualifiedPath", 3, $2, $3, $6); }
-| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident
-{
-  $$ = mk_node("PatQualifiedPath", 3, mk_node("PatQualifiedPath", 3, $2, $3, $6), $7, $10);
-}
-;
-
-pats_or
-: pat              { $$ = mk_node("Pats", 1, $1); }
-| pats_or '|' pat  { $$ = ext_node($1, 1, $3); }
-;
-
-binding_mode
-: REF         { $$ = mk_node("BindByRef", 1, mk_atom("MutImmutable")); }
-| REF MUT     { $$ = mk_node("BindByRef", 1, mk_atom("MutMutable")); }
-| MUT         { $$ = mk_node("BindByValue", 1, mk_atom("MutMutable")); }
-;
-
-lit_or_path
-: path_expr    { $$ = mk_node("PatLit", 1, $1); }
-| lit          { $$ = mk_node("PatLit", 1, $1); }
-| '-' lit      { $$ = mk_node("PatLit", 1, $2); }
-;
-
-pat_field
-:                  ident        { $$ = mk_node("PatField", 1, $1); }
-|     binding_mode ident        { $$ = mk_node("PatField", 2, $1, $2); }
-| BOX              ident        { $$ = mk_node("PatField", 2, mk_atom("box"), $2); }
-| BOX binding_mode ident        { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); }
-|              ident ':' pat    { $$ = mk_node("PatField", 2, $1, $3); }
-| binding_mode ident ':' pat    { $$ = mk_node("PatField", 3, $1, $2, $4); }
-|        LIT_INTEGER ':' pat    { $$ = mk_node("PatField", 2, mk_atom(yytext), $3); }
-;
-
-pat_fields
-: pat_field                  { $$ = mk_node("PatFields", 1, $1); }
-| pat_fields ',' pat_field   { $$ = ext_node($1, 1, $3); }
-;
-
-pat_struct
-: pat_fields                 { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); }
-| pat_fields ','             { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); }
-| pat_fields ',' DOTDOT      { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); }
-| DOTDOT                     { $$ = mk_node("PatStruct", 1, mk_atom("true")); }
-| %empty                     { $$ = mk_node("PatStruct", 1, mk_none()); }
-;
-
-pat_tup
-: pat_tup_elts                                  { $$ = mk_node("PatTup", 2, $1, mk_none()); }
-| pat_tup_elts                             ','  { $$ = mk_node("PatTup", 2, $1, mk_none()); }
-| pat_tup_elts     DOTDOT                       { $$ = mk_node("PatTup", 2, $1, mk_none()); }
-| pat_tup_elts ',' DOTDOT                       { $$ = mk_node("PatTup", 2, $1, mk_none()); }
-| pat_tup_elts     DOTDOT ',' pat_tup_elts      { $$ = mk_node("PatTup", 2, $1, $4); }
-| pat_tup_elts     DOTDOT ',' pat_tup_elts ','  { $$ = mk_node("PatTup", 2, $1, $4); }
-| pat_tup_elts ',' DOTDOT ',' pat_tup_elts      { $$ = mk_node("PatTup", 2, $1, $5); }
-| pat_tup_elts ',' DOTDOT ',' pat_tup_elts ','  { $$ = mk_node("PatTup", 2, $1, $5); }
-|                  DOTDOT ',' pat_tup_elts      { $$ = mk_node("PatTup", 2, mk_none(), $3); }
-|                  DOTDOT ',' pat_tup_elts ','  { $$ = mk_node("PatTup", 2, mk_none(), $3); }
-|                  DOTDOT                       { $$ = mk_node("PatTup", 2, mk_none(), mk_none()); }
-;
-
-pat_tup_elts
-: pat                    { $$ = mk_node("PatTupElts", 1, $1); }
-| pat_tup_elts ',' pat   { $$ = ext_node($1, 1, $3); }
-;
-
-pat_vec
-: pat_vec_elts                                  { $$ = mk_node("PatVec", 2, $1, mk_none()); }
-| pat_vec_elts                             ','  { $$ = mk_node("PatVec", 2, $1, mk_none()); }
-| pat_vec_elts     DOTDOT                       { $$ = mk_node("PatVec", 2, $1, mk_none()); }
-| pat_vec_elts ',' DOTDOT                       { $$ = mk_node("PatVec", 2, $1, mk_none()); }
-| pat_vec_elts     DOTDOT ',' pat_vec_elts      { $$ = mk_node("PatVec", 2, $1, $4); }
-| pat_vec_elts     DOTDOT ',' pat_vec_elts ','  { $$ = mk_node("PatVec", 2, $1, $4); }
-| pat_vec_elts ',' DOTDOT ',' pat_vec_elts      { $$ = mk_node("PatVec", 2, $1, $5); }
-| pat_vec_elts ',' DOTDOT ',' pat_vec_elts ','  { $$ = mk_node("PatVec", 2, $1, $5); }
-|                  DOTDOT ',' pat_vec_elts      { $$ = mk_node("PatVec", 2, mk_none(), $3); }
-|                  DOTDOT ',' pat_vec_elts ','  { $$ = mk_node("PatVec", 2, mk_none(), $3); }
-|                  DOTDOT                       { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); }
-| %empty                                        { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); }
-;
-
-pat_vec_elts
-: pat                    { $$ = mk_node("PatVecElts", 1, $1); }
-| pat_vec_elts ',' pat   { $$ = ext_node($1, 1, $3); }
-;
-
-////////////////////////////////////////////////////////////////////////
-// Part 3: Types
-////////////////////////////////////////////////////////////////////////
-
-ty
-: ty_prim
-| ty_closure
-| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident                                      { $$ = mk_node("TyQualifiedPath", 3, $2, $3, $6); }
-| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, mk_node("TyQualifiedPath", 3, $2, $3, $6), $7, $10); }
-| '(' ty_sums ')'                                                                      { $$ = mk_node("TyTup", 1, $2); }
-| '(' ty_sums ',' ')'                                                                  { $$ = mk_node("TyTup", 1, $2); }
-| '(' ')'                                                                              { $$ = mk_atom("TyNil"); }
-;
-
-ty_prim
-: %prec IDENT path_generic_args_without_colons                                               { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); }
-| %prec IDENT MOD_SEP path_generic_args_without_colons                                       { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); }
-| %prec IDENT SELF MOD_SEP path_generic_args_without_colons                                  { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); }
-| %prec IDENT path_generic_args_without_colons '!' maybe_ident delimited_token_trees         { $$ = mk_node("TyMacro", 3, $1, $3, $4); }
-| %prec IDENT MOD_SEP path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $2, $4, $5); }
-| BOX ty                                                                                     { $$ = mk_node("TyBox", 1, $2); }
-| '*' maybe_mut_or_const ty                                                                  { $$ = mk_node("TyPtr", 2, $2, $3); }
-| '&' ty                                                                                     { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); }
-| '&' MUT ty                                                                                 { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); }
-| ANDAND ty                                                                                  { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); }
-| ANDAND MUT ty                                                                              { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); }
-| '&' lifetime maybe_mut ty                                                                  { $$ = mk_node("TyRptr", 3, $2, $3, $4); }
-| ANDAND lifetime maybe_mut ty                                                               { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); }
-| '[' ty ']'                                                                                 { $$ = mk_node("TyVec", 1, $2); }
-| '[' ty ',' DOTDOT expr ']'                                                                 { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); }
-| '[' ty ';' expr ']'                                                                        { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); }
-| TYPEOF '(' expr ')'                                                                        { $$ = mk_node("TyTypeof", 1, $3); }
-| UNDERSCORE                                                                                 { $$ = mk_atom("TyInfer"); }
-| ty_bare_fn
-| for_in_type
-;
-
-ty_bare_fn
-:                         FN ty_fn_decl { $$ = $2; }
-| UNSAFE                  FN ty_fn_decl { $$ = $3; }
-|        EXTERN maybe_abi FN ty_fn_decl { $$ = $4; }
-| UNSAFE EXTERN maybe_abi FN ty_fn_decl { $$ = $5; }
-;
-
-ty_fn_decl
-: generic_params fn_anon_params ret_ty { $$ = mk_node("TyFnDecl", 3, $1, $2, $3); }
-;
-
-ty_closure
-: UNSAFE '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $3, $5, $6); }
-|        '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $2, $4, $5); }
-| UNSAFE OROR maybe_bounds ret_ty                { $$ = mk_node("TyClosure", 2, $3, $4); }
-|        OROR maybe_bounds ret_ty                { $$ = mk_node("TyClosure", 2, $2, $3); }
-;
-
-for_in_type
-: FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); }
-;
-
-for_in_type_suffix
-: ty_bare_fn
-| trait_ref
-| ty_closure
-;
-
-maybe_mut
-: MUT              { $$ = mk_atom("MutMutable"); }
-| %prec MUT %empty { $$ = mk_atom("MutImmutable"); }
-;
-
-maybe_mut_or_const
-: MUT    { $$ = mk_atom("MutMutable"); }
-| CONST  { $$ = mk_atom("MutImmutable"); }
-| %empty { $$ = mk_atom("MutImmutable"); }
-;
-
-ty_qualified_path_and_generic_values
-: ty_qualified_path maybe_bindings
-{
-  $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 1, mk_node("TySum", 1, $1)), $2);
-}
-| ty_qualified_path ',' ty_sums maybe_bindings
-{
-  $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 2, $1, $3), $4);
-}
-;
-
-ty_qualified_path
-: ty_sum AS trait_ref '>' MOD_SEP ident                     { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); }
-| ty_sum AS trait_ref '>' MOD_SEP ident '+' ty_param_bounds { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); }
-;
-
-maybe_ty_sums
-: ty_sums
-| ty_sums ','
-| %empty { $$ = mk_none(); }
-;
-
-ty_sums
-: ty_sum             { $$ = mk_node("TySums", 1, $1); }
-| ty_sums ',' ty_sum { $$ = ext_node($1, 1, $3); }
-;
-
-ty_sum
-: ty_sum_elt            { $$ = mk_node("TySum", 1, $1); }
-| ty_sum '+' ty_sum_elt { $$ = ext_node($1, 1, $3); }
-;
-
-ty_sum_elt
-: ty
-| lifetime
-;
-
-ty_prim_sum
-: ty_prim_sum_elt                 { $$ = mk_node("TySum", 1, $1); }
-| ty_prim_sum '+' ty_prim_sum_elt { $$ = ext_node($1, 1, $3); }
-;
-
-ty_prim_sum_elt
-: ty_prim
-| lifetime
-;
-
-maybe_ty_param_bounds
-: ':' ty_param_bounds { $$ = $2; }
-| %empty              { $$ = mk_none(); }
-;
-
-ty_param_bounds
-: boundseq
-| %empty { $$ = mk_none(); }
-;
-
-boundseq
-: polybound
-| boundseq '+' polybound { $$ = ext_node($1, 1, $3); }
-;
-
-polybound
-: FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); }
-| bound
-| '?' FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $4, $6); }
-| '?' bound { $$ = $2; }
-;
-
-bindings
-: binding              { $$ = mk_node("Bindings", 1, $1); }
-| bindings ',' binding { $$ = ext_node($1, 1, $3); }
-;
-
-binding
-: ident '=' ty { mk_node("Binding", 2, $1, $3); }
-;
-
-ty_param
-: ident maybe_ty_param_bounds maybe_ty_default           { $$ = mk_node("TyParam", 3, $1, $2, $3); }
-| ident '?' ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 4, $1, $3, $4, $5); }
-;
-
-maybe_bounds
-: %prec SHIFTPLUS
-  ':' bounds             { $$ = $2; }
-| %prec SHIFTPLUS %empty { $$ = mk_none(); }
-;
-
-bounds
-: bound            { $$ = mk_node("bounds", 1, $1); }
-| bounds '+' bound { $$ = ext_node($1, 1, $3); }
-;
-
-bound
-: lifetime
-| trait_ref
-;
-
-maybe_ltbounds
-: %prec SHIFTPLUS
-  ':' ltbounds       { $$ = $2; }
-| %empty             { $$ = mk_none(); }
-;
-
-ltbounds
-: lifetime              { $$ = mk_node("ltbounds", 1, $1); }
-| ltbounds '+' lifetime { $$ = ext_node($1, 1, $3); }
-;
-
-maybe_ty_default
-: '=' ty_sum { $$ = mk_node("TyDefault", 1, $2); }
-| %empty     { $$ = mk_none(); }
-;
-
-maybe_lifetimes
-: lifetimes
-| lifetimes ','
-| %empty { $$ = mk_none(); }
-;
-
-lifetimes
-: lifetime_and_bounds               { $$ = mk_node("Lifetimes", 1, $1); }
-| lifetimes ',' lifetime_and_bounds { $$ = ext_node($1, 1, $3); }
-;
-
-lifetime_and_bounds
-: LIFETIME maybe_ltbounds         { $$ = mk_node("lifetime", 2, mk_atom(yytext), $2); }
-| STATIC_LIFETIME                 { $$ = mk_atom("static_lifetime"); }
-;
-
-lifetime
-: LIFETIME         { $$ = mk_node("lifetime", 1, mk_atom(yytext)); }
-| STATIC_LIFETIME  { $$ = mk_atom("static_lifetime"); }
-;
-
-trait_ref
-: %prec IDENT path_generic_args_without_colons
-| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = $2; }
-;
-
-////////////////////////////////////////////////////////////////////////
-// Part 4: Blocks, statements, and expressions
-////////////////////////////////////////////////////////////////////////
-
-inner_attrs_and_block
-: '{' maybe_inner_attrs maybe_stmts '}'        { $$ = mk_node("ExprBlock", 2, $2, $3); }
-;
-
-block
-: '{' maybe_stmts '}'                          { $$ = mk_node("ExprBlock", 1, $2); }
-;
-
-maybe_stmts
-: stmts
-| stmts nonblock_expr { $$ = ext_node($1, 1, $2); }
-| nonblock_expr
-| %empty              { $$ = mk_none(); }
-;
-
-// There are two sub-grammars within a "stmts: exprs" derivation
-// depending on whether each stmt-expr is a block-expr form; this is to
-// handle the "semicolon rule" for stmt sequencing that permits
-// writing
-//
-//     if foo { bar } 10
-//
-// as a sequence of two stmts (one if-expr stmt, one lit-10-expr
-// stmt). Unfortunately by permitting juxtaposition of exprs in
-// sequence like that, the non-block expr grammar has to have a
-// second limited sub-grammar that excludes the prefix exprs that
-// are ambiguous with binops. That is to say:
-//
-//     {10} - 1
-//
-// should parse as (progn (progn 10) (- 1)) not (- (progn 10) 1), that
-// is to say, two statements rather than one, at least according to
-// the mainline rust parser.
-//
-// So we wind up with a 3-way split in exprs that occur in stmt lists:
-// block, nonblock-prefix, and nonblock-nonprefix.
-//
-// In non-stmts contexts, expr can relax this trichotomy.
-
-stmts
-: stmt           { $$ = mk_node("stmts", 1, $1); }
-| stmts stmt     { $$ = ext_node($1, 1, $2); }
-;
-
-stmt
-: maybe_outer_attrs let     { $$ = $2; }
-|                 stmt_item
-|             PUB stmt_item { $$ = $2; }
-| outer_attrs     stmt_item { $$ = $2; }
-| outer_attrs PUB stmt_item { $$ = $3; }
-| full_block_expr
-| maybe_outer_attrs block   { $$ = $2; }
-|             nonblock_expr ';'
-| outer_attrs nonblock_expr ';' { $$ = $2; }
-| ';'                   { $$ = mk_none(); }
-;
-
-maybe_exprs
-: exprs
-| exprs ','
-| %empty { $$ = mk_none(); }
-;
-
-maybe_expr
-: expr
-| %empty { $$ = mk_none(); }
-;
-
-exprs
-: expr                                                        { $$ = mk_node("exprs", 1, $1); }
-| exprs ',' expr                                              { $$ = ext_node($1, 1, $3); }
-;
-
-path_expr
-: path_generic_args_with_colons
-| MOD_SEP path_generic_args_with_colons      { $$ = $2; }
-| SELF MOD_SEP path_generic_args_with_colons { $$ = mk_node("SelfPath", 1, $3); }
-;
-
-// A path with a lifetime and type parameters with double colons before
-// the type parameters; e.g. `foo::bar::<'a>::Baz::<T>`
-//
-// These show up in expr context, in order to disambiguate from "less-than"
-// expressions.
-path_generic_args_with_colons
-: ident                                              { $$ = mk_node("components", 1, $1); }
-| SUPER                                              { $$ = mk_atom("Super"); }
-| path_generic_args_with_colons MOD_SEP ident        { $$ = ext_node($1, 1, $3); }
-| path_generic_args_with_colons MOD_SEP SUPER        { $$ = ext_node($1, 1, mk_atom("Super")); }
-| path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); }
-;
-
-// the braces-delimited macro is a block_expr so it doesn't appear here
-macro_expr
-: path_expr '!' maybe_ident parens_delimited_token_trees   { $$ = mk_node("MacroExpr", 3, $1, $3, $4); }
-| path_expr '!' maybe_ident brackets_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); }
-;
-
-nonblock_expr
-: lit                                                           { $$ = mk_node("ExprLit", 1, $1); }
-| %prec IDENT
-  path_expr                                                     { $$ = mk_node("ExprPath", 1, $1); }
-| SELF                                                          { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
-| macro_expr                                                    { $$ = mk_node("ExprMac", 1, $1); }
-| path_expr '{' struct_expr_fields '}'                          { $$ = mk_node("ExprStruct", 2, $1, $3); }
-| nonblock_expr '?'                                             { $$ = mk_node("ExprTry", 1, $1); }
-| nonblock_expr '.' path_generic_args_with_colons               { $$ = mk_node("ExprField", 2, $1, $3); }
-| nonblock_expr '.' LIT_INTEGER                                 { $$ = mk_node("ExprTupleIndex", 1, $1); }
-| nonblock_expr '[' maybe_expr ']'                              { $$ = mk_node("ExprIndex", 2, $1, $3); }
-| nonblock_expr '(' maybe_exprs ')'                             { $$ = mk_node("ExprCall", 2, $1, $3); }
-| '[' vec_expr ']'                                              { $$ = mk_node("ExprVec", 1, $2); }
-| '(' maybe_exprs ')'                                           { $$ = mk_node("ExprParen", 1, $2); }
-| CONTINUE                                                      { $$ = mk_node("ExprAgain", 0); }
-| CONTINUE lifetime                                             { $$ = mk_node("ExprAgain", 1, $2); }
-| RETURN                                                        { $$ = mk_node("ExprRet", 0); }
-| RETURN expr                                                   { $$ = mk_node("ExprRet", 1, $2); }
-| BREAK                                                         { $$ = mk_node("ExprBreak", 0); }
-| BREAK lifetime                                                { $$ = mk_node("ExprBreak", 1, $2); }
-| YIELD                                                         { $$ = mk_node("ExprYield", 0); }
-| YIELD expr                                                    { $$ = mk_node("ExprYield", 1, $2); }
-| nonblock_expr '=' expr                                        { $$ = mk_node("ExprAssign", 2, $1, $3); }
-| nonblock_expr SHLEQ expr                                      { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
-| nonblock_expr SHREQ expr                                      { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
-| nonblock_expr MINUSEQ expr                                    { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
-| nonblock_expr ANDEQ expr                                      { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
-| nonblock_expr OREQ expr                                       { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
-| nonblock_expr PLUSEQ expr                                     { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
-| nonblock_expr STAREQ expr                                     { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
-| nonblock_expr SLASHEQ expr                                    { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
-| nonblock_expr CARETEQ expr                                    { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
-| nonblock_expr PERCENTEQ expr                                  { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
-| nonblock_expr OROR expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
-| nonblock_expr ANDAND expr                                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
-| nonblock_expr EQEQ expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
-| nonblock_expr NE expr                                         { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
-| nonblock_expr '<' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
-| nonblock_expr '>' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
-| nonblock_expr LE expr                                         { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
-| nonblock_expr GE expr                                         { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
-| nonblock_expr '|' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
-| nonblock_expr '^' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
-| nonblock_expr '&' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
-| nonblock_expr SHL expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
-| nonblock_expr SHR expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
-| nonblock_expr '+' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
-| nonblock_expr '-' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
-| nonblock_expr '*' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
-| nonblock_expr '/' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
-| nonblock_expr '%' expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
-| nonblock_expr DOTDOT                                          { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
-| nonblock_expr DOTDOT expr                                     { $$ = mk_node("ExprRange", 2, $1, $3); }
-|               DOTDOT expr                                     { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
-|               DOTDOT                                          { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
-| nonblock_expr AS ty                                           { $$ = mk_node("ExprCast", 2, $1, $3); }
-| nonblock_expr ':' ty                                          { $$ = mk_node("ExprTypeAscr", 2, $1, $3); }
-| BOX expr                                                      { $$ = mk_node("ExprBox", 1, $2); }
-| expr_qualified_path
-| nonblock_prefix_expr
-;
-
-expr
-: lit                                                 { $$ = mk_node("ExprLit", 1, $1); }
-| %prec IDENT
-  path_expr                                           { $$ = mk_node("ExprPath", 1, $1); }
-| SELF                                                { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
-| macro_expr                                          { $$ = mk_node("ExprMac", 1, $1); }
-| path_expr '{' struct_expr_fields '}'                { $$ = mk_node("ExprStruct", 2, $1, $3); }
-| expr '?'                                            { $$ = mk_node("ExprTry", 1, $1); }
-| expr '.' path_generic_args_with_colons              { $$ = mk_node("ExprField", 2, $1, $3); }
-| expr '.' LIT_INTEGER                                { $$ = mk_node("ExprTupleIndex", 1, $1); }
-| expr '[' maybe_expr ']'                             { $$ = mk_node("ExprIndex", 2, $1, $3); }
-| expr '(' maybe_exprs ')'                            { $$ = mk_node("ExprCall", 2, $1, $3); }
-| '(' maybe_exprs ')'                                 { $$ = mk_node("ExprParen", 1, $2); }
-| '[' vec_expr ']'                                    { $$ = mk_node("ExprVec", 1, $2); }
-| CONTINUE                                            { $$ = mk_node("ExprAgain", 0); }
-| CONTINUE ident                                      { $$ = mk_node("ExprAgain", 1, $2); }
-| RETURN                                              { $$ = mk_node("ExprRet", 0); }
-| RETURN expr                                         { $$ = mk_node("ExprRet", 1, $2); }
-| BREAK                                               { $$ = mk_node("ExprBreak", 0); }
-| BREAK ident                                         { $$ = mk_node("ExprBreak", 1, $2); }
-| YIELD                                               { $$ = mk_node("ExprYield", 0); }
-| YIELD expr                                          { $$ = mk_node("ExprYield", 1, $2); }
-| expr '=' expr                                       { $$ = mk_node("ExprAssign", 2, $1, $3); }
-| expr SHLEQ expr                                     { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
-| expr SHREQ expr                                     { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
-| expr MINUSEQ expr                                   { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
-| expr ANDEQ expr                                     { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
-| expr OREQ expr                                      { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
-| expr PLUSEQ expr                                    { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
-| expr STAREQ expr                                    { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
-| expr SLASHEQ expr                                   { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
-| expr CARETEQ expr                                   { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
-| expr PERCENTEQ expr                                 { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
-| expr OROR expr                                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
-| expr ANDAND expr                                    { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
-| expr EQEQ expr                                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
-| expr NE expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
-| expr '<' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
-| expr '>' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
-| expr LE expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
-| expr GE expr                                        { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
-| expr '|' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
-| expr '^' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
-| expr '&' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
-| expr SHL expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
-| expr SHR expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
-| expr '+' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
-| expr '-' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
-| expr '*' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
-| expr '/' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
-| expr '%' expr                                       { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
-| expr DOTDOT                                         { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
-| expr DOTDOT expr                                    { $$ = mk_node("ExprRange", 2, $1, $3); }
-|      DOTDOT expr                                    { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
-|      DOTDOT                                         { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
-| expr AS ty                                          { $$ = mk_node("ExprCast", 2, $1, $3); }
-| expr ':' ty                                         { $$ = mk_node("ExprTypeAscr", 2, $1, $3); }
-| BOX expr                                            { $$ = mk_node("ExprBox", 1, $2); }
-| expr_qualified_path
-| block_expr
-| block
-| nonblock_prefix_expr
-;
-
-expr_nostruct
-: lit                                                 { $$ = mk_node("ExprLit", 1, $1); }
-| %prec IDENT
-  path_expr                                           { $$ = mk_node("ExprPath", 1, $1); }
-| SELF                                                { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
-| macro_expr                                          { $$ = mk_node("ExprMac", 1, $1); }
-| expr_nostruct '?'                                   { $$ = mk_node("ExprTry", 1, $1); }
-| expr_nostruct '.' path_generic_args_with_colons     { $$ = mk_node("ExprField", 2, $1, $3); }
-| expr_nostruct '.' LIT_INTEGER                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
-| expr_nostruct '[' maybe_expr ']'                    { $$ = mk_node("ExprIndex", 2, $1, $3); }
-| expr_nostruct '(' maybe_exprs ')'                   { $$ = mk_node("ExprCall", 2, $1, $3); }
-| '[' vec_expr ']'                                    { $$ = mk_node("ExprVec", 1, $2); }
-| '(' maybe_exprs ')'                                 { $$ = mk_node("ExprParen", 1, $2); }
-| CONTINUE                                            { $$ = mk_node("ExprAgain", 0); }
-| CONTINUE ident                                      { $$ = mk_node("ExprAgain", 1, $2); }
-| RETURN                                              { $$ = mk_node("ExprRet", 0); }
-| RETURN expr                                         { $$ = mk_node("ExprRet", 1, $2); }
-| BREAK                                               { $$ = mk_node("ExprBreak", 0); }
-| BREAK ident                                         { $$ = mk_node("ExprBreak", 1, $2); }
-| YIELD                                               { $$ = mk_node("ExprYield", 0); }
-| YIELD expr                                          { $$ = mk_node("ExprYield", 1, $2); }
-| expr_nostruct '=' expr_nostruct                     { $$ = mk_node("ExprAssign", 2, $1, $3); }
-| expr_nostruct SHLEQ expr_nostruct                   { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
-| expr_nostruct SHREQ expr_nostruct                   { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
-| expr_nostruct MINUSEQ expr_nostruct                 { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
-| expr_nostruct ANDEQ expr_nostruct                   { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
-| expr_nostruct OREQ expr_nostruct                    { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
-| expr_nostruct PLUSEQ expr_nostruct                  { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
-| expr_nostruct STAREQ expr_nostruct                  { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
-| expr_nostruct SLASHEQ expr_nostruct                 { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
-| expr_nostruct CARETEQ expr_nostruct                 { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
-| expr_nostruct PERCENTEQ expr_nostruct               { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
-| expr_nostruct OROR expr_nostruct                    { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
-| expr_nostruct ANDAND expr_nostruct                  { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
-| expr_nostruct EQEQ expr_nostruct                    { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
-| expr_nostruct NE expr_nostruct                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
-| expr_nostruct '<' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
-| expr_nostruct '>' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
-| expr_nostruct LE expr_nostruct                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
-| expr_nostruct GE expr_nostruct                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
-| expr_nostruct '|' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
-| expr_nostruct '^' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
-| expr_nostruct '&' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
-| expr_nostruct SHL expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
-| expr_nostruct SHR expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
-| expr_nostruct '+' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
-| expr_nostruct '-' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
-| expr_nostruct '*' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
-| expr_nostruct '/' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
-| expr_nostruct '%' expr_nostruct                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
-| expr_nostruct DOTDOT               %prec RANGE      { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
-| expr_nostruct DOTDOT expr_nostruct                  { $$ = mk_node("ExprRange", 2, $1, $3); }
-|               DOTDOT expr_nostruct                  { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
-|               DOTDOT                                { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
-| expr_nostruct AS ty                                 { $$ = mk_node("ExprCast", 2, $1, $3); }
-| expr_nostruct ':' ty                                { $$ = mk_node("ExprTypeAscr", 2, $1, $3); }
-| BOX expr                                            { $$ = mk_node("ExprBox", 1, $2); }
-| expr_qualified_path
-| block_expr
-| block
-| nonblock_prefix_expr_nostruct
-;
-
-nonblock_prefix_expr_nostruct
-: '-' expr_nostruct                         { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); }
-| '!' expr_nostruct                         { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); }
-| '*' expr_nostruct                         { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); }
-| '&' maybe_mut expr_nostruct               { $$ = mk_node("ExprAddrOf", 2, $2, $3); }
-| ANDAND maybe_mut expr_nostruct            { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); }
-| lambda_expr_nostruct
-| MOVE lambda_expr_nostruct                 { $$ = $2; }
-;
-
-nonblock_prefix_expr
-: '-' expr                         { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); }
-| '!' expr                         { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); }
-| '*' expr                         { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); }
-| '&' maybe_mut expr               { $$ = mk_node("ExprAddrOf", 2, $2, $3); }
-| ANDAND maybe_mut expr            { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); }
-| lambda_expr
-| MOVE lambda_expr                 { $$ = $2; }
-;
-
-expr_qualified_path
-: '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_qpath_params
-{
-  $$ = mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7);
-}
-| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident
-{
-  $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10);
-}
-| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident
-{
-  $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11);
-}
-| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident generic_args
-{
-  $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10, $11);
-}
-| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident generic_args
-{
-  $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11, $12);
-}
-
-maybe_qpath_params
-: MOD_SEP generic_args { $$ = $2; }
-| %empty               { $$ = mk_none(); }
-;
-
-maybe_as_trait_ref
-: AS trait_ref { $$ = $2; }
-| %empty       { $$ = mk_none(); }
-;
-
-lambda_expr
-: %prec LAMBDA
-  OROR ret_ty expr                                    { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
-| %prec LAMBDA
-  '|' '|' ret_ty expr                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); }
-| %prec LAMBDA
-  '|' inferrable_params '|' ret_ty expr               { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); }
-| %prec LAMBDA
-  '|' inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); }
-;
-
-lambda_expr_no_first_bar
-: %prec LAMBDA
-  '|' ret_ty expr                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
-| %prec LAMBDA
-  inferrable_params '|' ret_ty expr               { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); }
-| %prec LAMBDA
-  inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); }
-;
-
-lambda_expr_nostruct
-: %prec LAMBDA
-  OROR expr_nostruct                                           { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); }
-| %prec LAMBDA
-  '|' '|' ret_ty expr_nostruct                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); }
-| %prec LAMBDA
-  '|' inferrable_params '|' expr_nostruct                      { $$ = mk_node("ExprFnBlock", 2, $2, $4); }
-| %prec LAMBDA
-  '|' inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); }
-;
-
-lambda_expr_nostruct_no_first_bar
-: %prec LAMBDA
-  '|' ret_ty expr_nostruct                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
-| %prec LAMBDA
-  inferrable_params '|' ret_ty expr_nostruct               { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); }
-| %prec LAMBDA
-  inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); }
-;
-
-vec_expr
-: maybe_exprs
-| exprs ';' expr { $$ = mk_node("VecRepeat", 2, $1, $3); }
-;
-
-struct_expr_fields
-: field_inits
-| field_inits ','
-| maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); }
-| %empty                               { $$ = mk_none(); }
-;
-
-maybe_field_inits
-: field_inits
-| field_inits ','
-| %empty { $$ = mk_none(); }
-;
-
-field_inits
-: field_init                 { $$ = mk_node("FieldInits", 1, $1); }
-| field_inits ',' field_init { $$ = ext_node($1, 1, $3); }
-;
-
-field_init
-: ident                { $$ = mk_node("FieldInit", 1, $1); }
-| ident ':' expr       { $$ = mk_node("FieldInit", 2, $1, $3); }
-| LIT_INTEGER ':' expr { $$ = mk_node("FieldInit", 2, mk_atom(yytext), $3); }
-;
-
-default_field_init
-: DOTDOT expr   { $$ = mk_node("DefaultFieldInit", 1, $2); }
-;
-
-block_expr
-: expr_match
-| expr_if
-| expr_if_let
-| expr_while
-| expr_while_let
-| expr_loop
-| expr_for
-| UNSAFE block                                           { $$ = mk_node("UnsafeBlock", 1, $2); }
-| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("Macro", 3, $1, $3, $4); }
-;
-
-full_block_expr
-: block_expr
-| block_expr_dot
-;
-
-block_expr_dot
-: block_expr     '.' path_generic_args_with_colons %prec IDENT         { $$ = mk_node("ExprField", 2, $1, $3); }
-| block_expr_dot '.' path_generic_args_with_colons %prec IDENT         { $$ = mk_node("ExprField", 2, $1, $3); }
-| block_expr     '.' path_generic_args_with_colons '[' maybe_expr ']'  { $$ = mk_node("ExprIndex", 3, $1, $3, $5); }
-| block_expr_dot '.' path_generic_args_with_colons '[' maybe_expr ']'  { $$ = mk_node("ExprIndex", 3, $1, $3, $5); }
-| block_expr     '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); }
-| block_expr_dot '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); }
-| block_expr     '.' LIT_INTEGER                                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
-| block_expr_dot '.' LIT_INTEGER                                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
-;
-
-expr_match
-: MATCH expr_nostruct '{' '}'                                     { $$ = mk_node("ExprMatch", 1, $2); }
-| MATCH expr_nostruct '{' match_clauses                       '}' { $$ = mk_node("ExprMatch", 2, $2, $4); }
-| MATCH expr_nostruct '{' match_clauses nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, ext_node($4, 1, $5)); }
-| MATCH expr_nostruct '{'               nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, mk_node("Arms", 1, $4)); }
-;
-
-match_clauses
-: match_clause               { $$ = mk_node("Arms", 1, $1); }
-| match_clauses match_clause { $$ = ext_node($1, 1, $2); }
-;
-
-match_clause
-: nonblock_match_clause ','
-| block_match_clause
-| block_match_clause ','
-;
-
-nonblock_match_clause
-: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr  { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); }
-| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr_dot { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); }
-;
-
-block_match_clause
-: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block      { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); }
-| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); }
-;
-
-maybe_guard
-: IF expr_nostruct           { $$ = $2; }
-| %empty                     { $$ = mk_none(); }
-;
-
-expr_if
-: IF expr_nostruct block                              { $$ = mk_node("ExprIf", 2, $2, $3); }
-| IF expr_nostruct block ELSE block_or_if             { $$ = mk_node("ExprIf", 3, $2, $3, $5); }
-;
-
-expr_if_let
-: IF LET pat '=' expr_nostruct block                  { $$ = mk_node("ExprIfLet", 3, $3, $5, $6); }
-| IF LET pat '=' expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIfLet", 4, $3, $5, $6, $8); }
-;
-
-block_or_if
-: block
-| expr_if
-| expr_if_let
-;
-
-expr_while
-: maybe_label WHILE expr_nostruct block               { $$ = mk_node("ExprWhile", 3, $1, $3, $4); }
-;
-
-expr_while_let
-: maybe_label WHILE LET pat '=' expr_nostruct block   { $$ = mk_node("ExprWhileLet", 4, $1, $4, $6, $7); }
-;
-
-expr_loop
-: maybe_label LOOP block                              { $$ = mk_node("ExprLoop", 2, $1, $3); }
-;
-
-expr_for
-: maybe_label FOR pat IN expr_nostruct block          { $$ = mk_node("ExprForLoop", 4, $1, $3, $5, $6); }
-;
-
-maybe_label
-: lifetime ':'
-| %empty { $$ = mk_none(); }
-;
-
-let
-: LET pat maybe_ty_ascription maybe_init_expr ';' { $$ = mk_node("DeclLocal", 3, $2, $3, $4); }
-;
-
-////////////////////////////////////////////////////////////////////////
-// Part 5: Macros and misc. rules
-////////////////////////////////////////////////////////////////////////
-
-lit
-: LIT_BYTE                   { $$ = mk_node("LitByte", 1, mk_atom(yytext)); }
-| LIT_CHAR                   { $$ = mk_node("LitChar", 1, mk_atom(yytext)); }
-| LIT_INTEGER                { $$ = mk_node("LitInteger", 1, mk_atom(yytext)); }
-| LIT_FLOAT                  { $$ = mk_node("LitFloat", 1, mk_atom(yytext)); }
-| TRUE                       { $$ = mk_node("LitBool", 1, mk_atom(yytext)); }
-| FALSE                      { $$ = mk_node("LitBool", 1, mk_atom(yytext)); }
-| str
-;
-
-str
-: LIT_STR                    { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("CookedStr")); }
-| LIT_STR_RAW                { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("RawStr")); }
-| LIT_BYTE_STR                 { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("ByteStr")); }
-| LIT_BYTE_STR_RAW             { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("RawByteStr")); }
-;
-
-maybe_ident
-: %empty { $$ = mk_none(); }
-| ident
-;
-
-ident
-: IDENT                      { $$ = mk_node("ident", 1, mk_atom(yytext)); }
-// Weak keywords that can be used as identifiers
-| CATCH                      { $$ = mk_node("ident", 1, mk_atom(yytext)); }
-| DEFAULT                    { $$ = mk_node("ident", 1, mk_atom(yytext)); }
-| UNION                      { $$ = mk_node("ident", 1, mk_atom(yytext)); }
-;
-
-unpaired_token
-: SHL                        { $$ = mk_atom(yytext); }
-| SHR                        { $$ = mk_atom(yytext); }
-| LE                         { $$ = mk_atom(yytext); }
-| EQEQ                       { $$ = mk_atom(yytext); }
-| NE                         { $$ = mk_atom(yytext); }
-| GE                         { $$ = mk_atom(yytext); }
-| ANDAND                     { $$ = mk_atom(yytext); }
-| OROR                       { $$ = mk_atom(yytext); }
-| LARROW                     { $$ = mk_atom(yytext); }
-| SHLEQ                      { $$ = mk_atom(yytext); }
-| SHREQ                      { $$ = mk_atom(yytext); }
-| MINUSEQ                    { $$ = mk_atom(yytext); }
-| ANDEQ                      { $$ = mk_atom(yytext); }
-| OREQ                       { $$ = mk_atom(yytext); }
-| PLUSEQ                     { $$ = mk_atom(yytext); }
-| STAREQ                     { $$ = mk_atom(yytext); }
-| SLASHEQ                    { $$ = mk_atom(yytext); }
-| CARETEQ                    { $$ = mk_atom(yytext); }
-| PERCENTEQ                  { $$ = mk_atom(yytext); }
-| DOTDOT                     { $$ = mk_atom(yytext); }
-| DOTDOTDOT                  { $$ = mk_atom(yytext); }
-| MOD_SEP                    { $$ = mk_atom(yytext); }
-| RARROW                     { $$ = mk_atom(yytext); }
-| FAT_ARROW                  { $$ = mk_atom(yytext); }
-| LIT_BYTE                   { $$ = mk_atom(yytext); }
-| LIT_CHAR                   { $$ = mk_atom(yytext); }
-| LIT_INTEGER                { $$ = mk_atom(yytext); }
-| LIT_FLOAT                  { $$ = mk_atom(yytext); }
-| LIT_STR                    { $$ = mk_atom(yytext); }
-| LIT_STR_RAW                { $$ = mk_atom(yytext); }
-| LIT_BYTE_STR               { $$ = mk_atom(yytext); }
-| LIT_BYTE_STR_RAW           { $$ = mk_atom(yytext); }
-| IDENT                      { $$ = mk_atom(yytext); }
-| UNDERSCORE                 { $$ = mk_atom(yytext); }
-| LIFETIME                   { $$ = mk_atom(yytext); }
-| SELF                       { $$ = mk_atom(yytext); }
-| STATIC                     { $$ = mk_atom(yytext); }
-| ABSTRACT                   { $$ = mk_atom(yytext); }
-| ALIGNOF                    { $$ = mk_atom(yytext); }
-| AS                         { $$ = mk_atom(yytext); }
-| BECOME                     { $$ = mk_atom(yytext); }
-| BREAK                      { $$ = mk_atom(yytext); }
-| CATCH                      { $$ = mk_atom(yytext); }
-| CRATE                      { $$ = mk_atom(yytext); }
-| DEFAULT                    { $$ = mk_atom(yytext); }
-| DO                         { $$ = mk_atom(yytext); }
-| ELSE                       { $$ = mk_atom(yytext); }
-| ENUM                       { $$ = mk_atom(yytext); }
-| EXTERN                     { $$ = mk_atom(yytext); }
-| FALSE                      { $$ = mk_atom(yytext); }
-| FINAL                      { $$ = mk_atom(yytext); }
-| FN                         { $$ = mk_atom(yytext); }
-| FOR                        { $$ = mk_atom(yytext); }
-| IF                         { $$ = mk_atom(yytext); }
-| IMPL                       { $$ = mk_atom(yytext); }
-| IN                         { $$ = mk_atom(yytext); }
-| LET                        { $$ = mk_atom(yytext); }
-| LOOP                       { $$ = mk_atom(yytext); }
-| MACRO                      { $$ = mk_atom(yytext); }
-| MATCH                      { $$ = mk_atom(yytext); }
-| MOD                        { $$ = mk_atom(yytext); }
-| MOVE                       { $$ = mk_atom(yytext); }
-| MUT                        { $$ = mk_atom(yytext); }
-| OFFSETOF                   { $$ = mk_atom(yytext); }
-| OVERRIDE                   { $$ = mk_atom(yytext); }
-| PRIV                       { $$ = mk_atom(yytext); }
-| PUB                        { $$ = mk_atom(yytext); }
-| PURE                       { $$ = mk_atom(yytext); }
-| REF                        { $$ = mk_atom(yytext); }
-| RETURN                     { $$ = mk_atom(yytext); }
-| STRUCT                     { $$ = mk_atom(yytext); }
-| SIZEOF                     { $$ = mk_atom(yytext); }
-| SUPER                      { $$ = mk_atom(yytext); }
-| TRUE                       { $$ = mk_atom(yytext); }
-| TRAIT                      { $$ = mk_atom(yytext); }
-| TYPE                       { $$ = mk_atom(yytext); }
-| UNION                      { $$ = mk_atom(yytext); }
-| UNSAFE                     { $$ = mk_atom(yytext); }
-| UNSIZED                    { $$ = mk_atom(yytext); }
-| USE                        { $$ = mk_atom(yytext); }
-| VIRTUAL                    { $$ = mk_atom(yytext); }
-| WHILE                      { $$ = mk_atom(yytext); }
-| YIELD                      { $$ = mk_atom(yytext); }
-| CONTINUE                   { $$ = mk_atom(yytext); }
-| PROC                       { $$ = mk_atom(yytext); }
-| BOX                        { $$ = mk_atom(yytext); }
-| CONST                      { $$ = mk_atom(yytext); }
-| WHERE                      { $$ = mk_atom(yytext); }
-| TYPEOF                     { $$ = mk_atom(yytext); }
-| INNER_DOC_COMMENT          { $$ = mk_atom(yytext); }
-| OUTER_DOC_COMMENT          { $$ = mk_atom(yytext); }
-| SHEBANG                    { $$ = mk_atom(yytext); }
-| STATIC_LIFETIME            { $$ = mk_atom(yytext); }
-| ';'                        { $$ = mk_atom(yytext); }
-| ','                        { $$ = mk_atom(yytext); }
-| '.'                        { $$ = mk_atom(yytext); }
-| '@'                        { $$ = mk_atom(yytext); }
-| '#'                        { $$ = mk_atom(yytext); }
-| '~'                        { $$ = mk_atom(yytext); }
-| ':'                        { $$ = mk_atom(yytext); }
-| '$'                        { $$ = mk_atom(yytext); }
-| '='                        { $$ = mk_atom(yytext); }
-| '?'                        { $$ = mk_atom(yytext); }
-| '!'                        { $$ = mk_atom(yytext); }
-| '<'                        { $$ = mk_atom(yytext); }
-| '>'                        { $$ = mk_atom(yytext); }
-| '-'                        { $$ = mk_atom(yytext); }
-| '&'                        { $$ = mk_atom(yytext); }
-| '|'                        { $$ = mk_atom(yytext); }
-| '+'                        { $$ = mk_atom(yytext); }
-| '*'                        { $$ = mk_atom(yytext); }
-| '/'                        { $$ = mk_atom(yytext); }
-| '^'                        { $$ = mk_atom(yytext); }
-| '%'                        { $$ = mk_atom(yytext); }
-;
-
-token_trees
-: %empty                     { $$ = mk_node("TokenTrees", 0); }
-| token_trees token_tree     { $$ = ext_node($1, 1, $2); }
-;
-
-token_tree
-: delimited_token_trees
-| unpaired_token         { $$ = mk_node("TTTok", 1, $1); }
-;
-
-delimited_token_trees
-: parens_delimited_token_trees
-| braces_delimited_token_trees
-| brackets_delimited_token_trees
-;
-
-parens_delimited_token_trees
-: '(' token_trees ')'
-{
-  $$ = mk_node("TTDelim", 3,
-               mk_node("TTTok", 1, mk_atom("(")),
-               $2,
-               mk_node("TTTok", 1, mk_atom(")")));
-}
-;
-
-braces_delimited_token_trees
-: '{' token_trees '}'
-{
-  $$ = mk_node("TTDelim", 3,
-               mk_node("TTTok", 1, mk_atom("{")),
-               $2,
-               mk_node("TTTok", 1, mk_atom("}")));
-}
-;
-
-brackets_delimited_token_trees
-: '[' token_trees ']'
-{
-  $$ = mk_node("TTDelim", 3,
-               mk_node("TTTok", 1, mk_atom("[")),
-               $2,
-               mk_node("TTTok", 1, mk_atom("]")));
-}
-;
diff --git a/src/grammar/raw-string-literal-ambiguity.md b/src/grammar/raw-string-literal-ambiguity.md
deleted file mode 100644
index c909f2333148a..0000000000000
--- a/src/grammar/raw-string-literal-ambiguity.md
+++ /dev/null
@@ -1,64 +0,0 @@
-Rust's lexical grammar is not context-free. Raw string literals are the source
-of the problem. Informally, a raw string literal is an `r`, followed by `N`
-hashes (where N can be zero), a quote, any characters, then a quote followed
-by `N` hashes. Critically, once inside the first pair of quotes,
-another quote cannot be followed by `N` consecutive hashes. e.g.
-`r###""###"###` is invalid.
-
-This grammar describes this as best possible:
-
-    R -> 'r' S
-    S -> '"' B '"'
-    S -> '#' S '#'
-    B -> . B
-    B -> ε
-
-Where `.` represents any character, and `ε` the empty string. Consider the
-string `r#""#"#`. This string is not a valid raw string literal, but can be
-accepted as one by the above grammar, using the derivation:
-
-    R : #""#"#
-    S : ""#"
-    S : "#
-    B : #
-    B : ε
-
-(Where `T : U` means the rule `T` is applied, and `U` is the remainder of the
-string.) The difficulty arises from the fact that it is fundamentally
-context-sensitive. In particular, the context needed is the number of hashes.
-
-To prove that Rust's string literals are not context-free, we will use
-the fact that context-free languages are closed under intersection with
-regular languages, and the
-[pumping lemma for context-free languages](https://en.wikipedia.org/wiki/Pumping_lemma_for_context-free_languages).
-
-Consider the regular language `R = r#+""#*"#+`. If Rust's raw string literals are
-context-free, then their intersection with `R`, `R'`, should also be context-free.
-Therefore, to prove that raw string literals are not context-free,
-it is sufficient to prove that `R'` is not context-free.
-
-The language `R'` is `{r#^n""#^m"#^n | m < n}`.
-
-Assume `R'` *is* context-free. Then `R'` has some pumping length `p > 0` for which
-the pumping lemma applies. Consider the following string `s` in `R'`:
-
-`r#^p""#^{p-1}"#^p`
-
-e.g. for `p = 2`: `s = r##""#"##`
-
-Then `s = uvwxy` for some choice of `uvwxy` such that `vx` is non-empty,
-`|vwx| < p+1`, and `uv^iwx^iy` is in `R'` for all `i >= 0`.
-
-Neither `v` nor `x` can contain a `"` or `r`, as the number of these characters
-in any string in `R'` is fixed. So `v` and `x` contain only hashes.
-Consequently, of the three sequences of hashes, `v` and `x` combined
-can only pump two of them.
-If we ever choose the central sequence of hashes, then one of the outer sequences
-will not grow when we pump, leading to an imbalance between the outer sequences.
-Therefore, we must pump both outer sequences of hashes. However,
-there are `p+2` characters between these two sequences of hashes, and `|vwx|` must
-be less than `p+1`. Therefore we have a contradiction, and `R'` must not be
-context-free.
-
-Since `R'` is not context-free, it follows that the Rust's raw string literals
-must not be context-free.
diff --git a/src/grammar/testparser.py b/src/grammar/testparser.py
deleted file mode 100755
index 4b5a7fb9e10b5..0000000000000
--- a/src/grammar/testparser.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-
-# ignore-tidy-linelength
-
-import sys
-
-import os
-import subprocess
-import argparse
-
-# usage: testparser.py [-h] [-p PARSER [PARSER ...]] -s SOURCE_DIR
-
-# Parsers should read from stdin and return exit status 0 for a
-# successful parse, and nonzero for an unsuccessful parse
-
-parser = argparse.ArgumentParser()
-parser.add_argument('-p', '--parser', nargs='+')
-parser.add_argument('-s', '--source-dir', nargs=1, required=True)
-args = parser.parse_args(sys.argv[1:])
-
-total = 0
-ok = {}
-bad = {}
-for parser in args.parser:
-    ok[parser] = 0
-    bad[parser] = []
-devnull = open(os.devnull, 'w')
-print("\n")
-
-for base, dirs, files in os.walk(args.source_dir[0]):
-    for f in filter(lambda p: p.endswith('.rs'), files):
-        p = os.path.join(base, f)
-        parse_fail = 'parse-fail' in p
-        if sys.version_info.major == 3:
-            lines = open(p, encoding='utf-8').readlines()
-        else:
-            lines = open(p).readlines()
-        if any('ignore-test' in line or 'ignore-lexer-test' in line for line in lines):
-            continue
-        total += 1
-        for parser in args.parser:
-            if subprocess.call(parser, stdin=open(p), stderr=subprocess.STDOUT, stdout=devnull) == 0:
-                if parse_fail:
-                    bad[parser].append(p)
-                else:
-                    ok[parser] += 1
-            else:
-                if parse_fail:
-                    ok[parser] += 1
-                else:
-                    bad[parser].append(p)
-        parser_stats = ', '.join(['{}: {}'.format(parser, ok[parser]) for parser in args.parser])
-        sys.stdout.write("\033[K\r total: {}, {}, scanned {}"
-                         .format(total, os.path.relpath(parser_stats), os.path.relpath(p)))
-
-devnull.close()
-
-print("\n")
-
-for parser in args.parser:
-    filename = os.path.basename(parser) + '.bad'
-    print("writing {} files that did not yield the correct result with {} to {}".format(len(bad[parser]), parser, filename))
-    with open(filename, "w") as f:
-        for p in bad[parser]:
-            f.write(p)
-            f.write("\n")
diff --git a/src/grammar/tokens.h b/src/grammar/tokens.h
deleted file mode 100644
index 297e3dc841e87..0000000000000
--- a/src/grammar/tokens.h
+++ /dev/null
@@ -1,99 +0,0 @@
-enum Token {
-  SHL = 257, // Parser generators reserve 0-256 for char literals
-  SHR,
-  LE,
-  EQEQ,
-  NE,
-  GE,
-  ANDAND,
-  OROR,
-  SHLEQ,
-  SHREQ,
-  MINUSEQ,
-  ANDEQ,
-  OREQ,
-  PLUSEQ,
-  STAREQ,
-  SLASHEQ,
-  CARETEQ,
-  PERCENTEQ,
-  DOTDOT,
-  DOTDOTDOT,
-  MOD_SEP,
-  LARROW,
-  RARROW,
-  FAT_ARROW,
-  LIT_BYTE,
-  LIT_CHAR,
-  LIT_INTEGER,
-  LIT_FLOAT,
-  LIT_STR,
-  LIT_STR_RAW,
-  LIT_BYTE_STR,
-  LIT_BYTE_STR_RAW,
-  IDENT,
-  UNDERSCORE,
-  LIFETIME,
-
-  // keywords
-  SELF,
-  STATIC,
-  ABSTRACT,
-  ALIGNOF,
-  AS,
-  BECOME,
-  BREAK,
-  CATCH,
-  CRATE,
-  DEFAULT,
-  DO,
-  ELSE,
-  ENUM,
-  EXTERN,
-  FALSE,
-  FINAL,
-  FN,
-  FOR,
-  IF,
-  IMPL,
-  IN,
-  LET,
-  LOOP,
-  MACRO,
-  MATCH,
-  MOD,
-  MOVE,
-  MUT,
-  OFFSETOF,
-  OVERRIDE,
-  PRIV,
-  PUB,
-  PURE,
-  REF,
-  RETURN,
-  SIZEOF,
-  STRUCT,
-  SUPER,
-  UNION,
-  TRUE,
-  TRAIT,
-  TYPE,
-  UNSAFE,
-  UNSIZED,
-  USE,
-  VIRTUAL,
-  WHILE,
-  YIELD,
-  CONTINUE,
-  PROC,
-  BOX,
-  CONST,
-  WHERE,
-  TYPEOF,
-  INNER_DOC_COMMENT,
-  OUTER_DOC_COMMENT,
-
-  SHEBANG,
-  SHEBANG_LINE,
-  STATIC_LIFETIME
-};
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index f9c1be20b8bc1..d22420e76dcd4 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -410,7 +410,7 @@ impl<'a> Parser<'a> {
         &self.input[start..self.input.len()]
     }
 
-    /// Parses an Argument structure, or what's contained within braces inside the format string
+    /// Parses an `Argument` structure, or what's contained within braces inside the format string.
     fn argument(&mut self) -> Argument<'a> {
         let pos = self.position();
         let format = self.format();
@@ -464,7 +464,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a format specifier at the current position, returning all of the
-    /// relevant information in the FormatSpec struct.
+    /// relevant information in the `FormatSpec` struct.
     fn format(&mut self) -> FormatSpec<'a> {
         let mut spec = FormatSpec {
             fill: None,
@@ -571,7 +571,7 @@ impl<'a> Parser<'a> {
         spec
     }
 
-    /// Parses a Count parameter at the current position. This does not check
+    /// Parses a `Count` parameter at the current position. This does not check
     /// for 'CountIsNextParam' because that is only used in precision, not
     /// width.
     fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 4310bafd7812a..2238a56b29d04 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -988,10 +988,12 @@ impl<'a> LoweringContext<'a> {
         // lower attributes (we use the AST version) there is nowhere to keep
         // the `HirId`s. We don't actually need HIR version of attributes anyway.
         Attribute {
+            item: AttrItem {
+                path: attr.path.clone(),
+                tokens: self.lower_token_stream(attr.tokens.clone()),
+            },
             id: attr.id,
             style: attr.style,
-            path: attr.path.clone(),
-            tokens: self.lower_token_stream(attr.tokens.clone()),
             is_sugared_doc: attr.is_sugared_doc,
             span: attr.span,
         }
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index bdcf9e42ac2a8..23a2f115e05e2 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -196,6 +196,11 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Path {
     }
 }
 
+impl_stable_hash_for!(struct ::syntax::ast::AttrItem {
+    path,
+    tokens,
+});
+
 impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         // Make sure that these have been filtered out.
@@ -203,19 +208,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
         debug_assert!(!self.is_sugared_doc);
 
         let ast::Attribute {
+            ref item,
             id: _,
             style,
-            ref path,
-            ref tokens,
             is_sugared_doc: _,
             span,
         } = *self;
 
+        item.hash_stable(hcx, hasher);
         style.hash_stable(hcx, hasher);
-        path.hash_stable(hcx, hasher);
-        for tt in tokens.trees() {
-            tt.hash_stable(hcx, hasher);
-        }
         span.hash_stable(hcx, hasher);
     }
 }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 750ca4e32a64e..b06b63455ba4b 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -23,7 +23,7 @@ use crate::ty::relate::RelateResult;
 use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, InferConst};
 use crate::ty::{FloatVid, IntVid, TyVid, ConstVid};
-use crate::util::nodemap::FxHashMap;
+use crate::util::nodemap::{FxHashMap, FxHashSet};
 
 use errors::DiagnosticBuilder;
 use rustc_data_structures::sync::Lrc;
@@ -155,6 +155,8 @@ pub struct InferCtxt<'a, 'tcx> {
     /// avoid reporting the same error twice.
     pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>,
 
+    pub reported_closure_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
+
     /// When an error occurs, we want to avoid reporting "derived"
     /// errors that are due to this original failure. Normally, we
     /// handle this with the `err_count_on_creation` count, which
@@ -538,6 +540,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
                 selection_cache: Default::default(),
                 evaluation_cache: Default::default(),
                 reported_trait_errors: Default::default(),
+                reported_closure_mismatch: Default::default(),
                 tainted_by_errors_flag: Cell::new(false),
                 err_count_on_creation: tcx.sess.err_count(),
                 in_snapshot: Cell::new(false),
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index c2d531793372a..a1c97d6c68790 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -24,7 +24,7 @@ use crate::hir::def_id::DefId;
 use crate::infer::{self, InferCtxt};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::session::DiagnosticMessageId;
-use crate::ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use crate::ty::GenericParamDefKind;
 use crate::ty::error::ExpectedFound;
 use crate::ty::fast_reject;
@@ -37,7 +37,7 @@ use errors::{Applicability, DiagnosticBuilder, pluralise};
 use std::fmt;
 use syntax::ast;
 use syntax::symbol::{sym, kw};
-use syntax_pos::{DUMMY_SP, Span, ExpnKind};
+use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan};
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn report_fulfillment_errors(
@@ -550,7 +550,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             self.suggest_new_overflow_limit(&mut err);
         }
 
-        self.note_obligation_cause(&mut err, obligation);
+        self.note_obligation_cause_code(&mut err, &obligation.predicate, &obligation.cause.code,
+                                        &mut vec![]);
 
         err.emit();
         self.tcx.sess.abort_if_errors();
@@ -885,6 +886,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     self.tcx.hir().span_if_local(did)
                 ).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def
 
+                if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
+                    // We check closures twice, with obligations flowing in different directions,
+                    // but we want to complain about them only once.
+                    return;
+                }
+
+                self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+
                 let found = match found_trait_ref.skip_binder().substs.type_at(1).kind {
                     ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
                     _ => vec![ArgKind::empty()],
@@ -940,7 +949,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 bug!("overflow should be handled before the `report_selection_error` path");
             }
         };
+
         self.note_obligation_cause(&mut err, obligation);
+
         err.emit();
     }
 
@@ -1604,15 +1615,165 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         })
     }
 
-    fn note_obligation_cause<T>(&self,
-                                err: &mut DiagnosticBuilder<'_>,
-                                obligation: &Obligation<'tcx, T>)
-        where T: fmt::Display
-    {
-        self.note_obligation_cause_code(err,
-                                        &obligation.predicate,
-                                        &obligation.cause.code,
-                                        &mut vec![]);
+    fn note_obligation_cause(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        obligation: &PredicateObligation<'tcx>,
+    ) {
+        // First, attempt to add note to this error with an async-await-specific
+        // message, and fall back to regular note otherwise.
+        if !self.note_obligation_cause_for_async_await(err, obligation) {
+            self.note_obligation_cause_code(err, &obligation.predicate, &obligation.cause.code,
+                                            &mut vec![]);
+        }
+    }
+
+    /// Adds an async-await specific note to the diagnostic:
+    ///
+    /// ```ignore (diagnostic)
+    /// note: future does not implement `std::marker::Send` because this value is used across an
+    ///       await
+    ///   --> $DIR/issue-64130-non-send-future-diags.rs:15:5
+    ///    |
+    /// LL |     let g = x.lock().unwrap();
+    ///    |         - has type `std::sync::MutexGuard<'_, u32>`
+    /// LL |     baz().await;
+    ///    |     ^^^^^^^^^^^ await occurs here, with `g` maybe used later
+    /// LL | }
+    ///    | - `g` is later dropped here
+    /// ```
+    ///
+    /// Returns `true` if an async-await specific note was added to the diagnostic.
+    fn note_obligation_cause_for_async_await(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        obligation: &PredicateObligation<'tcx>,
+    ) -> bool {
+        debug!("note_obligation_cause_for_async_await: obligation.predicate={:?} \
+                obligation.cause.span={:?}", obligation.predicate, obligation.cause.span);
+        let source_map = self.tcx.sess.source_map();
+
+        // Look into the obligation predicate to determine the type in the generator which meant
+        // that the predicate was not satisifed.
+        let (trait_ref, target_ty) = match obligation.predicate {
+            ty::Predicate::Trait(trait_predicate) =>
+                (trait_predicate.skip_binder().trait_ref, trait_predicate.skip_binder().self_ty()),
+            _ => return false,
+        };
+        debug!("note_obligation_cause_for_async_await: target_ty={:?}", target_ty);
+
+        // Attempt to detect an async-await error by looking at the obligation causes, looking
+        // for only generators, generator witnesses, opaque types or `std::future::GenFuture` to
+        // be present.
+        //
+        // When a future does not implement a trait because of a captured type in one of the
+        // generators somewhere in the call stack, then the result is a chain of obligations.
+        // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that
+        // future is passed as an argument to a function C which requires a `Send` type, then the
+        // chain looks something like this:
+        //
+        // - `BuiltinDerivedObligation` with a generator witness (B)
+        // - `BuiltinDerivedObligation` with a generator (B)
+        // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B)
+        // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
+        // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
+        // - `BuiltinDerivedObligation` with a generator witness (A)
+        // - `BuiltinDerivedObligation` with a generator (A)
+        // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A)
+        // - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
+        // - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
+        // - `BindingObligation` with `impl_send (Send requirement)
+        //
+        // The first obligations in the chain can be used to get the details of the type that is
+        // captured but the entire chain must be inspected to detect this case.
+        let mut generator = None;
+        let mut next_code = Some(&obligation.cause.code);
+        while let Some(code) = next_code {
+            debug!("note_obligation_cause_for_async_await: code={:?}", code);
+            match code {
+                ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) |
+                ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
+                    debug!("note_obligation_cause_for_async_await: self_ty.kind={:?}",
+                           derived_obligation.parent_trait_ref.self_ty().kind);
+                    match derived_obligation.parent_trait_ref.self_ty().kind {
+                        ty::Adt(ty::AdtDef { did, .. }, ..) if
+                            self.tcx.is_diagnostic_item(sym::gen_future, *did) => {},
+                        ty::Generator(did, ..) => generator = generator.or(Some(did)),
+                        ty::GeneratorWitness(_) | ty::Opaque(..) => {},
+                        _ => return false,
+                    }
+
+                    next_code = Some(derived_obligation.parent_code.as_ref());
+                },
+                ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(..)
+                    if generator.is_some() => break,
+                _ => return false,
+            }
+        }
+
+        let generator_did = generator.expect("can only reach this if there was a generator");
+
+        // Only continue to add a note if the generator is from an `async` function.
+        let parent_node = self.tcx.parent(generator_did)
+            .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did));
+        debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node);
+        if let Some(hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(_, header, _, _),
+            ..
+        })) = parent_node {
+            debug!("note_obligation_cause_for_async_await: header={:?}", header);
+            if header.asyncness != hir::IsAsync::Async {
+                return false;
+            }
+        }
+
+        let span = self.tcx.def_span(generator_did);
+        let tables = self.tcx.typeck_tables_of(generator_did);
+        debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ",
+               generator_did, span);
+
+        // Look for a type inside the generator interior that matches the target type to get
+        // a span.
+        let target_span = tables.generator_interior_types.iter()
+            .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty::TyS::same_type(*ty, target_ty))
+            .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }|
+                 (span, source_map.span_to_snippet(*span), scope_span));
+        if let Some((target_span, Ok(snippet), scope_span)) = target_span {
+            // Look at the last interior type to get a span for the `.await`.
+            let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap();
+            let mut span = MultiSpan::from_span(await_span);
+            span.push_span_label(
+                await_span, format!("await occurs here, with `{}` maybe used later", snippet));
+
+            span.push_span_label(*target_span, format!("has type `{}`", target_ty));
+
+            // If available, use the scope span to annotate the drop location.
+            if let Some(scope_span) = scope_span {
+                span.push_span_label(
+                    source_map.end_point(*scope_span),
+                    format!("`{}` is later dropped here", snippet),
+                );
+            }
+
+            err.span_note(span, &format!(
+                "future does not implement `{}` as this value is used across an await",
+                trait_ref,
+            ));
+
+            // Add a note for the item obligation that remains - normally a note pointing to the
+            // bound that introduced the obligation (e.g. `T: Send`).
+            debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
+            self.note_obligation_cause_code(
+                err,
+                &obligation.predicate,
+                next_code.unwrap(),
+                &mut Vec::new(),
+            );
+
+            true
+        } else {
+            false
+        }
     }
 
     fn note_obligation_cause_code<T>(&self,
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 34c650b06a586..ffe1a11e81a11 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -288,6 +288,34 @@ pub struct ResolvedOpaqueTy<'tcx> {
     pub substs: SubstsRef<'tcx>,
 }
 
+/// Whenever a value may be live across a generator yield, the type of that value winds up in the
+/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
+/// captured types that can be useful for diagnostics. In particular, it stores the span that
+/// caused a given type to be recorded, along with the scope that enclosed the value (which can
+/// be used to find the await that the value is live across).
+///
+/// For example:
+///
+/// ```ignore (pseudo-Rust)
+/// async move {
+///     let x: T = ...;
+///     foo.await
+///     ...
+/// }
+/// ```
+///
+/// Here, we would store the type `T`, the span of the value `x`, and the "scope-span" for
+/// the scope that contains `x`.
+#[derive(RustcEncodable, RustcDecodable, Clone, Debug, Eq, Hash, HashStable, PartialEq)]
+pub struct GeneratorInteriorTypeCause<'tcx> {
+    /// Type of the captured binding.
+    pub ty: Ty<'tcx>,
+    /// Span of the binding that was captured.
+    pub span: Span,
+    /// Span of the scope of the captured binding.
+    pub scope_span: Option<Span>,
+}
+
 #[derive(RustcEncodable, RustcDecodable, Debug)]
 pub struct TypeckTables<'tcx> {
     /// The HirId::owner all ItemLocalIds in this table are relative to.
@@ -397,6 +425,10 @@ pub struct TypeckTables<'tcx> {
     /// leading to the member of the struct or tuple that is used instead of the
     /// entire variable.
     pub upvar_list: ty::UpvarListMap,
+
+    /// Stores the type, span and optional scope span of all types
+    /// that are live across the yield of this generator (if a generator).
+    pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>,
 }
 
 impl<'tcx> TypeckTables<'tcx> {
@@ -422,6 +454,7 @@ impl<'tcx> TypeckTables<'tcx> {
             free_region_map: Default::default(),
             concrete_opaque_types: Default::default(),
             upvar_list: Default::default(),
+            generator_interior_types: Default::default(),
         }
     }
 
@@ -729,6 +762,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
             ref free_region_map,
             ref concrete_opaque_types,
             ref upvar_list,
+            ref generator_interior_types,
 
         } = *self;
 
@@ -773,6 +807,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
             free_region_map.hash_stable(hcx, hasher);
             concrete_opaque_types.hash_stable(hcx, hasher);
             upvar_list.hash_stable(hcx, hasher);
+            generator_interior_types.hash_stable(hcx, hasher);
         })
     }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 269f87c441a82..4b9117f71be5c 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -75,7 +75,7 @@ pub use self::binding::BindingMode;
 pub use self::binding::BindingMode::*;
 
 pub use self::context::{TyCtxt, FreeRegionInfo, AllArenas, tls, keep_local};
-pub use self::context::{Lift, TypeckTables, CtxtInterners, GlobalCtxt};
+pub use self::context::{Lift, GeneratorInteriorTypeCause, TypeckTables, CtxtInterners, GlobalCtxt};
 pub use self::context::{
     UserTypeAnnotationIndex, UserType, CanonicalUserType,
     CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy,
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 2a89c94652a24..0c7aa3582ac23 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -99,8 +99,8 @@ impl Margin {
         // ```
 
         let mut m = Margin {
-            whitespace_left: if whitespace_left >= 6 { whitespace_left - 6 } else { 0 },
-            span_left: if span_left >= 6 { span_left - 6 } else { 0 },
+            whitespace_left: whitespace_left.saturating_sub(6),
+            span_left: span_left.saturating_sub(6),
             span_right: span_right + 6,
             computed_left: 0,
             computed_right: 0,
@@ -125,7 +125,7 @@ impl Margin {
         } else {
             self.computed_right
         };
-        right < line_len && line_len > self.computed_left + self.column_width
+        right < line_len && self.computed_left + self.column_width < line_len
     }
 
     fn compute(&mut self, max_line_len: usize) {
@@ -167,12 +167,10 @@ impl Margin {
     }
 
     fn right(&self, line_len: usize) -> usize {
-        if max(line_len, self.computed_left) - self.computed_left <= self.column_width {
-            line_len
-        } else if self.computed_right > line_len {
+        if line_len.saturating_sub(self.computed_left) <= self.column_width {
             line_len
         } else {
-            self.computed_right
+            min(line_len, self.computed_right)
         }
     }
 }
@@ -297,81 +295,82 @@ pub trait Emitter {
                                    source_map: &Option<Lrc<SourceMapperDyn>>,
                                    span: &mut MultiSpan,
                                    always_backtrace: bool) -> bool {
-        let mut spans_updated = false;
+        let sm = match source_map {
+            Some(ref sm) => sm,
+            None => return false,
+        };
 
-        if let Some(ref sm) = source_map {
-            let mut before_after: Vec<(Span, Span)> = vec![];
-            let mut new_labels: Vec<(Span, String)> = vec![];
+        let mut before_after: Vec<(Span, Span)> = vec![];
+        let mut new_labels: Vec<(Span, String)> = vec![];
 
-            // First, find all the spans in <*macros> and point instead at their use site
-            for sp in span.primary_spans() {
-                if sp.is_dummy() {
+        // First, find all the spans in <*macros> and point instead at their use site
+        for sp in span.primary_spans() {
+            if sp.is_dummy() {
+                continue;
+            }
+            let call_sp = sm.call_span_if_macro(*sp);
+            if call_sp != *sp && !always_backtrace {
+                before_after.push((*sp, call_sp));
+            }
+            let backtrace_len = sp.macro_backtrace().len();
+            for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() {
+                // Only show macro locations that are local
+                // and display them like a span_note
+                if trace.def_site_span.is_dummy() {
                     continue;
                 }
-                let call_sp = sm.call_span_if_macro(*sp);
-                if call_sp != *sp && !always_backtrace {
-                    before_after.push((*sp, call_sp));
+                if always_backtrace {
+                    new_labels.push((trace.def_site_span,
+                                        format!("in this expansion of `{}`{}",
+                                                trace.macro_decl_name,
+                                                if backtrace_len > 2 {
+                                                    // if backtrace_len == 1 it'll be pointed
+                                                    // at by "in this macro invocation"
+                                                    format!(" (#{})", i + 1)
+                                                } else {
+                                                    String::new()
+                                                })));
                 }
-                let backtrace_len = sp.macro_backtrace().len();
-                for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() {
-                    // Only show macro locations that are local
-                    // and display them like a span_note
-                    if trace.def_site_span.is_dummy() {
-                        continue;
-                    }
-                    if always_backtrace {
-                        new_labels.push((trace.def_site_span,
-                                            format!("in this expansion of `{}`{}",
-                                                    trace.macro_decl_name,
-                                                    if backtrace_len > 2 {
-                                                        // if backtrace_len == 1 it'll be pointed
-                                                        // at by "in this macro invocation"
-                                                        format!(" (#{})", i + 1)
-                                                    } else {
-                                                        String::new()
-                                                    })));
-                    }
-                    // Check to make sure we're not in any <*macros>
-                    if !sm.span_to_filename(trace.def_site_span).is_macros() &&
-                        !trace.macro_decl_name.starts_with("desugaring of ") &&
-                        !trace.macro_decl_name.starts_with("#[") ||
-                        always_backtrace {
-                        new_labels.push((trace.call_site,
-                                            format!("in this macro invocation{}",
-                                                    if backtrace_len > 2 && always_backtrace {
-                                                        // only specify order when the macro
-                                                        // backtrace is multiple levels deep
-                                                        format!(" (#{})", i + 1)
-                                                    } else {
-                                                        String::new()
-                                                    })));
-                        if !always_backtrace {
-                            break;
-                        }
+                // Check to make sure we're not in any <*macros>
+                if !sm.span_to_filename(trace.def_site_span).is_macros() &&
+                    !trace.macro_decl_name.starts_with("desugaring of ") &&
+                    !trace.macro_decl_name.starts_with("#[") ||
+                    always_backtrace {
+                    new_labels.push((trace.call_site,
+                                        format!("in this macro invocation{}",
+                                                if backtrace_len > 2 && always_backtrace {
+                                                    // only specify order when the macro
+                                                    // backtrace is multiple levels deep
+                                                    format!(" (#{})", i + 1)
+                                                } else {
+                                                    String::new()
+                                                })));
+                    if !always_backtrace {
+                        break;
                     }
                 }
             }
-            for (label_span, label_text) in new_labels {
-                span.push_span_label(label_span, label_text);
+        }
+        for (label_span, label_text) in new_labels {
+            span.push_span_label(label_span, label_text);
+        }
+        for sp_label in span.span_labels() {
+            if sp_label.span.is_dummy() {
+                continue;
             }
-            for sp_label in span.span_labels() {
-                if sp_label.span.is_dummy() {
-                    continue;
-                }
-                if sm.span_to_filename(sp_label.span.clone()).is_macros() &&
-                    !always_backtrace
-                {
-                    let v = sp_label.span.macro_backtrace();
-                    if let Some(use_site) = v.last() {
-                        before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
-                    }
+            if sm.span_to_filename(sp_label.span.clone()).is_macros() &&
+                !always_backtrace
+            {
+                let v = sp_label.span.macro_backtrace();
+                if let Some(use_site) = v.last() {
+                    before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
                 }
             }
-            // After we have them, make sure we replace these 'bad' def sites with their use sites
-            for (before, after) in before_after {
-                span.replace(before, after);
-                spans_updated = true;
-            }
+        }
+        // After we have them, make sure we replace these 'bad' def sites with their use sites
+        let spans_updated = !before_after.is_empty();
+        for (before, after) in before_after {
+            span.replace(before, after);
         }
 
         spans_updated
@@ -593,9 +592,9 @@ impl EmitterWriter {
 
         let left = margin.left(source_string.len()); // Left trim
         // Account for unicode characters of width !=0 that were removed.
-        let left = source_string.chars().take(left).fold(0, |acc, ch| {
-            acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)
-        });
+        let left = source_string.chars().take(left)
+            .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1))
+            .sum();
 
         self.draw_line(
             buffer,
@@ -623,18 +622,16 @@ impl EmitterWriter {
         // 3 | |
         // 4 | | }
         //   | |_^ test
-        if line.annotations.len() == 1 {
-            if let Some(ref ann) = line.annotations.get(0) {
-                if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
-                    if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
-                        let style = if ann.is_primary {
-                            Style::UnderlinePrimary
-                        } else {
-                            Style::UnderlineSecondary
-                        };
-                        buffer.putc(line_offset, width_offset + depth - 1, '/', style);
-                        return vec![(depth, style)];
-                    }
+        if let [ann] = &line.annotations[..] {
+            if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
+                if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
+                    let style = if ann.is_primary {
+                        Style::UnderlinePrimary
+                    } else {
+                        Style::UnderlineSecondary
+                    };
+                    buffer.putc(line_offset, width_offset + depth - 1, '/', style);
+                    return vec![(depth, style)];
                 }
             }
         }
@@ -763,11 +760,7 @@ impl EmitterWriter {
             annotations_position.push((p, annotation));
             for (j, next) in annotations.iter().enumerate() {
                 if j > i  {
-                    let l = if let Some(ref label) = next.label {
-                        label.len() + 2
-                    } else {
-                        0
-                    };
+                    let l = next.label.as_ref().map_or(0, |label| label.len() + 2);
                     if (overlaps(next, annotation, l) // Do not allow two labels to be in the same
                                                      // line if they overlap including padding, to
                                                      // avoid situations like:
@@ -797,9 +790,7 @@ impl EmitterWriter {
                     }
                 }
             }
-            if line_len < p {
-                line_len = p;
-            }
+            line_len = max(line_len, p);
         }
 
         if line_len != 0 {
@@ -941,17 +932,9 @@ impl EmitterWriter {
                 Style::LabelSecondary
             };
             let (pos, col) = if pos == 0 {
-                (pos + 1, if annotation.end_col + 1 > left {
-                    annotation.end_col + 1 - left
-                } else {
-                    0
-                })
+                (pos + 1, (annotation.end_col + 1).saturating_sub(left))
             } else {
-                (pos + 2, if annotation.start_col > left {
-                    annotation.start_col - left
-                } else {
-                    0
-                })
+                (pos + 2, annotation.start_col.saturating_sub(left))
             };
             if let Some(ref label) = annotation.label {
                 buffer.puts(line_offset + pos, code_offset + col, &label, style);
@@ -966,9 +949,9 @@ impl EmitterWriter {
         //   | |  |
         //   | |  something about `foo`
         //   | something about `fn foo()`
-        annotations_position.sort_by(|a, b| {
-            // Decreasing order. When `a` and `b` are the same length, prefer `Primary`.
-            (a.1.len(), !a.1.is_primary).cmp(&(b.1.len(), !b.1.is_primary)).reverse()
+        annotations_position.sort_by_key(|(_, ann)| {
+            // Decreasing order. When annotations share the same length, prefer `Primary`.
+            (Reverse(ann.len()), ann.is_primary)
         });
 
         // Write the underlines.
@@ -991,11 +974,7 @@ impl EmitterWriter {
             for p in annotation.start_col..annotation.end_col {
                 buffer.putc(
                     line_offset + 1,
-                    if code_offset + p > left {
-                        code_offset + p - left
-                    } else {
-                        0
-                    },
+                    (code_offset + p).saturating_sub(left),
                     underline,
                     style,
                 );
@@ -1018,40 +997,36 @@ impl EmitterWriter {
     }
 
     fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
+        let sm = match self.sm {
+            Some(ref sm) => sm,
+            None => return 0,
+        };
+
         let mut max = 0;
-        if let Some(ref sm) = self.sm {
-            for primary_span in msp.primary_spans() {
-                if !primary_span.is_dummy() {
-                    let hi = sm.lookup_char_pos(primary_span.hi());
-                    if hi.line > max {
-                        max = hi.line;
-                    }
-                }
+        for primary_span in msp.primary_spans() {
+            if !primary_span.is_dummy() {
+                let hi = sm.lookup_char_pos(primary_span.hi());
+                max = (hi.line).max(max);
             }
-            if !self.short_message {
-                for span_label in msp.span_labels() {
-                    if !span_label.span.is_dummy() {
-                        let hi = sm.lookup_char_pos(span_label.span.hi());
-                        if hi.line > max {
-                            max = hi.line;
-                        }
-                    }
+        }
+        if !self.short_message {
+            for span_label in msp.span_labels() {
+                if !span_label.span.is_dummy() {
+                    let hi = sm.lookup_char_pos(span_label.span.hi());
+                    max = (hi.line).max(max);
                 }
             }
         }
+
         max
     }
 
     fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize {
-
         let primary = self.get_multispan_max_line_num(span);
-        let mut max = primary;
-
-        for sub in children {
-            let sub_result = self.get_multispan_max_line_num(&sub.span);
-            max = std::cmp::max(sub_result, max);
-        }
-        max
+        children.iter()
+            .map(|sub| self.get_multispan_max_line_num(&sub.span))
+            .max()
+            .unwrap_or(primary)
     }
 
     /// Adds a left margin to every line but the first, given a padding length and the label being
@@ -1081,14 +1056,12 @@ impl EmitterWriter {
         //    `max_line_num_len`
         let padding = " ".repeat(padding + label.len() + 5);
 
-        /// Returns `true` if `style`, or the override if present and the style is `NoStyle`.
-        fn style_or_override(style: Style, override_style: Option<Style>) -> Style {
-            if let Some(o) = override_style {
-                if style == Style::NoStyle {
-                    return o;
-                }
+        /// Returns `override` if it is present and `style` is `NoStyle` or `style` otherwise
+        fn style_or_override(style: Style, override_: Option<Style>) -> Style {
+            match (style, override_) {
+                (Style::NoStyle, Some(override_)) => override_,
+                _ => style,
             }
-            style
         }
 
         let mut line_number = 0;
@@ -1324,13 +1297,12 @@ impl EmitterWriter {
                 for line in &annotated_file.lines {
                     max_line_len = max(max_line_len, annotated_file.file
                         .get_line(line.line_index - 1)
-                        .map(|s| s.len())
-                        .unwrap_or(0));
+                        .map_or(0, |s| s.len()));
                     for ann in &line.annotations {
                         span_right_margin = max(span_right_margin, ann.start_col);
                         span_right_margin = max(span_right_margin, ann.end_col);
                         // FIXME: account for labels not in the same line
-                        let label_right = ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0);
+                        let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1);
                         label_right_margin = max(label_right_margin, ann.end_col + label_right);
                     }
                 }
@@ -1459,122 +1431,125 @@ impl EmitterWriter {
         level: &Level,
         max_line_num_len: usize,
     ) -> io::Result<()> {
-        if let Some(ref sm) = self.sm {
-            let mut buffer = StyledBuffer::new();
+        let sm = match self.sm {
+            Some(ref sm) => sm,
+            None => return Ok(())
+        };
 
-            // Render the suggestion message
-            let level_str = level.to_string();
-            if !level_str.is_empty() {
-                buffer.append(0, &level_str, Style::Level(level.clone()));
-                buffer.append(0, ": ", Style::HeaderMsg);
+        let mut buffer = StyledBuffer::new();
+
+        // Render the suggestion message
+        let level_str = level.to_string();
+        if !level_str.is_empty() {
+            buffer.append(0, &level_str, Style::Level(level.clone()));
+            buffer.append(0, ": ", Style::HeaderMsg);
+        }
+        self.msg_to_buffer(
+            &mut buffer,
+            &[(suggestion.msg.to_owned(), Style::NoStyle)],
+            max_line_num_len,
+            "suggestion",
+            Some(Style::HeaderMsg),
+        );
+
+        // Render the replacements for each suggestion
+        let suggestions = suggestion.splice_lines(&**sm);
+
+        let mut row_num = 2;
+        for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) {
+            // Only show underline if the suggestion spans a single line and doesn't cover the
+            // entirety of the code output. If you have multiple replacements in the same line
+            // of code, show the underline.
+            let show_underline = !(parts.len() == 1
+                && parts[0].snippet.trim() == complete.trim())
+                && complete.lines().count() == 1;
+
+            let lines = sm.span_to_lines(parts[0].span).unwrap();
+
+            assert!(!lines.lines.is_empty());
+
+            let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
+            draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
+            let mut line_pos = 0;
+            let mut lines = complete.lines();
+            for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
+                // Print the span column to avoid confusion
+                buffer.puts(row_num,
+                            0,
+                            &self.maybe_anonymized(line_start + line_pos),
+                            Style::LineNumber);
+                // print the suggestion
+                draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+                buffer.append(row_num, line, Style::NoStyle);
+                line_pos += 1;
+                row_num += 1;
             }
-            self.msg_to_buffer(
-                &mut buffer,
-                &[(suggestion.msg.to_owned(), Style::NoStyle)],
-                max_line_num_len,
-                "suggestion",
-                Some(Style::HeaderMsg),
-            );
-
-            // Render the replacements for each suggestion
-            let suggestions = suggestion.splice_lines(&**sm);
-
-            let mut row_num = 2;
-            for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) {
-                // Only show underline if the suggestion spans a single line and doesn't cover the
-                // entirety of the code output. If you have multiple replacements in the same line
-                // of code, show the underline.
-                let show_underline = !(parts.len() == 1
-                    && parts[0].snippet.trim() == complete.trim())
-                    && complete.lines().count() == 1;
-
-                let lines = sm.span_to_lines(parts[0].span).unwrap();
-
-                assert!(!lines.lines.is_empty());
-
-                let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
-                draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
-                let mut line_pos = 0;
-                let mut lines = complete.lines();
-                for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
-                    // Print the span column to avoid confusion
-                    buffer.puts(row_num,
-                                0,
-                                &self.maybe_anonymized(line_start + line_pos),
-                                Style::LineNumber);
-                    // print the suggestion
-                    draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
-                    buffer.append(row_num, line, Style::NoStyle);
-                    line_pos += 1;
-                    row_num += 1;
-                }
 
-                // This offset and the ones below need to be signed to account for replacement code
-                // that is shorter than the original code.
-                let mut offset: isize = 0;
-                // Only show an underline in the suggestions if the suggestion is not the
-                // entirety of the code being shown and the displayed code is not multiline.
-                if show_underline {
-                    draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
-                    for part in parts {
-                        let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
-                        let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display;
-
-                        // Do not underline the leading...
-                        let start = part.snippet.len()
-                            .saturating_sub(part.snippet.trim_start().len());
-                        // ...or trailing spaces. Account for substitutions containing unicode
-                        // characters.
-                        let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| {
-                            acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)
-                        });
-
-                        let underline_start = (span_start_pos + start) as isize + offset;
-                        let underline_end = (span_start_pos + start + sub_len) as isize + offset;
-                        for p in underline_start..underline_end {
+            // This offset and the ones below need to be signed to account for replacement code
+            // that is shorter than the original code.
+            let mut offset: isize = 0;
+            // Only show an underline in the suggestions if the suggestion is not the
+            // entirety of the code being shown and the displayed code is not multiline.
+            if show_underline {
+                draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+                for part in parts {
+                    let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
+                    let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display;
+
+                    // Do not underline the leading...
+                    let start = part.snippet.len()
+                        .saturating_sub(part.snippet.trim_start().len());
+                    // ...or trailing spaces. Account for substitutions containing unicode
+                    // characters.
+                    let sub_len: usize = part.snippet.trim().chars()
+                        .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1))
+                        .sum();
+
+                    let underline_start = (span_start_pos + start) as isize + offset;
+                    let underline_end = (span_start_pos + start + sub_len) as isize + offset;
+                    for p in underline_start..underline_end {
+                        buffer.putc(row_num,
+                                    max_line_num_len + 3 + p as usize,
+                                    '^',
+                                    Style::UnderlinePrimary);
+                    }
+                    // underline removals too
+                    if underline_start == underline_end {
+                        for p in underline_start-1..underline_start+1 {
                             buffer.putc(row_num,
                                         max_line_num_len + 3 + p as usize,
-                                        '^',
-                                        Style::UnderlinePrimary);
+                                        '-',
+                                        Style::UnderlineSecondary);
                         }
-                        // underline removals too
-                        if underline_start == underline_end {
-                            for p in underline_start-1..underline_start+1 {
-                                buffer.putc(row_num,
-                                            max_line_num_len + 3 + p as usize,
-                                            '-',
-                                            Style::UnderlineSecondary);
-                            }
-                        }
-
-                        // length of the code after substitution
-                        let full_sub_len = part.snippet.chars().fold(0, |acc, ch| {
-                            acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) as isize
-                        });
-
-                        // length of the code to be substituted
-                        let snippet_len = span_end_pos as isize - span_start_pos as isize;
-                        // For multiple substitutions, use the position *after* the previous
-                        // substitutions have happened.
-                        offset += full_sub_len - snippet_len;
                     }
-                    row_num += 1;
-                }
 
-                // if we elided some lines, add an ellipsis
-                if lines.next().is_some() {
-                    buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
-                } else if !show_underline {
-                    draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
-                    row_num += 1;
+                    // length of the code after substitution
+                    let full_sub_len = part.snippet.chars()
+                        .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1))
+                        .sum::<usize>() as isize;
+
+                    // length of the code to be substituted
+                    let snippet_len = span_end_pos as isize - span_start_pos as isize;
+                    // For multiple substitutions, use the position *after* the previous
+                    // substitutions have happened.
+                    offset += full_sub_len - snippet_len;
                 }
+                row_num += 1;
             }
-            if suggestions.len() > MAX_SUGGESTIONS {
-                let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
-                buffer.puts(row_num, 0, &msg, Style::NoStyle);
+
+            // if we elided some lines, add an ellipsis
+            if lines.next().is_some() {
+                buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
+            } else if !show_underline {
+                draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
+                row_num += 1;
             }
-            emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
         }
+        if suggestions.len() > MAX_SUGGESTIONS {
+            let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
+            buffer.puts(row_num, 0, &msg, Style::NoStyle);
+        }
+        emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
         Ok(())
     }
 
@@ -1732,7 +1707,7 @@ impl FileWithAnnotatedLines {
                     hi.col_display += 1;
                 }
 
-                let ann_type = if lo.line != hi.line {
+                if lo.line != hi.line {
                     let ml = MultilineAnnotation {
                         depth: 1,
                         line_start: lo.line,
@@ -1740,34 +1715,27 @@ impl FileWithAnnotatedLines {
                         start_col: lo.col_display,
                         end_col: hi.col_display,
                         is_primary: span_label.is_primary,
-                        label: span_label.label.clone(),
+                        label: span_label.label,
                         overlaps_exactly: false,
                     };
-                    multiline_annotations.push((lo.file.clone(), ml.clone()));
-                    AnnotationType::Multiline(ml)
+                    multiline_annotations.push((lo.file, ml));
                 } else {
-                    AnnotationType::Singleline
-                };
-                let ann = Annotation {
-                    start_col: lo.col_display,
-                    end_col: hi.col_display,
-                    is_primary: span_label.is_primary,
-                    label: span_label.label.clone(),
-                    annotation_type: ann_type,
-                };
-
-                if !ann.is_multiline() {
+                    let ann = Annotation {
+                        start_col: lo.col_display,
+                        end_col: hi.col_display,
+                        is_primary: span_label.is_primary,
+                        label: span_label.label,
+                        annotation_type: AnnotationType::Singleline,
+                    };
                     add_annotation_to_file(&mut output, lo.file, lo.line, ann);
-                }
+                };
             }
         }
 
         // Find overlapping multiline annotations, put them at different depths
         multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end));
-        for item in multiline_annotations.clone() {
-            let ann = item.1;
-            for item in multiline_annotations.iter_mut() {
-                let ref mut a = item.1;
+        for (_, ann) in multiline_annotations.clone() {
+            for (_, a) in multiline_annotations.iter_mut() {
                 // Move all other multiline annotations overlapping with this one
                 // one level to the right.
                 if !(ann.same_span(a)) &&
@@ -1784,9 +1752,7 @@ impl FileWithAnnotatedLines {
 
         let mut max_depth = 0;  // max overlapping multiline spans
         for (file, ann) in multiline_annotations {
-            if ann.depth > max_depth {
-                max_depth = ann.depth;
-            }
+            max_depth = max(max_depth, ann.depth);
             let mut end_ann = ann.as_end();
             if !ann.overlaps_exactly {
                 // avoid output like
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 8474bae5a71d2..9874c0673cfc9 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -247,7 +247,7 @@ pub fn register_plugins<'a>(
     rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
 
     if sess.opts.incremental.is_some() {
-        time(sess, "garbage collect incremental cache directory", || {
+        time(sess, "garbage-collect incremental cache directory", || {
             if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
                 warn!(
                     "Error while trying to garbage collect incremental \
@@ -318,7 +318,7 @@ fn configure_and_expand_inner<'a>(
     crate_loader: &'a mut CrateLoader<'a>,
     plugin_info: PluginInfo,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
-    time(sess, "pre ast expansion lint checks", || {
+    time(sess, "pre-AST-expansion lint checks", || {
         lint::check_ast_crate(
             sess,
             &krate,
@@ -536,8 +536,8 @@ pub fn lower_to_hir(
     dep_graph: &DepGraph,
     krate: &ast::Crate,
 ) -> Result<hir::map::Forest> {
-    // Lower ast -> hir
-    let hir_forest = time(sess, "lowering ast -> hir", || {
+    // Lower AST to HIR.
+    let hir_forest = time(sess, "lowering AST -> HIR", || {
         let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver);
 
         if sess.opts.debugging_opts.hir_stats {
@@ -757,7 +757,7 @@ pub fn prepare_outputs(
     if !only_dep_info {
         if let Some(ref dir) = compiler.output_dir {
             if fs::create_dir_all(dir).is_err() {
-                sess.err("failed to find or create the directory specified by --out-dir");
+                sess.err("failed to find or create the directory specified by `--out-dir`");
                 return Err(ErrorReported);
             }
         }
@@ -830,8 +830,8 @@ pub fn create_global_ctxt(
         let global_ctxt: Option<GlobalCtxt<'_>>;
         let arenas = AllArenas::new();
 
-        // Construct the HIR map
-        let hir_map = time(sess, "indexing hir", || {
+        // Construct the HIR map.
+        let hir_map = time(sess, "indexing HIR", || {
             hir::map::map_crate(sess, cstore, &mut hir_forest, &defs)
         });
 
@@ -942,7 +942,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
         tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
     });
 
-    time(sess, "dumping chalk-like clauses", || {
+    time(sess, "dumping Chalk-like clauses", || {
         rustc_traits::lowering::dump_program_clauses(tcx);
     });
 
diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs
index 3d3a020ef0c8e..0540c95d3ded3 100644
--- a/src/librustc_macros/src/lib.rs
+++ b/src/librustc_macros/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(proc_macro_hygiene)]
 #![allow(rustc::default_hash_types)]
 
 #![recursion_limit="128"]
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index fd6744da06067..b8e2700803a5d 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -952,8 +952,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         tcx.sess.span_warn(
                             span,
                             "default bound relaxed for a type parameter, but \
-                            this does nothing because the given bound is not \
-                            a default. Only `?Sized` is supported",
+                             this does nothing because the given bound is not \
+                             a default; only `?Sized` is supported",
                         );
                     }
                 }
diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs
index d2d3854d2758c..4608eb51df74e 100644
--- a/src/librustc_typeck/check/generator_interior.rs
+++ b/src/librustc_typeck/check/generator_interior.rs
@@ -14,7 +14,7 @@ use crate::util::nodemap::FxHashMap;
 
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
-    types: FxHashMap<Ty<'tcx>, usize>,
+    types: FxHashMap<ty::GeneratorInteriorTypeCause<'tcx>, usize>,
     region_scope_tree: &'tcx region::ScopeTree,
     expr_count: usize,
     kind: hir::GeneratorKind,
@@ -83,7 +83,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
             } else {
                 // Map the type to the number of types added before it
                 let entries = self.types.len();
-                self.types.entry(&ty).or_insert(entries);
+                let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
+                self.types.entry(ty::GeneratorInteriorTypeCause {
+                    span: source_span,
+                    ty: &ty,
+                    scope_span
+                }).or_insert(entries);
             }
         } else {
             debug!("no type in expr = {:?}, count = {:?}, span = {:?}",
@@ -118,8 +123,12 @@ pub fn resolve_interior<'a, 'tcx>(
     // Sort types by insertion order
     types.sort_by_key(|t| t.1);
 
+    // Store the generator types and spans into the tables for this generator.
+    let interior_types = types.iter().cloned().map(|t| t.0).collect::<Vec<_>>();
+    visitor.fcx.inh.tables.borrow_mut().generator_interior_types = interior_types;
+
     // Extract type components
-    let type_list = fcx.tcx.mk_type_list(types.into_iter().map(|t| t.0));
+    let type_list = fcx.tcx.mk_type_list(types.into_iter().map(|t| (t.0).ty));
 
     // The types in the generator interior contain lifetimes local to the generator itself,
     // which should not be exposed outside of the generator. Therefore, we replace these
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 2d4d2e32f23db..2b34c24b266d0 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -631,26 +631,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn suggest_valid_traits(&self,
-                            err: &mut DiagnosticBuilder<'_>,
-                            valid_out_of_scope_traits: Vec<DefId>) -> bool {
+    fn suggest_valid_traits(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        valid_out_of_scope_traits: Vec<DefId>,
+    ) -> bool {
         if !valid_out_of_scope_traits.is_empty() {
             let mut candidates = valid_out_of_scope_traits;
             candidates.sort();
             candidates.dedup();
             err.help("items from traits can only be used if the trait is in scope");
-            let msg = format!("the following {traits_are} implemented but not in scope, \
-                               perhaps add a `use` for {one_of_them}:",
-                            traits_are = if candidates.len() == 1 {
-                                "trait is"
-                            } else {
-                                "traits are"
-                            },
-                            one_of_them = if candidates.len() == 1 {
-                                "it"
-                            } else {
-                                "one of them"
-                            });
+            let msg = format!(
+                "the following {traits_are} implemented but not in scope; \
+                 perhaps add a `use` for {one_of_them}:",
+                traits_are = if candidates.len() == 1 {
+                    "trait is"
+                } else {
+                    "traits are"
+                },
+                one_of_them = if candidates.len() == 1 {
+                    "it"
+                } else {
+                    "one of them"
+                },
+            );
 
             self.suggest_use_candidates(err, msg, candidates);
             true
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 5e3db1c7990d0..be5723959fb22 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2364,7 +2364,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
             // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
             if !span.is_desugaring(DesugaringKind::CondTemporary) &&
-                !span.is_desugaring(DesugaringKind::Async)
+                !span.is_desugaring(DesugaringKind::Async) &&
+                !orig_span.is_desugaring(DesugaringKind::Await)
             {
                 self.diverges.set(Diverges::WarnedAlways);
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index de78c1cdfaba3..99d62d198a9fd 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -58,6 +58,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         wbcx.visit_free_region_map();
         wbcx.visit_user_provided_tys();
         wbcx.visit_user_provided_sigs();
+        wbcx.visit_generator_interior_types();
 
         let used_trait_imports = mem::replace(
             &mut self.tables.borrow_mut().used_trait_imports,
@@ -430,6 +431,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         }
     }
 
+    fn visit_generator_interior_types(&mut self) {
+        let fcx_tables = self.fcx.tables.borrow();
+        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
+        self.tables.generator_interior_types = fcx_tables.generator_interior_types.clone();
+    }
+
     fn visit_opaque_types(&mut self, span: Span) {
         for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
             let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap();
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index 0406549ff0791..c65f71fb1a4e2 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -26,6 +26,7 @@ pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T:
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
 struct GenFuture<T: Generator<Yield = ()>>(T);
 
 // We rely on the fact that async/await futures are immovable in order to create
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 7a5c92167bc45..023952042e6d4 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2139,18 +2139,29 @@ impl rustc_serialize::Decodable for AttrId {
     }
 }
 
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub struct AttrItem {
+    pub path: Path,
+    pub tokens: TokenStream,
+}
+
 /// Metadata associated with an item.
 /// Doc-comments are promoted to attributes that have `is_sugared_doc = true`.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Attribute {
+    pub item: AttrItem,
     pub id: AttrId,
     pub style: AttrStyle,
-    pub path: Path,
-    pub tokens: TokenStream,
     pub is_sugared_doc: bool,
     pub span: Span,
 }
 
+// Compatibility impl to avoid churn, consider removing.
+impl std::ops::Deref for Attribute {
+    type Target = AttrItem;
+    fn deref(&self) -> &Self::Target { &self.item }
+}
+
 /// `TraitRef`s appear in impls.
 ///
 /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 122cb7fb12b24..7bef693a5be4c 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -9,7 +9,7 @@ pub use StabilityLevel::*;
 pub use crate::ast::Attribute;
 
 use crate::ast;
-use crate::ast::{AttrId, AttrStyle, Name, Ident, Path, PathSegment};
+use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
 use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
 use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
 use crate::mut_visit::visit_clobber;
@@ -255,9 +255,8 @@ impl MetaItem {
     }
 }
 
-impl Attribute {
-    /// Extracts the `MetaItem` from inside this `Attribute`.
-    pub fn meta(&self) -> Option<MetaItem> {
+impl AttrItem {
+    crate fn meta(&self, span: Span) -> Option<MetaItem> {
         let mut tokens = self.tokens.trees().peekable();
         Some(MetaItem {
             path: self.path.clone(),
@@ -269,9 +268,16 @@ impl Attribute {
             } else {
                 return None;
             },
-            span: self.span,
+            span,
         })
     }
+}
+
+impl Attribute {
+    /// Extracts the MetaItem from inside this Attribute.
+    pub fn meta(&self) -> Option<MetaItem> {
+        self.item.meta(self.span)
+    }
 
     pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
@@ -333,10 +339,9 @@ impl Attribute {
                 DUMMY_SP,
             );
             f(&Attribute {
+                item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
                 id: self.id,
                 style: self.style,
-                path: meta.path,
-                tokens: meta.kind.tokens(meta.span),
                 is_sugared_doc: true,
                 span: self.span,
             })
@@ -384,10 +389,9 @@ crate fn mk_attr_id() -> AttrId {
 
 pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute {
     Attribute {
+        item: AttrItem { path, tokens },
         id: mk_attr_id(),
         style,
-        path,
-        tokens,
         is_sugared_doc: false,
         span,
     }
@@ -408,10 +412,12 @@ pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute {
     let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
     let lit = Lit::from_lit_kind(lit_kind, span);
     Attribute {
+        item: AttrItem {
+            path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
+            tokens: MetaItemKind::NameValue(lit).tokens(span),
+        },
         id: mk_attr_id(),
         style,
-        path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
-        tokens: MetaItemKind::NameValue(lit).tokens(span),
         is_sugared_doc: true,
         span,
     }
@@ -524,7 +530,7 @@ impl MetaItem {
             }
             Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
                 token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
-                token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
+                token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
                 token::Nonterminal::NtPath(ref path) => path.clone(),
                 _ => return None,
             },
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 990358c674ff7..2923cc86ba029 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -122,8 +122,8 @@ impl<'a> StripUnconfigured<'a> {
 
             while !parser.check(&token::CloseDelim(token::Paren)) {
                 let lo = parser.token.span.lo();
-                let (path, tokens) = parser.parse_meta_item_unrestricted()?;
-                expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo)));
+                let item = parser.parse_attr_item()?;
+                expanded_attrs.push((item, parser.prev_span.with_lo(lo)));
                 parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
             }
 
@@ -150,11 +150,10 @@ impl<'a> StripUnconfigured<'a> {
             // `cfg_attr` inside of another `cfg_attr`. E.g.
             //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
             expanded_attrs.into_iter()
-            .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute {
+            .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute {
+                item,
                 id: attr::mk_attr_id(),
                 style: attr.style,
-                path,
-                tokens,
                 is_sugared_doc: false,
                 span,
             }))
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 02e7c6775a49d..bbd8da2acef05 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1,4 +1,4 @@
-use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
+use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
 use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
 use crate::attr::{self, HasAttrs};
 use crate::source_map::respan;
@@ -555,15 +555,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     }
 
     fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment {
-        let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
-        if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() {
-            if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else {
-                emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
-                                 span, GateIssue::Language,
-                                 "macro invocations in `extern {}` blocks are experimental");
-            }
-        }
-
         if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
             let expn_data = self.cx.current_expansion.id.expn_data();
             let suggested_limit = self.cx.ecfg.recursion_limit * 2;
@@ -578,6 +569,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             FatalError.raise();
         }
 
+        let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
         match invoc.kind {
             InvocationKind::Bang { mac, .. } => match ext {
                 SyntaxExtensionKind::Bang(expander) => {
@@ -625,9 +617,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         | Annotatable::Variant(..)
                             => panic!("unexpected annotatable"),
                     })), DUMMY_SP).into();
-                    let input = self.extract_proc_macro_attr_input(attr.tokens, span);
+                    let input = self.extract_proc_macro_attr_input(attr.item.tokens, span);
                     let tok_result = expander.expand(self.cx, span, input, item_tok);
-                    let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span);
+                    let res =
+                        self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span);
                     self.gate_proc_macro_expansion(span, &res);
                     res
                 }
@@ -757,14 +750,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
     fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) {
         let kind = match kind {
-            AstFragmentKind::Expr => "expressions",
+            AstFragmentKind::Expr |
             AstFragmentKind::OptExpr => "expressions",
             AstFragmentKind::Pat => "patterns",
-            AstFragmentKind::Ty => "types",
             AstFragmentKind::Stmts => "statements",
-            AstFragmentKind::Items => return,
-            AstFragmentKind::TraitItems => return,
-            AstFragmentKind::ImplItems => return,
+            AstFragmentKind::Ty |
+            AstFragmentKind::Items |
+            AstFragmentKind::TraitItems |
+            AstFragmentKind::ImplItems |
             AstFragmentKind::ForeignItems => return,
             AstFragmentKind::Arms
             | AstFragmentKind::Fields
@@ -1530,11 +1523,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
 
             let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
             *at = attr::Attribute {
+                item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
                 span: at.span,
                 id: at.id,
                 style: at.style,
-                path: meta.path,
-                tokens: meta.kind.tokens(meta.span),
                 is_sugared_doc: false,
             };
         } else {
@@ -1578,9 +1570,6 @@ impl<'feat> ExpansionConfig<'feat> {
         }
     }
 
-    fn macros_in_extern(&self) -> bool {
-        self.features.map_or(false, |features| features.macros_in_extern)
-    }
     fn proc_macro_hygiene(&self) -> bool {
         self.features.map_or(false, |features| features.proc_macro_hygiene)
     }
diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs
index 8f49ba9572d77..d1c50fd85945d 100644
--- a/src/libsyntax/ext/mbe/macro_parser.rs
+++ b/src/libsyntax/ext/mbe/macro_parser.rs
@@ -924,7 +924,7 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
             FatalError.raise()
         }
         sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))),
-        sym::meta => token::NtMeta(panictry!(p.parse_meta_item())),
+        sym::meta => token::NtMeta(panictry!(p.parse_attr_item())),
         sym::vis => token::NtVis(panictry!(p.parse_visibility(true))),
         sym::lifetime => if p.check_lifetime() {
             token::NtLifetime(p.expect_lifetime().ident)
diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs
index 5538daf388e2f..cda1ef1436ca1 100644
--- a/src/libsyntax/feature_gate/accepted.rs
+++ b/src/libsyntax/feature_gate/accepted.rs
@@ -245,6 +245,8 @@ declare_features! (
     (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),
+    // Allows macro invocations in `extern {}` blocks.
+    (accepted, macros_in_extern, "1.40.0", Some(49476), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs
index 38c16dbac6ab7..47ee41f0adc16 100644
--- a/src/libsyntax/feature_gate/active.rs
+++ b/src/libsyntax/feature_gate/active.rs
@@ -402,9 +402,6 @@ declare_features! (
     /// Allows infering `'static` outlives requirements (RFC 2093).
     (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
 
-    /// Allows macro invocations in `extern {}` blocks.
-    (active, macros_in_extern, "1.27.0", Some(49476), None),
-
     /// Allows accessing fields of unions inside `const` functions.
     (active, const_fn_union, "1.27.0", Some(51909), None),
 
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 80dfe9e5be0ad..3923b9f297b9f 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -550,7 +550,8 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
 }
 
 pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
-    let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr;
+    let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span }
+        = attr;
     vis.visit_path(path);
     vis.visit_tts(tokens);
     vis.visit_span(span);
@@ -681,7 +682,10 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
         token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
         token::NtLifetime(ident) => vis.visit_ident(ident),
         token::NtLiteral(expr) => vis.visit_expr(expr),
-        token::NtMeta(meta) => vis.visit_meta_item(meta),
+        token::NtMeta(AttrItem { path, tokens }) => {
+            vis.visit_path(path);
+            vis.visit_tts(tokens);
+        }
         token::NtPath(path) => vis.visit_path(path),
         token::NtTT(tt) => vis.visit_tt(tt),
         token::NtImplItem(item) =>
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 44688bd36b5fb..e74f3045db804 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -90,7 +90,7 @@ impl<'a> Parser<'a> {
         debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
                inner_parse_policy,
                self.token);
-        let (span, path, tokens, style) = match self.token.kind {
+        let (span, item, style) = match self.token.kind {
             token::Pound => {
                 let lo = self.token.span;
                 self.bump();
@@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
                 };
 
                 self.expect(&token::OpenDelim(token::Bracket))?;
-                let (path, tokens) = self.parse_meta_item_unrestricted()?;
+                let item = self.parse_attr_item()?;
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 let hi = self.prev_span;
 
@@ -142,7 +142,7 @@ impl<'a> Parser<'a> {
                     }
                 }
 
-                (attr_sp, path, tokens, style)
+                (attr_sp, item, style)
             }
             _ => {
                 let token_str = self.this_token_to_string();
@@ -151,10 +151,9 @@ impl<'a> Parser<'a> {
         };
 
         Ok(ast::Attribute {
+            item,
             id: attr::mk_attr_id(),
             style,
-            path,
-            tokens,
             is_sugared_doc: false,
             span,
         })
@@ -167,19 +166,19 @@ impl<'a> Parser<'a> {
     ///     PATH `[` TOKEN_STREAM `]`
     ///     PATH `{` TOKEN_STREAM `}`
     ///     PATH
-    ///     PATH `=` TOKEN_TREE
+    ///     PATH `=` UNSUFFIXED_LIT
     /// The delimiters or `=` are still put into the resulting token stream.
-    pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
-        let meta = match self.token.kind {
+    pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
+        let item = match self.token.kind {
             token::Interpolated(ref nt) => match **nt {
-                Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
+                Nonterminal::NtMeta(ref item) => Some(item.clone()),
                 _ => None,
             },
             _ => None,
         };
-        Ok(if let Some(meta) = meta {
+        Ok(if let Some(item) = item {
             self.bump();
-            (meta.path, meta.kind.tokens(meta.span))
+            item
         } else {
             let path = self.parse_path(PathStyle::Mod)?;
             let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
@@ -206,7 +205,7 @@ impl<'a> Parser<'a> {
             } else {
                 TokenStream::empty()
             };
-            (path, tokens)
+            ast::AttrItem { path, tokens }
         })
     }
 
@@ -263,7 +262,7 @@ impl<'a> Parser<'a> {
 
     /// Matches the following grammar (per RFC 1559).
     ///
-    ///     meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
+    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
     ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
         let nt_meta = match self.token.kind {
@@ -274,9 +273,14 @@ impl<'a> Parser<'a> {
             _ => None,
         };
 
-        if let Some(meta) = nt_meta {
-            self.bump();
-            return Ok(meta);
+        if let Some(item) = nt_meta {
+            return match item.meta(item.path.span) {
+                Some(meta) => {
+                    self.bump();
+                    Ok(meta)
+                }
+                None => self.unexpected(),
+            }
         }
 
         let lo = self.token.span;
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 66add869359d8..ac3feadce3ae6 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -47,7 +47,7 @@ impl<'a> StringReader<'a> {
                source_file: Lrc<syntax_pos::SourceFile>,
                override_span: Option<Span>) -> Self {
         if source_file.src.is_none() {
-            sess.span_diagnostic.bug(&format!("Cannot lex source_file without source: {}",
+            sess.span_diagnostic.bug(&format!("cannot lex `source_file` without source: {}",
                                               source_file.name));
         }
 
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index de72f1c4d4906..7eb2a73a11a82 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -18,6 +18,8 @@ type Expected = Option<&'static str>;
 /// `Expected` for function and lambda parameter patterns.
 pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
 
+const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here";
+
 /// Whether or not an or-pattern should be gated when occurring in the current context.
 #[derive(PartialEq)]
 pub enum GateOr { Yes, No }
@@ -40,7 +42,7 @@ impl<'a> Parser<'a> {
     /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
     pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P<Pat>> {
         // Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
-        let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes;
+        let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes;
         let leading_vert_span = self.prev_span;
 
         // Parse the possibly-or-pattern.
@@ -63,7 +65,7 @@ impl<'a> Parser<'a> {
     /// Parse the pattern for a function or function pointer parameter.
     /// Special recovery is provided for or-patterns and leading `|`.
     pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert("not allowed in a parameter pattern");
+        self.recover_leading_vert(None, "not allowed in a parameter pattern");
         let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
 
         if let PatKind::Or(..) = &pat.kind {
@@ -90,7 +92,7 @@ impl<'a> Parser<'a> {
         gate_or: GateOr,
         rc: RecoverComma,
     ) -> PResult<'a, P<Pat>> {
-        // Parse the first pattern.
+        // Parse the first pattern (`p_0`).
         let first_pat = self.parse_pat(expected)?;
         self.maybe_recover_unexpected_comma(first_pat.span, rc)?;
 
@@ -100,11 +102,12 @@ impl<'a> Parser<'a> {
             return Ok(first_pat)
         }
 
+        // Parse the patterns `p_1 | ... | p_n` where `n > 0`.
         let lo = first_pat.span;
         let mut pats = vec![first_pat];
-        while self.eat_or_separator() {
+        while self.eat_or_separator(Some(lo)) {
             let pat = self.parse_pat(expected).map_err(|mut err| {
-                err.span_label(lo, "while parsing this or-pattern starting here");
+                err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
             self.maybe_recover_unexpected_comma(pat.span, rc)?;
@@ -122,11 +125,15 @@ impl<'a> Parser<'a> {
 
     /// Eat the or-pattern `|` separator.
     /// If instead a `||` token is encountered, recover and pretend we parsed `|`.
-    fn eat_or_separator(&mut self) -> bool {
+    fn eat_or_separator(&mut self, lo: Option<Span>) -> bool {
+        if self.recover_trailing_vert(lo) {
+            return false;
+        }
+
         match self.token.kind {
             token::OrOr => {
                 // Found `||`; Recover and pretend we parsed `|`.
-                self.ban_unexpected_or_or();
+                self.ban_unexpected_or_or(lo);
                 self.bump();
                 true
             }
@@ -134,16 +141,49 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Recover if `|` or `||` is the current token and we have one of the
+    /// tokens `=>`, `if`, `=`, `:`, `;`, `,`, `]`, `)`, or `}` ahead of us.
+    ///
+    /// These tokens all indicate that we reached the end of the or-pattern
+    /// list and can now reliably say that the `|` was an illegal trailing vert.
+    /// Note that there are more tokens such as `@` for which we know that the `|`
+    /// is an illegal parse. However, the user's intent is less clear in that case.
+    fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
+        let is_end_ahead = self.look_ahead(1, |token| match &token.kind {
+            token::FatArrow // e.g. `a | => 0,`.
+            | token::Ident(kw::If, false) // e.g. `a | if expr`.
+            | token::Eq // e.g. `let a | = 0`.
+            | token::Semi // e.g. `let a |;`.
+            | token::Colon // e.g. `let a | :`.
+            | token::Comma // e.g. `let (a |,)`.
+            | token::CloseDelim(token::Bracket) // e.g. `let [a | ]`.
+            | token::CloseDelim(token::Paren) // e.g. `let (a | )`.
+            | token::CloseDelim(token::Brace) => true, // e.g. `let A { f: a | }`.
+            _ => false,
+        });
+        match (is_end_ahead, &self.token.kind) {
+            (true, token::BinOp(token::Or)) | (true, token::OrOr) => {
+                self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern");
+                self.bump();
+                true
+            }
+            _ => false,
+        }
+    }
+
     /// We have parsed `||` instead of `|`. Error and suggest `|` instead.
-    fn ban_unexpected_or_or(&mut self) {
-        self.struct_span_err(self.token.span, "unexpected token `||` after pattern")
-            .span_suggestion(
-                self.token.span,
-                "use a single `|` to separate multiple alternative patterns",
-                "|".to_owned(),
-                Applicability::MachineApplicable
-            )
-            .emit();
+    fn ban_unexpected_or_or(&mut self, lo: Option<Span>) {
+        let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern");
+        err.span_suggestion(
+            self.token.span,
+            "use a single `|` to separate multiple alternative patterns",
+            "|".to_owned(),
+            Applicability::MachineApplicable
+        );
+        if let Some(lo) = lo {
+            err.span_label(lo, WHILE_PARSING_OR_MSG);
+        }
+        err.emit();
     }
 
     /// Some special error handling for the "top-level" patterns in a match arm,
@@ -198,25 +238,38 @@ impl<'a> Parser<'a> {
     /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`.
     /// See `parse_pat_with_or` for details on parsing or-patterns.
     fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert("only allowed in a top-level pattern");
+        self.recover_leading_vert(None, "only allowed in a top-level pattern");
         self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No)
     }
 
     /// Recover if `|` or `||` is here.
     /// The user is thinking that a leading `|` is allowed in this position.
-    fn recover_leading_vert(&mut self, ctx: &str) {
+    fn recover_leading_vert(&mut self, lo: Option<Span>, ctx: &str) {
         if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
-            let span = self.token.span;
-            let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token));
-
-            self.struct_span_err(span, &format!("a leading `|` is {}", ctx))
-                .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable)
-                .emit();
-
+            self.ban_illegal_vert(lo, "leading", ctx);
             self.bump();
         }
     }
 
+    /// A `|` or possibly `||` token shouldn't be here. Ban it.
+    fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
+        let span = self.token.span;
+        let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx));
+        err.span_suggestion(
+            span,
+            &format!("remove the `{}`", pprust::token_to_string(&self.token)),
+            String::new(),
+            Applicability::MachineApplicable,
+        );
+        if let Some(lo) = lo {
+            err.span_label(lo, WHILE_PARSING_OR_MSG);
+        }
+        if let token::OrOr = self.token.kind {
+            err.note("alternatives in or-patterns are separated with `|`, not `||`");
+        }
+        err.emit();
+    }
+
     /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
     /// allowed).
     fn parse_pat_with_range_pat(
@@ -259,7 +312,7 @@ impl<'a> Parser<'a> {
                 self.bump();
                 self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?
             }
-            // At this point, token != &, &&, (, [
+            // At this point, token != `&`, `&&`, `(`, `[`, `..`, `..=`, or `...`.
             _ => if self.eat_keyword(kw::Underscore) {
                 // Parse _
                 PatKind::Wild
diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs
index 463ae9124ca23..ca823991a2e5f 100644
--- a/src/libsyntax/parse/parser/path.rs
+++ b/src/libsyntax/parse/parser/path.rs
@@ -114,9 +114,9 @@ impl<'a> Parser<'a> {
     pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
         let meta_ident = match self.token.kind {
             token::Interpolated(ref nt) => match **nt {
-                token::NtMeta(ref meta) => match meta.kind {
-                    ast::MetaItemKind::Word => Some(meta.path.clone()),
-                    _ => None,
+                token::NtMeta(ref item) => match item.tokens.is_empty() {
+                    true => Some(item.path.clone()),
+                    false => None,
                 },
                 _ => None,
             },
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index fe3b51aa246b8..fd78a2bd53442 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -687,7 +687,7 @@ pub enum Nonterminal {
     NtLifetime(ast::Ident),
     NtLiteral(P<ast::Expr>),
     /// Stuff inside brackets for attributes
-    NtMeta(ast::MetaItem),
+    NtMeta(ast::AttrItem),
     NtPath(ast::Path),
     NtVis(ast::Visibility),
     NtTT(TokenTree),
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 4b9c2d13f26b9..7d4ffe493d709 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -324,7 +324,7 @@ fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
 crate fn nonterminal_to_string(nt: &Nonterminal) -> String {
     match *nt {
         token::NtExpr(ref e)        => expr_to_string(e),
-        token::NtMeta(ref e)        => meta_item_to_string(e),
+        token::NtMeta(ref e)        => attr_item_to_string(e),
         token::NtTy(ref e)          => ty_to_string(e),
         token::NtPath(ref e)        => path_to_string(e),
         token::NtItem(ref e)        => item_to_string(e),
@@ -412,8 +412,8 @@ pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
     to_string(|s| s.print_meta_list_item(li))
 }
 
-pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
-    to_string(|s| s.print_meta_item(mi))
+fn attr_item_to_string(ai: &ast::AttrItem) -> String {
+    to_string(|s| s.print_attr_item(ai, ai.path.span))
 }
 
 pub fn attribute_to_string(attr: &ast::Attribute) -> String {
@@ -629,24 +629,28 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                 ast::AttrStyle::Inner => self.word("#!["),
                 ast::AttrStyle::Outer => self.word("#["),
             }
-            self.ibox(0);
-            match attr.tokens.trees().next() {
-                Some(TokenTree::Delimited(_, delim, tts)) => {
-                    self.print_mac_common(
-                        Some(MacHeader::Path(&attr.path)), false, None, delim, tts, true, attr.span
-                    );
-                }
-                tree => {
-                    self.print_path(&attr.path, false, 0);
-                    if tree.is_some() {
-                        self.space();
-                        self.print_tts(attr.tokens.clone(), true);
-                    }
+            self.print_attr_item(&attr.item, attr.span);
+            self.word("]");
+        }
+    }
+
+    fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
+        self.ibox(0);
+        match item.tokens.trees().next() {
+            Some(TokenTree::Delimited(_, delim, tts)) => {
+                self.print_mac_common(
+                    Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span
+                );
+            }
+            tree => {
+                self.print_path(&item.path, false, 0);
+                if tree.is_some() {
+                    self.space();
+                    self.print_tts(item.tokens.clone(), true);
                 }
             }
-            self.end();
-            self.word("]");
         }
+        self.end();
     }
 
     fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs
index bb8e3df3db921..203c4a834899b 100644
--- a/src/libsyntax_ext/cmdline_attrs.rs
+++ b/src/libsyntax_ext/cmdline_attrs.rs
@@ -1,6 +1,6 @@
 //! Attributes injected into the crate root from command line using `-Z crate-attr`.
 
-use syntax::ast::{self, AttrStyle};
+use syntax::ast::{self, AttrItem, AttrStyle};
 use syntax::attr::mk_attr;
 use syntax::panictry;
 use syntax::parse::{self, token, ParseSess};
@@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
         );
 
         let start_span = parser.token.span;
-        let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted());
+        let AttrItem { path, tokens } = panictry!(parser.parse_attr_item());
         let end_span = parser.token.span;
         if parser.token != token::Eof {
             parse_sess.span_diagnostic
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 674f17de618e9..6e83e1d3f8d4f 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -884,7 +884,7 @@ pub struct OffsetOverflowError;
 /// A single source in the `SourceMap`.
 #[derive(Clone)]
 pub struct SourceFile {
-    /// The name of the file that the source came from, source that doesn't
+    /// The name of the file that the source came from. Source that doesn't
     /// originate from files has names between angle brackets by convention
     /// (e.g., `<anon>`).
     pub name: FileName,
@@ -922,9 +922,9 @@ impl Encodable for SourceFile {
             s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
             s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
             s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
-            s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?;
-            s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?;
-            s.emit_struct_field("lines", 6, |s| {
+            s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?;
+            s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?;
+            s.emit_struct_field("lines", 5, |s| {
                 let lines = &self.lines[..];
                 // Store the length.
                 s.emit_u32(lines.len() as u32)?;
@@ -970,13 +970,13 @@ impl Encodable for SourceFile {
 
                 Ok(())
             })?;
-            s.emit_struct_field("multibyte_chars", 7, |s| {
+            s.emit_struct_field("multibyte_chars", 6, |s| {
                 self.multibyte_chars.encode(s)
             })?;
-            s.emit_struct_field("non_narrow_chars", 8, |s| {
+            s.emit_struct_field("non_narrow_chars", 7, |s| {
                 self.non_narrow_chars.encode(s)
             })?;
-            s.emit_struct_field("name_hash", 9, |s| {
+            s.emit_struct_field("name_hash", 8, |s| {
                 self.name_hash.encode(s)
             })
         })
@@ -985,7 +985,6 @@ impl Encodable for SourceFile {
 
 impl Decodable for SourceFile {
     fn decode<D: Decoder>(d: &mut D) -> Result<SourceFile, D::Error> {
-
         d.read_struct("SourceFile", 8, |d| {
             let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
             let name_was_remapped: bool =
@@ -993,9 +992,9 @@ impl Decodable for SourceFile {
             let src_hash: u128 =
                 d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
             let start_pos: BytePos =
-                d.read_struct_field("start_pos", 4, |d| Decodable::decode(d))?;
-            let end_pos: BytePos = d.read_struct_field("end_pos", 5, |d| Decodable::decode(d))?;
-            let lines: Vec<BytePos> = d.read_struct_field("lines", 6, |d| {
+                d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?;
+            let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?;
+            let lines: Vec<BytePos> = d.read_struct_field("lines", 5, |d| {
                 let num_lines: u32 = Decodable::decode(d)?;
                 let mut lines = Vec::with_capacity(num_lines as usize);
 
@@ -1024,18 +1023,18 @@ impl Decodable for SourceFile {
                 Ok(lines)
             })?;
             let multibyte_chars: Vec<MultiByteChar> =
-                d.read_struct_field("multibyte_chars", 7, |d| Decodable::decode(d))?;
+                d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?;
             let non_narrow_chars: Vec<NonNarrowChar> =
-                d.read_struct_field("non_narrow_chars", 8, |d| Decodable::decode(d))?;
+                d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
             let name_hash: u128 =
-                d.read_struct_field("name_hash", 9, |d| Decodable::decode(d))?;
+                d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
             Ok(SourceFile {
                 name,
                 name_was_remapped,
                 unmapped_path: None,
                 // `crate_of_origin` has to be set by the importer.
-                // This value matches up with rustc::hir::def_id::INVALID_CRATE.
-                // That constant is not available here unfortunately :(
+                // This value matches up with `rustc::hir::def_id::INVALID_CRATE`.
+                // That constant is not available here, unfortunately.
                 crate_of_origin: std::u32::MAX - 1,
                 start_pos,
                 end_pos,
diff --git a/src/test/ui/abi/macros/macros-in-extern.stderr b/src/test/ui/abi/macros/macros-in-extern.stderr
deleted file mode 100644
index 6ee33f4ab61f6..0000000000000
--- a/src/test/ui/abi/macros/macros-in-extern.stderr
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:26:5
-   |
-LL |     returns_isize!(rust_get_test_int);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:28:5
-   |
-LL |     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:30:5
-   |
-LL |     emits_nothing!();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs b/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs
deleted file mode 100644
index 27efa44f98032..0000000000000
--- a/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-// force-host
-// no-prefer-dynamic
-
-// Proc macros commonly used by tests.
-// `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros.
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-use proc_macro::TokenStream;
-
-// Macro that return empty token stream.
-
-#[proc_macro]
-pub fn empty(_: TokenStream) -> TokenStream {
-    TokenStream::new()
-}
-
-#[proc_macro_attribute]
-pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream {
-    TokenStream::new()
-}
-
-#[proc_macro_derive(Empty, attributes(empty_helper))]
-pub fn empty_derive(_: TokenStream) -> TokenStream {
-    TokenStream::new()
-}
-
-// Macro that panics.
-
-#[proc_macro]
-pub fn panic_bang(_: TokenStream) -> TokenStream {
-    panic!("panic-bang");
-}
-
-#[proc_macro_attribute]
-pub fn panic_attr(_: TokenStream, _: TokenStream) -> TokenStream {
-    panic!("panic-attr");
-}
-
-#[proc_macro_derive(Panic, attributes(panic_helper))]
-pub fn panic_derive(_: TokenStream) -> TokenStream {
-    panic!("panic-derive");
-}
-
-// Macros that return the input stream.
-
-#[proc_macro]
-pub fn identity(input: TokenStream) -> TokenStream {
-    input
-}
-
-#[proc_macro_attribute]
-pub fn identity_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    input
-}
-
-#[proc_macro_derive(Identity, attributes(identity_helper))]
-pub fn identity_derive(input: TokenStream) -> TokenStream {
-    input
-}
-
-// Macros that iterate and re-collect the input stream.
-
-#[proc_macro]
-pub fn recollect(input: TokenStream) -> TokenStream {
-    input.into_iter().collect()
-}
-
-#[proc_macro_attribute]
-pub fn recollect_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    input.into_iter().collect()
-}
-
-#[proc_macro_derive(Recollect, attributes(recollect_helper))]
-pub fn recollect_derive(input: TokenStream) -> TokenStream {
-    input.into_iter().collect()
-}
-
-// Macros that print their input in the original and re-collected forms (if they differ).
-
-fn print_helper(input: TokenStream, kind: &str) -> TokenStream {
-    let input_display = format!("{}", input);
-    let input_debug = format!("{:#?}", input);
-    let recollected = input.into_iter().collect();
-    let recollected_display = format!("{}", recollected);
-    let recollected_debug = format!("{:#?}", recollected);
-    println!("PRINT-{} INPUT (DISPLAY): {}", kind, input_display);
-    if recollected_display != input_display {
-        println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display);
-    }
-    println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug);
-    if recollected_debug != input_debug {
-        println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug);
-    }
-    recollected
-}
-
-#[proc_macro]
-pub fn print_bang(input: TokenStream) -> TokenStream {
-    print_helper(input, "BANG")
-}
-
-#[proc_macro_attribute]
-pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    print_helper(input, "ATTR")
-}
-
-#[proc_macro_derive(Print, attributes(print_helper))]
-pub fn print_derive(input: TokenStream) -> TokenStream {
-    print_helper(input, "DERIVE")
-}
diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.stderr b/src/test/ui/abi/proc-macro/macros-in-extern.stderr
deleted file mode 100644
index 6049c2aa4482e..0000000000000
--- a/src/test/ui/abi/proc-macro/macros-in-extern.stderr
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:14:5
-   |
-LL |     #[empty_attr]
-   |     ^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:18:5
-   |
-LL |     #[identity_attr]
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:22:5
-   |
-LL |     identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs
index 8a1744ed5f8ae..898fe22fa234f 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.rs
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs
@@ -1,26 +1,15 @@
 fn main() {
     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     f3(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
 }
 
 // Basic
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
index fbe2d192d0cce..9be44c7f44807 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
@@ -10,18 +10,7 @@ LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
    |    --                   ------------ required by this bound in `f1`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5
-   |
-LL |     f1(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), &()) -> _`
-...
-LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
-   |    --                   ------------ required by this bound in `f1`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
    |
 LL |     f2(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -34,17 +23,6 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
    |
-LL |     f2(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&'a (), &()) -> _`
-...
-LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
-   |    --                           --------------- required by this bound in `f2`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
-   |
 LL |     f3(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
    |     |
@@ -54,18 +32,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
    |    --                       --------------- required by this bound in `f3`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
-   |
-LL |     f3(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), &()) -> _`
-...
-LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
-   |    --                       --------------- required by this bound in `f3`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
    |
 LL |     f4(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -76,18 +43,7 @@ LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
    |    --                   ----------------------- required by this bound in `f4`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
-   |
-LL |     f4(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), &'r ()) -> _`
-...
-LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
-   |    --                           --------------- required by this bound in `f4`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
    |
 LL |     f5(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -98,18 +54,7 @@ LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
    |    --                   -------------------------- required by this bound in `f5`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
-   |
-LL |     f5(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&'r (), &'r ()) -> _`
-...
-LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
-   |    --                           ------------------ required by this bound in `f5`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
    |
 LL |     g1(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -120,18 +65,7 @@ LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {}
    |    --                   ------------------------- required by this bound in `g1`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
-   |
-LL |     g1(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
-...
-LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {}
-   |    --                   ------------------------- required by this bound in `g1`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
    |
 LL |     g2(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -142,18 +76,7 @@ LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
    |    --                   ---------------- required by this bound in `g2`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
-   |
-LL |     g2(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), for<'r> fn(&'r ())) -> _`
-...
-LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
-   |    --                   ---------------- required by this bound in `g2`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
    |
 LL |     g3(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -164,18 +87,7 @@ LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {}
    |    --                   ------------------------------------ required by this bound in `g3`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
-   |
-LL |     g3(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
-...
-LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {}
-   |    --                           ---------------------------- required by this bound in `g3`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
    |
 LL |     g4(|_: (), _: ()| {});
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -186,18 +98,7 @@ LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
    |    --                   --------------------------- required by this bound in `g4`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
-   |
-LL |     g4(|_: (), _: ()| {});
-   |     ^^ -------------- found signature of `fn((), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), for<'r> fn(&'r ())) -> _`
-...
-LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
-   |    --                   --------------------------- required by this bound in `g4`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
    |
 LL |     h1(|_: (), _: (), _: (), _: ()| {});
    |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
@@ -208,18 +109,7 @@ LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {}
    |    --                   -------------------------------------------- required by this bound in `h1`
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
-   |
-LL |     h1(|_: (), _: (), _: (), _: ()| {});
-   |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &(), for<'r, 's> fn(&'r (), &'s ())) -> _`
-...
-LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {}
-   |    --                   -------------------------------------------- required by this bound in `h1`
-
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
    |
 LL |     h2(|_: (), _: (), _: (), _: ()| {});
    |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
@@ -229,16 +119,5 @@ LL |     h2(|_: (), _: (), _: (), _: ()| {});
 LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), &())) {}
    |    --                   --------------------------------------------------------- required by this bound in `h2`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
-   |
-LL |     h2(|_: (), _: (), _: (), _: ()| {});
-   |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
-   |     |
-   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _`
-...
-LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), &())) {}
-   |    --                            ------------------------------------------------ required by this bound in `h2`
-
-error: aborting due to 22 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index 001e0b1cad305..696bd5c39d283 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -9,9 +9,9 @@ LL |     assert_send(local_dropped_before_await());
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
    = note: required because it appears within the type `impl std::fmt::Debug`
-   = note: required because it appears within the type `{impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `{impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
@@ -26,9 +26,9 @@ LL |     assert_send(non_send_temporary_in_match());
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
    = note: required because it appears within the type `impl std::fmt::Debug`
-   = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
@@ -45,9 +45,9 @@ LL |     assert_send(non_sync_with_method_call());
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
    = note: required because it appears within the type `std::fmt::Formatter<'_>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
-   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
@@ -68,9 +68,9 @@ LL |     assert_send(non_sync_with_method_call());
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
    = note: required because it appears within the type `std::fmt::Formatter<'_>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
-   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}`
-   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]`
-   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, ()}]>`
+   = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]`
+   = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, fn() -> impl std::future::Future {fut}, impl std::future::Future, impl std::future::Future, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`
 
diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
new file mode 100644
index 0000000000000..1936d1a2ed56e
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
@@ -0,0 +1,25 @@
+// edition:2018
+
+use std::sync::Mutex;
+
+fn is_send<T: Send>(t: T) {
+
+}
+
+async fn foo() {
+    bar(&Mutex::new(22)).await;
+}
+
+async fn bar(x: &Mutex<u32>) {
+    let g = x.lock().unwrap();
+    baz().await;
+}
+
+async fn baz() {
+
+}
+
+fn main() {
+    is_send(foo());
+    //~^ ERROR `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely [E0277]
+}
diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
new file mode 100644
index 0000000000000..9e9fc52e30b7f
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
@@ -0,0 +1,23 @@
+error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
+  --> $DIR/issue-64130-non-send-future-diags.rs:23:5
+   |
+LL | fn is_send<T: Send>(t: T) {
+   |    -------    ---- required by this bound in `is_send`
+...
+LL |     is_send(foo());
+   |     ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
+   |
+   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>`
+note: future does not implement `std::marker::Send` as this value is used across an await
+  --> $DIR/issue-64130-non-send-future-diags.rs:15:5
+   |
+LL |     let g = x.lock().unwrap();
+   |         - has type `std::sync::MutexGuard<'_, u32>`
+LL |     baz().await;
+   |     ^^^^^^^^^^^ await occurs here, with `g` maybe used later
+LL | }
+   | - `g` is later dropped here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/unreachable-lint-1.rs b/src/test/ui/async-await/unreachable-lint-1.rs
new file mode 100644
index 0000000000000..d63d643c4e70b
--- /dev/null
+++ b/src/test/ui/async-await/unreachable-lint-1.rs
@@ -0,0 +1,12 @@
+// edition:2018
+#![deny(unreachable_code)]
+
+async fn foo() {
+    return; bar().await;
+    //~^ ERROR unreachable statement
+}
+
+async fn bar() {
+}
+
+fn main() { }
diff --git a/src/test/ui/async-await/unreachable-lint-1.stderr b/src/test/ui/async-await/unreachable-lint-1.stderr
new file mode 100644
index 0000000000000..382581bf94554
--- /dev/null
+++ b/src/test/ui/async-await/unreachable-lint-1.stderr
@@ -0,0 +1,16 @@
+error: unreachable statement
+  --> $DIR/unreachable-lint-1.rs:5:13
+   |
+LL |     return; bar().await;
+   |     ------  ^^^^^^^^^^^^ unreachable statement
+   |     |
+   |     any code following this expression is unreachable
+   |
+note: lint level defined here
+  --> $DIR/unreachable-lint-1.rs:2:9
+   |
+LL | #![deny(unreachable_code)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/unreachable-lint.rs b/src/test/ui/async-await/unreachable-lint.rs
new file mode 100644
index 0000000000000..ca18cfde4f2f5
--- /dev/null
+++ b/src/test/ui/async-await/unreachable-lint.rs
@@ -0,0 +1,13 @@
+// check-pass
+// edition:2018
+#![deny(unreachable_code)]
+
+async fn foo() {
+    endless().await;
+}
+
+async fn endless() -> ! {
+    loop {}
+}
+
+fn main() { }
diff --git a/src/test/ui/cfg/cfg_stmt_expr.rs b/src/test/ui/cfg/cfg_stmt_expr.rs
index e466ad69f721c..6381bb2d58877 100644
--- a/src/test/ui/cfg/cfg_stmt_expr.rs
+++ b/src/test/ui/cfg/cfg_stmt_expr.rs
@@ -57,7 +57,7 @@ fn main() {
     // check that macro expanded code works
 
     macro_rules! if_cfg {
-        ($cfg:meta $ib:block else $eb:block) => {
+        ($cfg:meta? $ib:block else $eb:block) => {
             {
                 let r;
                 #[cfg($cfg)]
@@ -69,7 +69,7 @@ fn main() {
         }
     }
 
-    let n = if_cfg!(unset {
+    let n = if_cfg!(unset? {
         413
     } else {
         612
diff --git a/src/test/ui/coherence/coherence_inherent.old.stderr b/src/test/ui/coherence/coherence_inherent.old.stderr
index 750d243480638..e71547cb89f9c 100644
--- a/src/test/ui/coherence/coherence_inherent.old.stderr
+++ b/src/test/ui/coherence/coherence_inherent.old.stderr
@@ -5,7 +5,7 @@ LL |         s.the_fn();
    |           ^^^^^^ method not found in `&Lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use Lib::TheTrait;`
 
 error: aborting due to previous error
diff --git a/src/test/ui/coherence/coherence_inherent.re.stderr b/src/test/ui/coherence/coherence_inherent.re.stderr
index 750d243480638..e71547cb89f9c 100644
--- a/src/test/ui/coherence/coherence_inherent.re.stderr
+++ b/src/test/ui/coherence/coherence_inherent.re.stderr
@@ -5,7 +5,7 @@ LL |         s.the_fn();
    |           ^^^^^^ method not found in `&Lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use Lib::TheTrait;`
 
 error: aborting due to previous error
diff --git a/src/test/ui/coherence/coherence_inherent_cc.old.stderr b/src/test/ui/coherence/coherence_inherent_cc.old.stderr
index 59166a4609406..3683943c5c819 100644
--- a/src/test/ui/coherence/coherence_inherent_cc.old.stderr
+++ b/src/test/ui/coherence/coherence_inherent_cc.old.stderr
@@ -5,7 +5,7 @@ LL |         s.the_fn();
    |           ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use coherence_inherent_cc_lib::TheTrait;`
 
 error: aborting due to previous error
diff --git a/src/test/ui/coherence/coherence_inherent_cc.re.stderr b/src/test/ui/coherence/coherence_inherent_cc.re.stderr
index 59166a4609406..3683943c5c819 100644
--- a/src/test/ui/coherence/coherence_inherent_cc.re.stderr
+++ b/src/test/ui/coherence/coherence_inherent_cc.re.stderr
@@ -5,7 +5,7 @@ LL |         s.the_fn();
    |           ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use coherence_inherent_cc_lib::TheTrait;`
 
 error: aborting due to previous error
diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs
deleted file mode 100644
index 125af64fef05c..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-#![feature(decl_macro)]
-
-macro_rules! returns_isize(
-    ($ident:ident) => (
-        fn $ident() -> isize;
-    )
-);
-
-macro takes_u32_returns_u32($ident:ident) {
-    fn $ident (arg: u32) -> u32;
-}
-
-macro_rules! emits_nothing(
-    () => ()
-);
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    returns_isize!(rust_get_test_int);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    emits_nothing!();
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr
deleted file mode 100644
index e8b3ab5dda20d..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/feature-gate-macros_in_extern.rs:19:5
-   |
-LL |     returns_isize!(rust_get_test_int);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/feature-gate-macros_in_extern.rs:21:5
-   |
-LL |     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/feature-gate-macros_in_extern.rs:23:5
-   |
-LL |     emits_nothing!();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr
index bc0ce746be925..736369dab8354 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude.stderr
@@ -25,7 +25,7 @@ LL |         ().clone()
    |            ^^^^^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use std::clone::Clone;`
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr
index 39e32522c7a76..c3ce484edf7a9 100644
--- a/src/test/ui/hygiene/trait_items.stderr
+++ b/src/test/ui/hygiene/trait_items.stderr
@@ -8,7 +8,7 @@ LL |     pub macro m() { ().f() }
    |                        ^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use foo::T;`
 
 error: aborting due to previous error
diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr
index be8f3ab1b72e8..f0a03e1be82ac 100644
--- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr
+++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr
@@ -5,7 +5,7 @@ LL |     1u32.method();
    |          ^^^^^^ method not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
+help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
    |
 LL | use foo::Bar;
    |
@@ -23,7 +23,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method();
    |                                            ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u32>>`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following traits are implemented but not in scope, perhaps add a `use` for one of them:
+help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
    |
 LL | use foo::Bar;
    |
@@ -41,7 +41,7 @@ LL |     'a'.method();
    |         ^^^^^^ method not found in `char`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use foo::Bar;
    |
@@ -61,7 +61,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&'a')).method();
    |                                           ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use foo::Bar;
    |
@@ -73,7 +73,7 @@ LL |     1i32.method();
    |          ^^^^^^ method not found in `i32`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use no_method_suggested_traits::foo::PubPub;
    |
@@ -85,7 +85,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method();
    |                                            ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use no_method_suggested_traits::foo::PubPub;
    |
diff --git a/src/test/ui/issues/issue-10465.stderr b/src/test/ui/issues/issue-10465.stderr
index 413daa6db6787..80ca051ceff0d 100644
--- a/src/test/ui/issues/issue-10465.stderr
+++ b/src/test/ui/issues/issue-10465.stderr
@@ -5,7 +5,7 @@ LL |             b.foo();
    |               ^^^ method not found in `&b::B`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use a::A;`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr
index 3a0ab32dcc66b..2ea9dcbe9d0a4 100644
--- a/src/test/ui/issues/issue-37534.stderr
+++ b/src/test/ui/issues/issue-37534.stderr
@@ -8,7 +8,7 @@ help: possible better candidate is found in another module, you can import it in
 LL | use std::hash::Hash;
    |
 
-warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default. Only `?Sized` is supported
+warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported
   --> $DIR/issue-37534.rs:1:12
    |
 LL | struct Foo<T: ?Hash> { }
diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr
index 66680b9936e68..8b173e1b50c1e 100644
--- a/src/test/ui/issues/issue-39175.stderr
+++ b/src/test/ui/issues/issue-39175.stderr
@@ -5,7 +5,7 @@ LL |     Command::new("echo").arg("hello").exec();
    |                                       ^^^^ method not found in `&mut std::process::Command`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use std::os::unix::process::CommandExt;
    |
diff --git a/src/test/ui/issues/issue-43189.stderr b/src/test/ui/issues/issue-43189.stderr
index 33c3f18650a80..4dae6c1cd158e 100644
--- a/src/test/ui/issues/issue-43189.stderr
+++ b/src/test/ui/issues/issue-43189.stderr
@@ -5,7 +5,7 @@ LL |     ().a();
    |        ^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use xcrate_issue_43189_b::xcrate_issue_43189_a::A;
    |
diff --git a/src/test/ui/issues/issue-50571.rs b/src/test/ui/issues/issue-50571.rs
new file mode 100644
index 0000000000000..728c113bdc323
--- /dev/null
+++ b/src/test/ui/issues/issue-50571.rs
@@ -0,0 +1,6 @@
+trait Foo {
+    fn foo([a, b]: [i32; 2]) {}
+    //~^ ERROR: patterns aren't allowed in methods without bodies
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-50571.stderr b/src/test/ui/issues/issue-50571.stderr
new file mode 100644
index 0000000000000..834635388a066
--- /dev/null
+++ b/src/test/ui/issues/issue-50571.stderr
@@ -0,0 +1,13 @@
+error[E0642]: patterns aren't allowed in methods without bodies
+  --> $DIR/issue-50571.rs:2:12
+   |
+LL |     fn foo([a, b]: [i32; 2]) {}
+   |            ^^^^^^
+help: give this argument a name or use an underscore to ignore it
+   |
+LL |     fn foo(_: [i32; 2]) {}
+   |            ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0642`.
diff --git a/src/test/ui/issues/issue-58022.rs b/src/test/ui/issues/issue-58022.rs
new file mode 100644
index 0000000000000..c6dd45e6cf3e9
--- /dev/null
+++ b/src/test/ui/issues/issue-58022.rs
@@ -0,0 +1,18 @@
+pub trait Foo: Sized {
+    const SIZE: usize;
+
+    fn new(slice: &[u8; Foo::SIZE]) -> Self;
+    //~^ ERROR: type annotations needed: cannot resolve `_: Foo`
+}
+
+pub struct Bar<T: ?Sized>(T);
+
+impl Bar<[u8]> {
+    const SIZE: usize = 32;
+
+    fn new(slice: &[u8; Self::SIZE]) -> Self {
+        Foo(Box::new(*slice)) //~ ERROR: expected function, found trait `Foo`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-58022.stderr b/src/test/ui/issues/issue-58022.stderr
new file mode 100644
index 0000000000000..71bad7b81fa87
--- /dev/null
+++ b/src/test/ui/issues/issue-58022.stderr
@@ -0,0 +1,19 @@
+error[E0423]: expected function, found trait `Foo`
+  --> $DIR/issue-58022.rs:14:9
+   |
+LL |         Foo(Box::new(*slice))
+   |         ^^^ not a function
+
+error[E0283]: type annotations needed: cannot resolve `_: Foo`
+  --> $DIR/issue-58022.rs:4:25
+   |
+LL |     const SIZE: usize;
+   |     ------------------ required by `Foo::SIZE`
+LL | 
+LL |     fn new(slice: &[u8; Foo::SIZE]) -> Self;
+   |                         ^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0283, E0423.
+For more information about an error, try `rustc --explain E0283`.
diff --git a/src/test/ui/issues/issue-58344.rs b/src/test/ui/issues/issue-58344.rs
new file mode 100644
index 0000000000000..99b656d74f505
--- /dev/null
+++ b/src/test/ui/issues/issue-58344.rs
@@ -0,0 +1,50 @@
+use std::ops::Add;
+
+trait Trait<T> {
+    fn get(self) -> T;
+}
+
+struct Holder<T>(T);
+
+impl<T> Trait<T> for Holder<T> {
+    fn get(self) -> T {
+        self.0
+    }
+}
+
+enum Either<L, R> {
+    Left(L),
+    Right(R),
+}
+
+impl<L, R> Either<L, R> {
+    fn converge<T>(self) -> T where L: Trait<T>, R: Trait<T> {
+        match self {
+            Either::Left(val) => val.get(),
+            Either::Right(val) => val.get(),
+        }
+    }
+}
+
+fn add_generic<A: Add<B>, B>(lhs: A, rhs: B) -> Either<
+    impl Trait<<A as Add<B>>::Output>,
+    impl Trait<<A as Add<B>>::Output>
+> {
+    if true {
+        Either::Left(Holder(lhs + rhs))
+    } else {
+        Either::Right(Holder(lhs + rhs))
+    }
+}
+
+fn add_one(
+    value: u32,
+) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
+    //~^ ERROR: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>`
+    //~| ERROR: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>`
+    add_generic(value, 1u32)
+}
+
+pub fn main() {
+    add_one(3).converge();
+}
diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr
new file mode 100644
index 0000000000000..427d03b679d5f
--- /dev/null
+++ b/src/test/ui/issues/issue-58344.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>` is not satisfied
+  --> $DIR/issue-58344.rs:42:13
+   |
+LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
+   |
+   = note: the return type of a function must have a statically known size
+
+error[E0277]: the trait bound `impl Trait<<u32 as std::ops::Add>::Output>: Trait<u32>` is not satisfied
+  --> $DIR/issue-58344.rs:42:52
+   |
+LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as std::ops::Add>::Output>`
+   |
+   = note: the return type of a function must have a statically known size
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs
index b45aedb549ecd..afdf76b7b580f 100644
--- a/src/test/ui/macros/issue-54441.rs
+++ b/src/test/ui/macros/issue-54441.rs
@@ -1,5 +1,3 @@
-#![feature(macros_in_extern)]
-
 macro_rules! m {
     () => {
         let //~ ERROR expected
diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr
index b0fafdc3b6326..af0ee3ae8eca3 100644
--- a/src/test/ui/macros/issue-54441.stderr
+++ b/src/test/ui/macros/issue-54441.stderr
@@ -1,5 +1,5 @@
 error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found `let`
-  --> $DIR/issue-54441.rs:5:9
+  --> $DIR/issue-54441.rs:3:9
    |
 LL |         let
    |         ^^^ unexpected token
diff --git a/src/test/ui/macros/macro-first-set.rs b/src/test/ui/macros/macro-first-set.rs
index 34529cdaa64f1..eb2504d4bfdb7 100644
--- a/src/test/ui/macros/macro-first-set.rs
+++ b/src/test/ui/macros/macro-first-set.rs
@@ -252,12 +252,6 @@ test_path!(::std);
 test_path!(std::u8,);
 test_path!(any, super, super::super::self::path, X<Y>::Z<'a, T=U>);
 
-macro_rules! test_meta_block {
-    ($($m:meta)* $b:block) => {};
-}
-
-test_meta_block!(windows {});
-
 macro_rules! test_lifetime {
     (1. $($l:lifetime)* $($b:block)*) => {};
     (2. $($b:block)* $($l:lifetime)*) => {};
diff --git a/src/test/ui/macros/macro-meta-items-modern.rs b/src/test/ui/macros/macro-meta-items-modern.rs
new file mode 100644
index 0000000000000..bc6938d4a6c9a
--- /dev/null
+++ b/src/test/ui/macros/macro-meta-items-modern.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+macro_rules! check { ($meta:meta) => () }
+
+check!(meta(a b c d));
+check!(meta[a b c d]);
+check!(meta { a b c d });
+check!(meta);
+check!(meta = 0);
+
+fn main() {}
diff --git a/src/test/ui/macros/macros-in-extern-rpass.rs b/src/test/ui/macros/macros-in-extern-rpass.rs
deleted file mode 100644
index 28abef5cf4edc..0000000000000
--- a/src/test/ui/macros/macros-in-extern-rpass.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// run-pass
-// ignore-wasm32
-
-#![feature(decl_macro, macros_in_extern)]
-
-macro_rules! returns_isize(
-    ($ident:ident) => (
-        fn $ident() -> isize;
-    )
-);
-
-macro takes_u32_returns_u32($ident:ident) {
-    fn $ident (arg: u32) -> u32;
-}
-
-macro_rules! emits_nothing(
-    () => ()
-);
-
-fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 1isize);
-    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
-}
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    returns_isize!(rust_get_test_int);
-    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    emits_nothing!();
-}
diff --git a/src/test/ui/abi/macros/macros-in-extern.rs b/src/test/ui/macros/macros-in-extern.rs
similarity index 60%
rename from src/test/ui/abi/macros/macros-in-extern.rs
rename to src/test/ui/macros/macros-in-extern.rs
index bba8b15cdb035..05002ed72c78d 100644
--- a/src/test/ui/abi/macros/macros-in-extern.rs
+++ b/src/test/ui/macros/macros-in-extern.rs
@@ -1,3 +1,4 @@
+// run-pass
 // ignore-wasm32
 
 #![feature(decl_macro)]
@@ -16,17 +17,29 @@ macro_rules! emits_nothing(
     () => ()
 );
 
+macro_rules! emits_multiple(
+    () => {
+        fn f1() -> u32;
+        fn f2() -> u32;
+    }
+);
+
+mod defs {
+    #[no_mangle] extern fn f1() -> u32 { 1 }
+    #[no_mangle] extern fn f2() -> u32 { 2 }
+}
+
 fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 0isize);
+    assert_eq!(unsafe { rust_get_test_int() }, 1);
     assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
+    assert_eq!(unsafe { f1() }, 1);
+    assert_eq!(unsafe { f2() }, 2);
 }
 
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     returns_isize!(rust_get_test_int);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     emits_nothing!();
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
+    emits_multiple!();
 }
diff --git a/src/test/ui/maybe-bounds-where.stderr b/src/test/ui/maybe-bounds-where.stderr
index 78524cbabecd7..15cbce46f0a9b 100644
--- a/src/test/ui/maybe-bounds-where.stderr
+++ b/src/test/ui/maybe-bounds-where.stderr
@@ -34,7 +34,7 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i
 LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
    |           ^
 
-warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default. Only `?Sized` is supported
+warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported
   --> $DIR/maybe-bounds-where.rs:15:11
    |
 LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
diff --git a/src/test/ui/mismatched_types/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs
index 9edfebcd49471..9035e3380b0c5 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.rs
+++ b/src/test/ui/mismatched_types/issue-36053-2.rs
@@ -7,5 +7,4 @@ fn main() {
     once::<&str>("str").fuse().filter(|a: &str| true).count();
     //~^ ERROR no method named `count`
     //~| ERROR type mismatch in closure arguments
-    //~| ERROR type mismatch in closure arguments
 }
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index 89c7b0981158a..72f3220cc1aba 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -16,14 +16,6 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
    |                                |
    |                                expected signature of `for<'r> fn(&'r &str) -> _`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/issue-36053-2.rs:7:32
-   |
-LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
-   |                                |
-   |                                expected signature of `fn(&&str) -> _`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs
new file mode 100644
index 0000000000000..181c770096a5f
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs
@@ -0,0 +1,15 @@
+// In this regression test we check that a trailing `|` in an or-pattern just
+// before the `if` token of a `match` guard will receive parser recovery with
+// an appropriate error message.
+
+enum E { A, B }
+
+fn main() {
+    match E::A {
+        E::A |
+        E::B | //~ ERROR a trailing `|` is not allowed in an or-pattern
+        if true => {
+            let recovery_witness: bool = 0; //~ ERROR mismatched types
+        }
+    }
+}
diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr
new file mode 100644
index 0000000000000..db6670fc5b1e0
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr
@@ -0,0 +1,20 @@
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/issue-64879-trailing-before-guard.rs:10:14
+   |
+LL |         E::A |
+   |         ---- while parsing this or-pattern starting here
+LL |         E::B |
+   |              ^ help: remove the `|`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-64879-trailing-before-guard.rs:12:42
+   |
+LL |             let recovery_witness: bool = 0;
+   |                                          ^ expected bool, found integer
+   |
+   = note: expected type `bool`
+              found type `{integer}`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr
index c61b5cb208251..c71c760b1e303 100644
--- a/src/test/ui/or-patterns/multiple-pattern-typo.stderr
+++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr
@@ -2,37 +2,49 @@ error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:8:15
    |
 LL |         1 | 2 || 3 => (),
-   |               ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         |
+   |         while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:13:16
    |
 LL |         (1 | 2 || 3) => (),
-   |                ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          |
+   |          while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:18:16
    |
 LL |         (1 | 2 || 3,) => (),
-   |                ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          |
+   |          while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:25:18
    |
 LL |         TS(1 | 2 || 3) => (),
-   |                  ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |            -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |            |
+   |            while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:32:23
    |
 LL |         NS { f: 1 | 2 || 3 } => (),
-   |                       ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |                 -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |                 |
+   |                 while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:37:16
    |
 LL |         [1 | 2 || 3] => (),
-   |                ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          |
+   |          while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:42:9
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
index 2a3a6abfb7b62..6d08b47c058ed 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -51,24 +51,32 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let ( || A | B) = E::A;
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/or-patterns-syntactic-fail.rs:48:11
    |
 LL |     let [ || A | B ] = [E::A];
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/or-patterns-syntactic-fail.rs:49:13
    |
 LL |     let TS( || A | B );
    |             ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/or-patterns-syntactic-fail.rs:50:17
    |
 LL |     let NS { f: || A | B };
    |                 ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: no rules expected the token `|`
   --> $DIR/or-patterns-syntactic-fail.rs:14:15
diff --git a/src/test/ui/or-patterns/remove-leading-vert.fixed b/src/test/ui/or-patterns/remove-leading-vert.fixed
index e96d76061ac28..443ef398293d9 100644
--- a/src/test/ui/or-patterns/remove-leading-vert.fixed
+++ b/src/test/ui/or-patterns/remove-leading-vert.fixed
@@ -1,4 +1,4 @@
-// Test the suggestion to remove a leading `|`.
+// Test the suggestion to remove a leading, or trailing `|`.
 
 // run-rustfix
 
@@ -8,7 +8,7 @@
 fn main() {}
 
 #[cfg(FALSE)]
-fn leading_vert() {
+fn leading() {
     fn fun1(  A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     fn fun2(  A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     let (  A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
@@ -21,3 +21,26 @@ fn leading_vert() {
     let NS { f:  A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
     let NS { f:  A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
 }
+
+#[cfg(FALSE)]
+fn trailing() {
+    let ( A  ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A | B  ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let [ A | B  ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let S { f: B  }; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A | B  ): E; //~ ERROR unexpected token `||` after pattern
+    //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    match A {
+        A  => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A  => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A | B  => {} //~ ERROR unexpected token `||` after pattern
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+        | A | B  => {}
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    }
+
+    let a  : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a  = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a  ; //~ ERROR a trailing `|` is not allowed in an or-pattern
+}
diff --git a/src/test/ui/or-patterns/remove-leading-vert.rs b/src/test/ui/or-patterns/remove-leading-vert.rs
index 3790b17553fe3..3c427a6f7b23e 100644
--- a/src/test/ui/or-patterns/remove-leading-vert.rs
+++ b/src/test/ui/or-patterns/remove-leading-vert.rs
@@ -1,4 +1,4 @@
-// Test the suggestion to remove a leading `|`.
+// Test the suggestion to remove a leading, or trailing `|`.
 
 // run-rustfix
 
@@ -8,7 +8,7 @@
 fn main() {}
 
 #[cfg(FALSE)]
-fn leading_vert() {
+fn leading() {
     fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
@@ -21,3 +21,26 @@ fn leading_vert() {
     let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
     let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
 }
+
+#[cfg(FALSE)]
+fn trailing() {
+    let ( A | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let (a |,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A || B | ): E; //~ ERROR unexpected token `||` after pattern
+    //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    match A {
+        A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A || B | => {} //~ ERROR unexpected token `||` after pattern
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+        | A | B | => {}
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    }
+
+    let a | : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a | = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a | ; //~ ERROR a trailing `|` is not allowed in an or-pattern
+}
diff --git a/src/test/ui/or-patterns/remove-leading-vert.stderr b/src/test/ui/or-patterns/remove-leading-vert.stderr
index cbe06f997296a..53025230a63c2 100644
--- a/src/test/ui/or-patterns/remove-leading-vert.stderr
+++ b/src/test/ui/or-patterns/remove-leading-vert.stderr
@@ -9,6 +9,8 @@ error: a leading `|` is not allowed in a parameter pattern
    |
 LL |     fn fun2( || A: E) {}
    |              ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:14:11
@@ -21,6 +23,8 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let ( || A): (E);
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:16:11
@@ -39,6 +43,8 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let [ || A ]: [E; 1];
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:19:13
@@ -51,6 +57,8 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let TS( || A ): TS;
    |             ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:21:17
@@ -63,6 +71,130 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let NS { f: || A }: NS;
    |                 ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:27:13
+   |
+LL |     let ( A | ): E;
+   |           - ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:28:12
+   |
+LL |     let (a |,): (E,);
+   |          - ^ help: remove the `|`
+   |          |
+   |          while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:29:17
+   |
+LL |     let ( A | B | ): E;
+   |           -     ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:30:17
+   |
+LL |     let [ A | B | ]: [E; 1];
+   |           -     ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:31:18
+   |
+LL |     let S { f: B | };
+   |                - ^ help: remove the `|`
+   |                |
+   |                while parsing this or-pattern starting here
+
+error: unexpected token `||` after pattern
+  --> $DIR/remove-leading-vert.rs:32:13
+   |
+LL |     let ( A || B | ): E;
+   |           - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:32:18
+   |
+LL |     let ( A || B | ): E;
+   |           -      ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:35:11
+   |
+LL |         A | => {}
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:36:11
+   |
+LL |         A || => {}
+   |         - ^^ help: remove the `||`
+   |         |
+   |         while parsing this or-pattern starting here
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
+
+error: unexpected token `||` after pattern
+  --> $DIR/remove-leading-vert.rs:37:11
+   |
+LL |         A || B | => {}
+   |         - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:37:16
+   |
+LL |         A || B | => {}
+   |         -      ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:39:17
+   |
+LL |         | A | B | => {}
+   |           -     ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:43:11
+   |
+LL |     let a | : u8 = 0;
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:44:11
+   |
+LL |     let a | = 0;
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:45:11
+   |
+LL |     let a | ;
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
 
-error: aborting due to 11 previous errors
+error: aborting due to 26 previous errors
 
diff --git a/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs b/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs
deleted file mode 100644
index 15fe3804f9b4f..0000000000000
--- a/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// force-host
-// no-prefer-dynamic
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::TokenStream;
-
-#[proc_macro_attribute]
-pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
-    assert!(_attr.to_string().is_empty());
-    input
-}
-
-#[proc_macro_attribute]
-pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream {
-    assert!(_attr.to_string().is_empty());
-    assert!(!_input.to_string().is_empty());
-    "".parse().unwrap()
-}
-
-#[proc_macro]
-pub fn emit_input(input: TokenStream) -> TokenStream {
-    input
-}
diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.rs b/src/test/ui/proc-macro/dollar-crate-issue-62325.rs
index b7b152e669213..223c4047cb2b1 100644
--- a/src/test/ui/proc-macro/dollar-crate-issue-62325.rs
+++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.rs
@@ -7,8 +7,6 @@
 // normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
 // normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
 
-#![feature(proc_macro_hygiene)]
-
 #[macro_use]
 extern crate test_macros;
 extern crate dollar_crate_external;
diff --git a/src/test/ui/proc-macro/lifetimes.rs b/src/test/ui/proc-macro/lifetimes.rs
index d0dd1b4603b16..5605696715e34 100644
--- a/src/test/ui/proc-macro/lifetimes.rs
+++ b/src/test/ui/proc-macro/lifetimes.rs
@@ -1,7 +1,5 @@
 // aux-build:lifetimes.rs
 
-#![feature(proc_macro_hygiene)]
-
 extern crate lifetimes;
 
 use lifetimes::*;
diff --git a/src/test/ui/proc-macro/lifetimes.stderr b/src/test/ui/proc-macro/lifetimes.stderr
index 6e91201405cc6..10acd4304aa23 100644
--- a/src/test/ui/proc-macro/lifetimes.stderr
+++ b/src/test/ui/proc-macro/lifetimes.stderr
@@ -1,5 +1,5 @@
 error: expected type, found `'`
-  --> $DIR/lifetimes.rs:9:10
+  --> $DIR/lifetimes.rs:7:10
    |
 LL | type A = single_quote_alone!();
    |          ^^^^^^^^^^^^^^^^^^^^^ this macro call doesn't expand to a type
diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.rs b/src/test/ui/proc-macro/macros-in-extern-derive.rs
new file mode 100644
index 0000000000000..d2751a353bd93
--- /dev/null
+++ b/src/test/ui/proc-macro/macros-in-extern-derive.rs
@@ -0,0 +1,6 @@
+extern {
+    #[derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
+    fn f();
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.stderr b/src/test/ui/proc-macro/macros-in-extern-derive.stderr
new file mode 100644
index 0000000000000..e2afb7d34c149
--- /dev/null
+++ b/src/test/ui/proc-macro/macros-in-extern-derive.stderr
@@ -0,0 +1,8 @@
+error: `derive` may only be applied to structs, enums and unions
+  --> $DIR/macros-in-extern-derive.rs:2:5
+   |
+LL |     #[derive(Copy)]
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/proc-macro/macros-in-extern-rpass.rs b/src/test/ui/proc-macro/macros-in-extern-rpass.rs
deleted file mode 100644
index a30a287a1011b..0000000000000
--- a/src/test/ui/proc-macro/macros-in-extern-rpass.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// run-pass
-// aux-build:test-macros-rpass.rs
-// ignore-wasm32
-
-#![feature(macros_in_extern)]
-
-extern crate test_macros_rpass as test_macros;
-
-use test_macros::{nop_attr, no_output, emit_input};
-
-fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 1isize);
-    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
-}
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    #[no_output]
-    fn some_definitely_unknown_symbol_which_should_be_removed();
-
-    #[nop_attr]
-    fn rust_get_test_int() -> isize;
-
-    emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
-}
diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.rs b/src/test/ui/proc-macro/macros-in-extern.rs
similarity index 62%
rename from src/test/ui/abi/proc-macro/macros-in-extern.rs
rename to src/test/ui/proc-macro/macros-in-extern.rs
index 0477b5c48ecc9..e2b1d55aedc28 100644
--- a/src/test/ui/abi/proc-macro/macros-in-extern.rs
+++ b/src/test/ui/proc-macro/macros-in-extern.rs
@@ -1,3 +1,4 @@
+// run-pass
 // aux-build:test-macros.rs
 // ignore-wasm32
 
@@ -5,20 +6,17 @@
 extern crate test_macros;
 
 fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 0isize);
+    assert_eq!(unsafe { rust_get_test_int() }, 1);
     assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
 }
 
 #[link(name = "rust_test_helpers", kind = "static")]
 extern {
     #[empty_attr]
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     fn some_definitely_unknown_symbol_which_should_be_removed();
 
     #[identity_attr]
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
     fn rust_get_test_int() -> isize;
 
     identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
 }
diff --git a/src/test/ui/proc-macro/macros-in-type.rs b/src/test/ui/proc-macro/macros-in-type.rs
new file mode 100644
index 0000000000000..19ed58eceb964
--- /dev/null
+++ b/src/test/ui/proc-macro/macros-in-type.rs
@@ -0,0 +1,11 @@
+// check-pass
+// aux-build:test-macros.rs
+
+#[macro_use]
+extern crate test_macros;
+
+const C: identity!(u8) = 10;
+
+fn main() {
+    let c: u8 = C;
+}
diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs
index 678dc83b753b5..0096a84f14c34 100644
--- a/src/test/ui/proc-macro/proc-macro-gates.rs
+++ b/src/test/ui/proc-macro/proc-macro-gates.rs
@@ -50,7 +50,6 @@ fn attrs() {
 }
 
 fn main() {
-    let _x: identity!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types
     if let identity!(Some(_x)) = Some(3) {}
     //~^ ERROR: procedural macros cannot be expanded to patterns
 
diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr
index 8462b564ec1d7..14a4f8c0fbca2 100644
--- a/src/test/ui/proc-macro/proc-macro-gates.stderr
+++ b/src/test/ui/proc-macro/proc-macro-gates.stderr
@@ -94,17 +94,8 @@ LL |     let _x = #[identity_attr] println!();
    = note: for more information, see https://github.com/rust-lang/rust/issues/54727
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
-error[E0658]: procedural macros cannot be expanded to types
-  --> $DIR/proc-macro-gates.rs:53:13
-   |
-LL |     let _x: identity!(u32) = 3;
-   |             ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/54727
-   = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-
 error[E0658]: procedural macros cannot be expanded to patterns
-  --> $DIR/proc-macro-gates.rs:54:12
+  --> $DIR/proc-macro-gates.rs:53:12
    |
 LL |     if let identity!(Some(_x)) = Some(3) {}
    |            ^^^^^^^^^^^^^^^^^^^
@@ -113,7 +104,7 @@ LL |     if let identity!(Some(_x)) = Some(3) {}
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to statements
-  --> $DIR/proc-macro-gates.rs:57:5
+  --> $DIR/proc-macro-gates.rs:56:5
    |
 LL |     empty!(struct S;);
    |     ^^^^^^^^^^^^^^^^^^
@@ -122,7 +113,7 @@ LL |     empty!(struct S;);
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to statements
-  --> $DIR/proc-macro-gates.rs:58:5
+  --> $DIR/proc-macro-gates.rs:57:5
    |
 LL |     empty!(let _x = 3;);
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -131,7 +122,7 @@ LL |     empty!(let _x = 3;);
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to expressions
-  --> $DIR/proc-macro-gates.rs:60:14
+  --> $DIR/proc-macro-gates.rs:59:14
    |
 LL |     let _x = identity!(3);
    |              ^^^^^^^^^^^^
@@ -140,7 +131,7 @@ LL |     let _x = identity!(3);
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to expressions
-  --> $DIR/proc-macro-gates.rs:61:15
+  --> $DIR/proc-macro-gates.rs:60:15
    |
 LL |     let _x = [empty!(3)];
    |               ^^^^^^^^^
@@ -148,6 +139,6 @@ LL |     let _x = [empty!(3)];
    = note: for more information, see https://github.com/rust-lang/rust/issues/54727
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr
index 19f758fd8da77..4b1898345a32e 100644
--- a/src/test/ui/rust-2018/trait-import-suggestions.stderr
+++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr
@@ -5,7 +5,7 @@ LL |         x.foobar();
    |           ^^^^^^ method not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use crate::foo::foobar::Foobar;`
 
 error[E0599]: no method named `bar` found for type `u32` in the current scope
@@ -15,7 +15,7 @@ LL |     x.bar();
    |       ^^^ method not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use crate::foo::Bar;
    |
@@ -33,7 +33,7 @@ LL |     let y = u32::from_str("33");
    |                  ^^^^^^^^ function or associated item not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use std::str::FromStr;
    |
diff --git a/src/test/ui/shadowed/shadowed-trait-methods.stderr b/src/test/ui/shadowed/shadowed-trait-methods.stderr
index 190159ec7b88d..3597cc53420aa 100644
--- a/src/test/ui/shadowed/shadowed-trait-methods.stderr
+++ b/src/test/ui/shadowed/shadowed-trait-methods.stderr
@@ -5,7 +5,7 @@ LL |     ().f()
    |        ^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use foo::T;
    |
diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr
index 39cc66d275c24..64a92c6b0b478 100644
--- a/src/test/ui/traits/trait-item-privacy.stderr
+++ b/src/test/ui/traits/trait-item-privacy.stderr
@@ -28,7 +28,7 @@ LL |     S.b();
    |       ^ method not found in `S`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use method::B;
    |
@@ -62,7 +62,7 @@ LL |     S::b(&S);
    |        ^ function or associated item not found in `S`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use method::B;
    |
@@ -96,7 +96,7 @@ LL |     S::B;
    |        ^ associated item not found in `S`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use assoc_const::B;
    |
diff --git a/src/test/ui/traits/trait-method-private.stderr b/src/test/ui/traits/trait-method-private.stderr
index c1dd9387ebc48..10552acb348be 100644
--- a/src/test/ui/traits/trait-method-private.stderr
+++ b/src/test/ui/traits/trait-method-private.stderr
@@ -5,7 +5,7 @@ LL |     foo.method();
    |         ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL | use inner::Bar;
    |
diff --git a/src/test/ui/underscore-imports/shadow.stderr b/src/test/ui/underscore-imports/shadow.stderr
index 63262d0dc326d..102c17f6f5618 100644
--- a/src/test/ui/underscore-imports/shadow.stderr
+++ b/src/test/ui/underscore-imports/shadow.stderr
@@ -5,7 +5,7 @@ LL |         x.deref();
    |           ^^^^^ method not found in `&()`
    |
    = help: items from traits can only be used if the trait is in scope
-   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   = note: the following trait is implemented but not in scope; perhaps add a `use` for it:
            `use std::ops::Deref;`
 
 error: aborting due to previous error