about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs1
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs5
-rw-r--r--compiler/rustc_ast/src/visit.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs4
-rw-r--r--compiler/rustc_parse/src/lib.rs38
-rw-r--r--compiler/rustc_parse/src/parser/path.rs109
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs11
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr17
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-expressions.rs23
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr25
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs21
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr50
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-segments.rs35
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-segments.stderr31
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs10
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr8
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-types.rs23
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-types.stderr29
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs17
-rw-r--r--src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr14
-rw-r--r--src/test/ui/issues/issue-20616-2.rs2
-rw-r--r--src/test/ui/issues/issue-20616-2.stderr4
-rw-r--r--src/test/ui/issues/issue-20616-3.rs2
-rw-r--r--src/test/ui/issues/issue-20616-3.stderr4
-rw-r--r--src/test/ui/issues/issue-20616-4.rs2
-rw-r--r--src/test/ui/issues/issue-20616-4.stderr4
-rw-r--r--src/test/ui/issues/issue-20616-5.rs2
-rw-r--r--src/test/ui/issues/issue-20616-5.stderr4
-rw-r--r--src/test/ui/issues/issue-20616-6.rs2
-rw-r--r--src/test/ui/issues/issue-20616-6.stderr4
-rw-r--r--src/test/ui/issues/issue-20616-7.rs2
-rw-r--r--src/test/ui/issues/issue-20616-7.stderr4
-rw-r--r--src/test/ui/issues/issue-34334.rs2
-rw-r--r--src/test/ui/issues/issue-34334.stderr6
-rw-r--r--src/test/ui/parser/issue-62660.rs2
-rw-r--r--src/test/ui/parser/issue-62660.stderr4
-rw-r--r--src/test/ui/parser/issue-63116.stderr2
-rw-r--r--src/test/ui/parser/lifetime-semicolon.rs2
-rw-r--r--src/test/ui/parser/lifetime-semicolon.stderr4
-rw-r--r--src/test/ui/parser/removed-syntax-closure-lifetime.rs2
-rw-r--r--src/test/ui/parser/removed-syntax-closure-lifetime.stderr4
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-79242.rs16
-rw-r--r--src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs34
44 files changed, 532 insertions, 63 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 328086af183..92b58782465 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1845,6 +1845,7 @@ impl UintTy {
 pub struct AssocTyConstraint {
     pub id: NodeId,
     pub ident: Ident,
+    pub gen_args: Option<GenericArgs>,
     pub kind: AssocTyConstraintKind,
     pub span: Span,
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index ddae0ab03e4..878196a6933 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -441,11 +441,14 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
 }
 
 pub fn noop_visit_ty_constraint<T: MutVisitor>(
-    AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
+    AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
     vis: &mut T,
 ) {
     vis.visit_id(id);
     vis.visit_ident(ident);
+    if let Some(ref mut gen_args) = gen_args {
+        vis.visit_generic_args(gen_args);
+    }
     match kind {
         AssocTyConstraintKind::Equality { ref mut ty } => {
             vis.visit_ty(ty);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 560064182e1..60ff956bd96 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -485,6 +485,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
     constraint: &'a AssocTyConstraint,
 ) {
     visitor.visit_ident(constraint.ident);
+    if let Some(ref gen_args) = constraint.gen_args {
+        visitor.visit_generic_args(gen_args.span(), gen_args);
+    }
     match constraint.kind {
         AssocTyConstraintKind::Equality { ref ty } => {
             visitor.visit_ty(ty);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index f7c693cc94d..eb45a0e1c05 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1000,6 +1000,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
 
+        if let Some(ref gen_args) = constraint.gen_args {
+            self.sess.span_fatal(
+                gen_args.span(),
+                "generic associated types in trait paths are currently not implemented",
+            );
+        }
+
         let kind = match constraint.kind {
             AssocTyConstraintKind::Equality { ref ty } => {
                 hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 08ebcbf381a..4ec3e39facc 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1372,16 +1372,18 @@ fn deny_equality_constraints(
                         if param.ident == *ident {
                             let param = ident;
                             match &full_path.segments[qself.position..] {
-                                [PathSegment { ident, .. }] => {
+                                [PathSegment { ident, args, .. }] => {
                                     // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
                                     let mut assoc_path = full_path.clone();
                                     // Remove `Bar` from `Foo::Bar`.
                                     assoc_path.segments.pop();
                                     let len = assoc_path.segments.len() - 1;
+                                    let gen_args = args.as_ref().map(|p| (**p).clone());
                                     // Build `<Bar = RhsTy>`.
                                     let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
                                         id: rustc_ast::node_id::DUMMY_NODE_ID,
                                         ident: *ident,
+                                        gen_args,
                                         kind: AssocTyConstraintKind::Equality {
                                             ty: predicate.rhs_ty.clone(),
                                         },
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 8a6b0230023..9953d3255b7 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -9,12 +9,14 @@ use rustc_ast as ast;
 use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{self, LazyTokenStream, TokenStream, TokenTree};
 use rustc_ast_pretty::pprust;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diagnostic, FatalError, Level, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::{symbol::kw, FileName, SourceFile, Span, DUMMY_SP};
 
 use smallvec::SmallVec;
+use std::cell::RefCell;
 use std::mem;
 use std::path::Path;
 use std::str;
@@ -281,6 +283,25 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
         }
     };
 
+    // Caches the stringification of 'good' `TokenStreams` which passed
+    // `tokenstream_probably_equal_for_proc_macro`. This allows us to avoid
+    // repeatedly stringifying and comparing the same `TokenStream` for deeply
+    // nested nonterminals.
+    //
+    // We cache by the strinification instead of the `TokenStream` to avoid
+    // needing to implement `Hash` for `TokenStream`. Note that it's possible to
+    // have two distinct `TokenStream`s that stringify to the same result
+    // (e.g. if they differ only in hygiene information). However, any
+    // information lost during the stringification process is also intentionally
+    // ignored by `tokenstream_probably_equal_for_proc_macro`, so it's fine
+    // that a single cache entry may 'map' to multiple distinct `TokenStream`s.
+    //
+    // This is a temporary hack to prevent compilation blowup on certain inputs.
+    // The entire pretty-print/retokenize process will be removed soon.
+    thread_local! {
+        static GOOD_TOKEN_CACHE: RefCell<FxHashSet<String>> = Default::default();
+    }
+
     // FIXME(#43081): Avoid this pretty-print + reparse hack
     // Pretty-print the AST struct without inserting any parenthesis
     // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`).
@@ -288,7 +309,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
     // ever used for a comparison against the capture tokenstream.
     let source = pprust::nonterminal_to_string_no_extra_parens(nt);
     let filename = FileName::macro_expansion_source_code(&source);
-    let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span));
+    let reparsed_tokens = parse_stream_from_source_str(filename, source.clone(), sess, Some(span));
 
     // During early phases of the compiler the AST could get modified
     // directly (e.g., attributes added or removed) and the internal cache
@@ -314,8 +335,13 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
     // modifications, including adding/removing typically non-semantic
     // tokens such as extra braces and commas, don't happen.
     if let Some(tokens) = tokens {
+        if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source)) {
+            return tokens;
+        }
+
         // Compare with a non-relaxed delim match to start.
         if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) {
+            GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
             return tokens;
         }
 
@@ -324,6 +350,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
         // token stream to match up with inserted parenthesis in the reparsed stream.
         let source_with_parens = pprust::nonterminal_to_string(nt);
         let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens);
+
+        if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source_with_parens)) {
+            return tokens;
+        }
+
         let reparsed_tokens_with_parens = parse_stream_from_source_str(
             filename_with_parens,
             source_with_parens,
@@ -339,6 +370,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
             sess,
             true,
         ) {
+            GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
             return tokens;
         }
 
@@ -418,9 +450,9 @@ pub fn tokenstream_probably_equal_for_proc_macro(
         // to iterate breaking tokens mutliple times. For example:
         // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]'
         let mut token_trees: SmallVec<[_; 2]>;
-        if let TokenTree::Token(token) = &tree {
+        if let TokenTree::Token(token) = tree {
             let mut out = SmallVec::<[_; 2]>::new();
-            out.push(token.clone());
+            out.push(token);
             // Iterate to fixpoint:
             // * We start off with 'out' containing our initial token, and `temp` empty
             // * If we are able to break any tokens in `out`, then `out` will have
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index d64fd59b0a6..17e5bcf7605 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -3,10 +3,9 @@ use super::{Parser, TokenType};
 use crate::maybe_whole;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
-use rustc_ast::{
-    self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs,
-};
+use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
 use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
+use rustc_ast::{GenericArg, GenericArgs};
 use rustc_ast::{Path, PathSegment, QSelf};
 use rustc_errors::{pluralize, Applicability, PResult};
 use rustc_span::source_map::{BytePos, Span};
@@ -414,32 +413,40 @@ impl<'a> Parser<'a> {
 
     /// Parses a single argument in the angle arguments `<...>` of a path segment.
     fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
-        if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon))
-        {
-            // Parse associated type constraint.
-            let lo = self.token.span;
-            let ident = self.parse_ident()?;
-            let kind = if self.eat(&token::Eq) {
-                let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
-                AssocTyConstraintKind::Equality { ty }
-            } else if self.eat(&token::Colon) {
-                let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
-                AssocTyConstraintKind::Bound { bounds }
-            } else {
-                unreachable!();
-            };
+        let lo = self.token.span;
+        let arg = self.parse_generic_arg()?;
+        match arg {
+            Some(arg) => {
+                if self.check(&token::Colon) | self.check(&token::Eq) {
+                    let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
+                    let kind = if self.eat(&token::Colon) {
+                        // Parse associated type constraint bound.
+
+                        let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+                        AssocTyConstraintKind::Bound { bounds }
+                    } else if self.eat(&token::Eq) {
+                        // Parse associated type equality constraint
+
+                        let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
+                        AssocTyConstraintKind::Equality { ty }
+                    } else {
+                        unreachable!();
+                    };
 
-            let span = lo.to(self.prev_token.span);
+                    let span = lo.to(self.prev_token.span);
 
-            // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
-            if let AssocTyConstraintKind::Bound { .. } = kind {
-                self.sess.gated_spans.gate(sym::associated_type_bounds, span);
+                    // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
+                    if let AssocTyConstraintKind::Bound { .. } = kind {
+                        self.sess.gated_spans.gate(sym::associated_type_bounds, span);
+                    }
+                    let constraint =
+                        AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
+                    Ok(Some(AngleBracketedArg::Constraint(constraint)))
+                } else {
+                    Ok(Some(AngleBracketedArg::Arg(arg)))
+                }
             }
-
-            let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span };
-            Ok(Some(AngleBracketedArg::Constraint(constraint)))
-        } else {
-            Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg))
+            _ => Ok(None),
         }
     }
 
@@ -542,4 +549,54 @@ impl<'a> Parser<'a> {
         };
         Ok(Some(arg))
     }
+
+    fn get_ident_from_generic_arg(
+        &self,
+        gen_arg: GenericArg,
+        lo: Span,
+    ) -> PResult<'a, (Ident, Option<GenericArgs>)> {
+        let gen_arg_span = gen_arg.span();
+        match gen_arg {
+            GenericArg::Type(t) => match t.into_inner().kind {
+                ast::TyKind::Path(qself, mut path) => {
+                    if let Some(qself) = qself {
+                        let mut err = self.struct_span_err(
+                            gen_arg_span,
+                            "qualified paths cannot be used in associated type constraints",
+                        );
+                        err.span_label(
+                            qself.path_span,
+                            "not allowed in associated type constraints",
+                        );
+                        return Err(err);
+                    }
+                    if path.segments.len() == 1 {
+                        let path_seg = path.segments.remove(0);
+                        let ident = path_seg.ident;
+                        let gen_args = path_seg.args.map(|args| args.into_inner());
+                        return Ok((ident, gen_args));
+                    }
+                    let err = self.struct_span_err(
+                        path.span,
+                        "paths with multiple segments cannot be used in associated type constraints",
+                    );
+                    return Err(err);
+                }
+                _ => {
+                    let span = lo.to(self.prev_token.span);
+                    let err = self.struct_span_err(
+                        span,
+                        "only path types can be used in associated type constraints",
+                    );
+                    return Err(err);
+                }
+            },
+            _ => {
+                let span = lo.to(self.prev_token.span);
+                let err = self
+                    .struct_span_err(span, "only types can be used in associated type constraints");
+                return Err(err);
+            }
+        }
+    }
 }
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs
new file mode 100644
index 00000000000..b10bfea9feb
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs
@@ -0,0 +1,11 @@
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+trait X {
+    type Y<'a>;
+}
+
+fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
+    //~^ ERROR: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr
new file mode 100644
index 00000000000..051253cadc6
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr
@@ -0,0 +1,17 @@
+error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
+  --> $DIR/trait-path-expected-token.rs:8:33
+   |
+LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
+   |                                 ^ expected one of 7 possible tokens
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/trait-path-expected-token.rs:1:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs
new file mode 100644
index 00000000000..de61cfa1cf7
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs
@@ -0,0 +1,23 @@
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+mod error1 {
+  trait X {
+      type Y<'a>;
+  }
+
+  fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
+      //~^ ERROR: expected expression, found `)`
+}
+
+mod error2 {
+
+  trait X {
+      type Y<'a>;
+  }
+
+  fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
+    //~^ ERROR: only types can be used in associated type constraints
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
new file mode 100644
index 00000000000..a9ba8adcaba
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
@@ -0,0 +1,25 @@
+error: expected expression, found `)`
+  --> $DIR/trait-path-expressions.rs:9:39
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
+   |                              -        ^ expected expression
+   |                              |
+   |                              while parsing a const generic argument starting here
+
+error: only types can be used in associated type constraints
+  --> $DIR/trait-path-expressions.rs:19:30
+   |
+LL |   fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
+   |                              ^^^^^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/trait-path-expressions.rs:1:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs
new file mode 100644
index 00000000000..dad8c2a2909
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs
@@ -0,0 +1,21 @@
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+trait X {
+    type Y<'a>;
+}
+
+const _: () = {
+  fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+      //~^ ERROR: expected one of `>`, const, lifetime, or type, found `:`
+      //~| ERROR: expected parameter name, found `>`
+      //~| ERROR: expected one of `!`, `)`, `+`, `,`, or `::`, found `>`
+      //~| ERROR: constant provided when a type was expected
+};
+
+const _: () = {
+  fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
+      //~^ ERROR: expected one of `>`, const, lifetime, or type, found `=`
+};
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr
new file mode 100644
index 00000000000..583697f0b67
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr
@@ -0,0 +1,50 @@
+error: expected one of `>`, const, lifetime, or type, found `:`
+  --> $DIR/trait-path-missing-gen_arg.rs:9:30
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+   |                              ^ expected one of `>`, const, lifetime, or type
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |   fn f1<'a>(arg : Box<{ dyn X< : 32 } >>) {}
+   |                       ^             ^
+
+error: expected parameter name, found `>`
+  --> $DIR/trait-path-missing-gen_arg.rs:9:36
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+   |                                    ^ expected parameter name
+
+error: expected one of `!`, `)`, `+`, `,`, or `::`, found `>`
+  --> $DIR/trait-path-missing-gen_arg.rs:9:36
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+   |                                    ^
+   |                                    |
+   |                                    expected one of `!`, `)`, `+`, `,`, or `::`
+   |                                    help: missing `,`
+
+error: expected one of `>`, const, lifetime, or type, found `=`
+  --> $DIR/trait-path-missing-gen_arg.rs:17:30
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
+   |                              ^ expected one of `>`, const, lifetime, or type
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/trait-path-missing-gen_arg.rs:1:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0747]: constant provided when a type was expected
+  --> $DIR/trait-path-missing-gen_arg.rs:9:23
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< : 32 >>) {}
+   |                       ^^^^^^^^^^^
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs
new file mode 100644
index 00000000000..0bf48b1f418
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs
@@ -0,0 +1,35 @@
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+const _: () = {
+    trait X {
+        type Y<'a>;
+    }
+
+    fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
+        //~^ ERROR: paths with multiple segments cannot be used in associated type constraints
+  };
+
+const _: () = {
+    trait X {
+        type Y<'a>;
+    }
+
+    trait Z {}
+
+    impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
+        //~^ ERROR: qualified paths cannot be used in associated type constraints
+};
+
+const _: () = {
+    trait X {
+      type Y<'a>;
+    }
+
+    trait Z {}
+
+    impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
+        //~^ ERROR: paths with multiple segments cannot be used in associated type constraints
+};
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
new file mode 100644
index 00000000000..4e2b84d0182
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
@@ -0,0 +1,31 @@
+error: paths with multiple segments cannot be used in associated type constraints
+  --> $DIR/trait-path-segments.rs:9:31
+   |
+LL |     fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
+   |                               ^^^^
+
+error: qualified paths cannot be used in associated type constraints
+  --> $DIR/trait-path-segments.rs:20:16
+   |
+LL |     impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
+   |                ^^^^^^^^^-^^^^^^^^
+   |                         |
+   |                         not allowed in associated type constraints
+
+error: paths with multiple segments cannot be used in associated type constraints
+  --> $DIR/trait-path-segments.rs:31:16
+   |
+LL |     impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
+   |                ^^^^^^^^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/trait-path-segments.rs:1:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
new file mode 100644
index 00000000000..e203a5e0d2d
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs
@@ -0,0 +1,10 @@
+#![feature(generic_associated_types)]
+
+trait X {
+    type Y<'a>;
+}
+
+const _: () = {
+  fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
+      //~^  ERROR: generic associated types in trait paths are currently not implemented
+};
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
new file mode 100644
index 00000000000..e59a72a99ee
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
@@ -0,0 +1,8 @@
+error: generic associated types in trait paths are currently not implemented
+  --> $DIR/trait-path-type-error-once-implemented.rs:8:30
+   |
+LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
+   |                              ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.rs b/src/test/ui/generic-associated-types/parse/trait-path-types.rs
new file mode 100644
index 00000000000..6cdb501ec65
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-types.rs
@@ -0,0 +1,23 @@
+#![feature(generic_associated_types)]
+//~^ WARNING: the feature `generic_associated_types` is incomplete
+
+trait X {
+    type Y<'a>;
+}
+
+const _: () = {
+  fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
+      //~^ ERROR: only path types can be used in associated type constraints
+};
+
+const _: () = {
+  fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
+      //~^ ERROR: only path types can be used in associated type constraints
+};
+
+const _: () = {
+  fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
+      //~^ ERROR: only types can be used in associated type constraints
+};
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
new file mode 100644
index 00000000000..f5be084613b
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
@@ -0,0 +1,29 @@
+error: only path types can be used in associated type constraints
+  --> $DIR/trait-path-types.rs:9:29
+   |
+LL |   fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
+   |                             ^^^^^^^
+
+error: only path types can be used in associated type constraints
+  --> $DIR/trait-path-types.rs:14:29
+   |
+LL |   fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
+   |                             ^^^^^^^
+
+error: only types can be used in associated type constraints
+  --> $DIR/trait-path-types.rs:19:30
+   |
+LL |   fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
+   |                              ^^
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/trait-path-types.rs:1:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs
new file mode 100644
index 00000000000..02d53d5faee
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.rs
@@ -0,0 +1,17 @@
+#![feature(generic_associated_types)]
+
+trait X {
+    type Y<'a>;
+}
+
+const _: () = {
+  fn f1<'a>(arg : Box<dyn X<Y<'a> = &'a ()>>) {}
+      //~^  ERROR: generic associated types in trait paths are currently not implemented
+};
+
+const _: () = {
+  fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}
+      //~^  ERROR: lifetime in trait object type must be followed by `+`
+};
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr
new file mode 100644
index 00000000000..1fba9cebd24
--- /dev/null
+++ b/src/test/ui/generic-associated-types/parse/trait-path-unimplemented.stderr
@@ -0,0 +1,14 @@
+error: lifetime in trait object type must be followed by `+`
+  --> $DIR/trait-path-unimplemented.rs:13:31
+   |
+LL |   fn f1<'a>(arg : Box<dyn X<Y('a) = &'a ()>>) {}
+   |                               ^^
+
+error: generic associated types in trait paths are currently not implemented
+  --> $DIR/trait-path-unimplemented.rs:8:30
+   |
+LL |   fn f1<'a>(arg : Box<dyn X<Y<'a> = &'a ()>>) {}
+   |                              ^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issues/issue-20616-2.rs b/src/test/ui/issues/issue-20616-2.rs
index 2f2c6903a9f..f108ae5de14 100644
--- a/src/test/ui/issues/issue-20616-2.rs
+++ b/src/test/ui/issues/issue-20616-2.rs
@@ -9,7 +9,7 @@ type Type_1_<'a, T> = &'a T;
 //type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
 
 
-type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(`
+type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,`, `:`, `=`, or `>`, found `(`
 
 
 //type Type_3<T> = Box<T,,>; // error: expected type, found `,`
diff --git a/src/test/ui/issues/issue-20616-2.stderr b/src/test/ui/issues/issue-20616-2.stderr
index 50ec7a304c5..01e3d3dd7cc 100644
--- a/src/test/ui/issues/issue-20616-2.stderr
+++ b/src/test/ui/issues/issue-20616-2.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,` or `>`, found `(`
+error: expected one of `,`, `:`, `=`, or `>`, found `(`
   --> $DIR/issue-20616-2.rs:12:31
    |
 LL | type Type_2 = Type_1_<'static ()>;
-   |                               ^ expected one of `,` or `>`
+   |                               ^ expected one of `,`, `:`, `=`, or `>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20616-3.rs b/src/test/ui/issues/issue-20616-3.rs
index 9bfd5bf2313..780038c11b8 100644
--- a/src/test/ui/issues/issue-20616-3.rs
+++ b/src/test/ui/issues/issue-20616-3.rs
@@ -11,7 +11,7 @@ type Type_1_<'a, T> = &'a T;
 
 
 type Type_3<T> = Box<T,,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
 
 
 //type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
diff --git a/src/test/ui/issues/issue-20616-3.stderr b/src/test/ui/issues/issue-20616-3.stderr
index cc4d79484e7..2f8cf8a79ed 100644
--- a/src/test/ui/issues/issue-20616-3.stderr
+++ b/src/test/ui/issues/issue-20616-3.stderr
@@ -1,8 +1,8 @@
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
   --> $DIR/issue-20616-3.rs:13:24
    |
 LL | type Type_3<T> = Box<T,,>;
-   |                        ^ expected one of `>`, const, identifier, lifetime, or type
+   |                        ^ expected one of `>`, const, lifetime, or type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20616-4.rs b/src/test/ui/issues/issue-20616-4.rs
index e9a34a04667..85aa9c1146d 100644
--- a/src/test/ui/issues/issue-20616-4.rs
+++ b/src/test/ui/issues/issue-20616-4.rs
@@ -14,7 +14,7 @@ type Type_1_<'a, T> = &'a T;
 
 
 type Type_4<T> = Type_1_<'static,, T>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
 
 
 type Type_5_<'a> = Type_1_<'a, ()>;
diff --git a/src/test/ui/issues/issue-20616-4.stderr b/src/test/ui/issues/issue-20616-4.stderr
index 254e4d6a34d..3be6c2e78ce 100644
--- a/src/test/ui/issues/issue-20616-4.stderr
+++ b/src/test/ui/issues/issue-20616-4.stderr
@@ -1,8 +1,8 @@
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
   --> $DIR/issue-20616-4.rs:16:34
    |
 LL | type Type_4<T> = Type_1_<'static,, T>;
-   |                                  ^ expected one of `>`, const, identifier, lifetime, or type
+   |                                  ^ expected one of `>`, const, lifetime, or type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20616-5.rs b/src/test/ui/issues/issue-20616-5.rs
index 23862516d2c..c0c6bc6dd97 100644
--- a/src/test/ui/issues/issue-20616-5.rs
+++ b/src/test/ui/issues/issue-20616-5.rs
@@ -20,7 +20,7 @@ type Type_5_<'a> = Type_1_<'a, ()>;
 
 
 type Type_5<'a> = Type_1_<'a, (),,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
 
 
 //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
diff --git a/src/test/ui/issues/issue-20616-5.stderr b/src/test/ui/issues/issue-20616-5.stderr
index aee8bf01a43..b90fbf60051 100644
--- a/src/test/ui/issues/issue-20616-5.stderr
+++ b/src/test/ui/issues/issue-20616-5.stderr
@@ -1,8 +1,8 @@
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
   --> $DIR/issue-20616-5.rs:22:34
    |
 LL | type Type_5<'a> = Type_1_<'a, (),,>;
-   |                                  ^ expected one of `>`, const, identifier, lifetime, or type
+   |                                  ^ expected one of `>`, const, lifetime, or type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20616-6.rs b/src/test/ui/issues/issue-20616-6.rs
index dc327f3f788..73c75bdc45f 100644
--- a/src/test/ui/issues/issue-20616-6.rs
+++ b/src/test/ui/issues/issue-20616-6.rs
@@ -23,7 +23,7 @@ type Type_5_<'a> = Type_1_<'a, ()>;
 
 
 type Type_6 = Type_5_<'a,,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
 
 
 //type Type_7 = Box<(),,>; // error: expected type, found `,`
diff --git a/src/test/ui/issues/issue-20616-6.stderr b/src/test/ui/issues/issue-20616-6.stderr
index 7192a87bc18..ea1c15ba423 100644
--- a/src/test/ui/issues/issue-20616-6.stderr
+++ b/src/test/ui/issues/issue-20616-6.stderr
@@ -1,8 +1,8 @@
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
   --> $DIR/issue-20616-6.rs:25:26
    |
 LL | type Type_6 = Type_5_<'a,,>;
-   |                          ^ expected one of `>`, const, identifier, lifetime, or type
+   |                          ^ expected one of `>`, const, lifetime, or type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20616-7.rs b/src/test/ui/issues/issue-20616-7.rs
index ffd1620c1d3..8beeebd7a95 100644
--- a/src/test/ui/issues/issue-20616-7.rs
+++ b/src/test/ui/issues/issue-20616-7.rs
@@ -26,7 +26,7 @@ type Type_5_<'a> = Type_1_<'a, ()>;
 
 
 type Type_7 = Box<(),,>;
-//~^ error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+//~^ error: expected one of `>`, const, lifetime, or type, found `,`
 
 
 //type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
diff --git a/src/test/ui/issues/issue-20616-7.stderr b/src/test/ui/issues/issue-20616-7.stderr
index 123dc1e2b7d..dcd199902fc 100644
--- a/src/test/ui/issues/issue-20616-7.stderr
+++ b/src/test/ui/issues/issue-20616-7.stderr
@@ -1,8 +1,8 @@
-error: expected one of `>`, const, identifier, lifetime, or type, found `,`
+error: expected one of `>`, const, lifetime, or type, found `,`
   --> $DIR/issue-20616-7.rs:28:22
    |
 LL | type Type_7 = Box<(),,>;
-   |                      ^ expected one of `>`, const, identifier, lifetime, or type
+   |                      ^ expected one of `>`, const, lifetime, or type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs
index bf2d091a01e..b45c00f6943 100644
--- a/src/test/ui/issues/issue-34334.rs
+++ b/src/test/ui/issues/issue-34334.rs
@@ -1,6 +1,6 @@
 fn main () {
     let sr: Vec<(u32, _, _) = vec![];
-    //~^ ERROR expected one of `,` or `>`, found `=`
+    //~^ ERROR only path types can be used in associated type constraints
     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
     //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built
 }
diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr
index c10a4144305..a9b9bf06d7f 100644
--- a/src/test/ui/issues/issue-34334.stderr
+++ b/src/test/ui/issues/issue-34334.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,` or `>`, found `=`
-  --> $DIR/issue-34334.rs:2:29
+error: only path types can be used in associated type constraints
+  --> $DIR/issue-34334.rs:2:17
    |
 LL |     let sr: Vec<(u32, _, _) = vec![];
-   |         --                  ^ expected one of `,` or `>`
+   |         --      ^^^^^^^^^^^
    |         |
    |         while parsing the type for `sr`
 
diff --git a/src/test/ui/parser/issue-62660.rs b/src/test/ui/parser/issue-62660.rs
index 33c8a9fa328..4f866b78976 100644
--- a/src/test/ui/parser/issue-62660.rs
+++ b/src/test/ui/parser/issue-62660.rs
@@ -5,7 +5,7 @@ struct Foo;
 
 impl Foo {
     pub fn foo(_: i32, self: Box<Self) {}
-    //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
+    //~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)`
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/issue-62660.stderr b/src/test/ui/parser/issue-62660.stderr
index 0844da1bd92..a50ada9056b 100644
--- a/src/test/ui/parser/issue-62660.stderr
+++ b/src/test/ui/parser/issue-62660.stderr
@@ -1,8 +1,8 @@
-error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
+error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `)`
   --> $DIR/issue-62660.rs:7:38
    |
 LL |     pub fn foo(_: i32, self: Box<Self) {}
-   |                                      ^ expected one of 7 possible tokens
+   |                                      ^ expected one of 9 possible tokens
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-63116.stderr b/src/test/ui/parser/issue-63116.stderr
index 80a450dbd36..e249a93df92 100644
--- a/src/test/ui/parser/issue-63116.stderr
+++ b/src/test/ui/parser/issue-63116.stderr
@@ -12,7 +12,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
 LL | impl W <s(f;Y(;]
    |            ^ expected one of 7 possible tokens
 
-error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
+error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `:`, `<`, `=`, `>`, `?`, `[`, `_`, `async`, `const`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
   --> $DIR/issue-63116.rs:3:15
    |
 LL | impl W <s(f;Y(;]
diff --git a/src/test/ui/parser/lifetime-semicolon.rs b/src/test/ui/parser/lifetime-semicolon.rs
index 1f147216ea6..7cc14971f63 100644
--- a/src/test/ui/parser/lifetime-semicolon.rs
+++ b/src/test/ui/parser/lifetime-semicolon.rs
@@ -3,6 +3,6 @@ struct Foo<'a, 'b> {
 }
 
 fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
-//~^ ERROR expected one of `,` or `>`, found `;`
+//~^ ERROR expected one of `,`, `:`, `=`, or `>`, found `;`
 
 fn main() {}
diff --git a/src/test/ui/parser/lifetime-semicolon.stderr b/src/test/ui/parser/lifetime-semicolon.stderr
index 4641c286cb8..3b67705aae9 100644
--- a/src/test/ui/parser/lifetime-semicolon.stderr
+++ b/src/test/ui/parser/lifetime-semicolon.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,` or `>`, found `;`
+error: expected one of `,`, `:`, `=`, or `>`, found `;`
   --> $DIR/lifetime-semicolon.rs:5:30
    |
 LL | fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {}
-   |                              ^ expected one of `,` or `>`
+   |                              ^ expected one of `,`, `:`, `=`, or `>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.rs b/src/test/ui/parser/removed-syntax-closure-lifetime.rs
index ceac9408006..e807a179473 100644
--- a/src/test/ui/parser/removed-syntax-closure-lifetime.rs
+++ b/src/test/ui/parser/removed-syntax-closure-lifetime.rs
@@ -1,2 +1,2 @@
 type closure = Box<lt/fn()>;
-//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/`
+//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/`
diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr
index a100f689fb8..63b6e138ce5 100644
--- a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr
+++ b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr
@@ -1,8 +1,8 @@
-error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/`
+error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, `=`, or `>`, found `/`
   --> $DIR/removed-syntax-closure-lifetime.rs:1:22
    |
 LL | type closure = Box<lt/fn()>;
-   |                      ^ expected one of 7 possible tokens
+   |                      ^ expected one of 9 possible tokens
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/proc-macro/auxiliary/issue-79242.rs b/src/test/ui/proc-macro/auxiliary/issue-79242.rs
new file mode 100644
index 00000000000..e586980f0ad
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-79242.rs
@@ -0,0 +1,16 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn dummy(input: TokenStream) -> TokenStream {
+    // Iterate to force internal conversion of nonterminals
+    // to `proc_macro` structs
+    for _ in input {}
+    TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs b/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs
new file mode 100644
index 00000000000..b68f19c5dd2
--- /dev/null
+++ b/src/test/ui/proc-macro/issue-79242-slow-retokenize-check.rs
@@ -0,0 +1,34 @@
+// check-pass
+// aux-build:issue-79242.rs
+
+// Regression test for issue #79242
+// Tests that compilation time doesn't blow up for a proc-macro
+// invocation with deeply nested nonterminals
+
+#![allow(unused)]
+
+extern crate issue_79242;
+
+macro_rules! declare_nats {
+    ($prev:ty) => {};
+    ($prev:ty, $n:literal$(, $tail:literal)*) => {
+
+        issue_79242::dummy! {
+            $prev
+        }
+
+        declare_nats!(Option<$prev>$(, $tail)*);
+    };
+    (0, $($n:literal),+) => {
+        pub struct N0;
+        declare_nats!(N0, $($n),+);
+    };
+}
+
+declare_nats! {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28
+}
+
+
+fn main() {}