about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--RELEASES.md5
-rw-r--r--compiler/rustc_ast_pretty/src/pp/convenience.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs48
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0192.md6
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs6
-rw-r--r--src/test/pretty/use-tree.rs23
-rw-r--r--src/test/ui/associated-types/issue-91069.rs24
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-80626.rs17
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-80626.stderr20
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-86218.rs27
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-86218.stderr15
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87735.rs45
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87735.stderr9
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87748.rs22
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87748.stderr20
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87755.rs21
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87755.stderr9
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87803.rs26
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87803.stderr12
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-88382.rs31
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-88382.stderr20
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-88460.rs31
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-88460.stderr18
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-88526.rs34
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-88526.stderr9
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-89008.rs43
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-89008.stderr21
-rw-r--r--src/test/ui/generic-associated-types/issue-91139.rs22
-rw-r--r--src/test/ui/parser/issues/issue-93282.rs11
-rw-r--r--src/test/ui/parser/issues/issue-93282.stderr14
-rw-r--r--src/test/ui/parser/require-parens-for-chained-comparison.rs2
-rw-r--r--src/test/ui/parser/require-parens-for-chained-comparison.stderr18
-rw-r--r--src/tools/linkchecker/main.rs5
-rw-r--r--src/tools/tidy/src/error_codes_check.rs33
36 files changed, 644 insertions, 31 deletions
diff --git a/RELEASES.md b/RELEASES.md
index aae2a669650..a9422fa103e 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -156,6 +156,7 @@ Language
 - [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220]
 - [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690]
 - [Allow panicking in constant evaluation.][89508]
+- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200]
 
 Compiler
 --------
@@ -216,6 +217,9 @@ Cargo
 Compatibility notes
 -------------------
 
+- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200]
+  This will break some builds that set `#![deny(dead_code)]`.
+
 Internal changes
 ----------------
 These changes provide no direct user facing benefits, but represent significant
@@ -224,6 +228,7 @@ and related tools.
 
 - [Added an experimental backend for codegen with `libgccjit`.][87260]
 
+[85200]: https://github.com/rust-lang/rust/pull/85200/
 [86191]: https://github.com/rust-lang/rust/pull/86191/
 [87220]: https://github.com/rust-lang/rust/pull/87220/
 [87260]: https://github.com/rust-lang/rust/pull/87260/
diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs
index 785e6886d8a..93310dd45c5 100644
--- a/compiler/rustc_ast_pretty/src/pp/convenience.rs
+++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs
@@ -75,6 +75,10 @@ impl Printer {
     }
 
     pub fn trailing_comma(&mut self) {
+        self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
+    }
+
+    pub fn trailing_comma_or_space(&mut self) {
         self.scan_break(BreakToken {
             blank_space: 1,
             pre_break: Some(','),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 44116fa76a0..6435f1b6141 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -142,7 +142,7 @@ impl<'a> State<'a> {
             if !field.is_last || has_rest {
                 self.word_space(",");
             } else {
-                self.trailing_comma();
+                self.trailing_comma_or_space();
             }
         }
         if has_rest {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index dac84ae9d5f..d7e9ef0e50d 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -1,5 +1,6 @@
 use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::{AnnNode, PrintState, State};
+use crate::pprust::state::delimited::IterDelimited;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
 
 use rustc_ast as ast;
 use rustc_ast::GenericBound;
@@ -138,11 +139,10 @@ impl<'a> State<'a> {
                 self.end(); // end outer head-block
             }
             ast::ItemKind::Use(ref tree) => {
-                self.head(visibility_qualified(&item.vis, "use"));
+                self.print_visibility(&item.vis);
+                self.word_nbsp("use");
                 self.print_use_tree(tree);
                 self.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
             }
             ast::ItemKind::Static(ref ty, mutbl, ref body) => {
                 let def = ast::Defaultness::Final;
@@ -615,8 +615,8 @@ impl<'a> State<'a> {
             ast::UseTreeKind::Simple(rename, ..) => {
                 self.print_path(&tree.prefix, false, 0);
                 if let Some(rename) = rename {
-                    self.space();
-                    self.word_space("as");
+                    self.nbsp();
+                    self.word_nbsp("as");
                     self.print_ident(rename);
                 }
             }
@@ -628,16 +628,36 @@ impl<'a> State<'a> {
                 self.word("*");
             }
             ast::UseTreeKind::Nested(ref items) => {
-                if tree.prefix.segments.is_empty() {
-                    self.word("{");
-                } else {
+                if !tree.prefix.segments.is_empty() {
                     self.print_path(&tree.prefix, false, 0);
-                    self.word("::{");
+                    self.word("::");
+                }
+                if items.is_empty() {
+                    self.word("{}");
+                } else if items.len() == 1 {
+                    self.print_use_tree(&items[0].0);
+                } else {
+                    self.cbox(INDENT_UNIT);
+                    self.word("{");
+                    self.zerobreak();
+                    self.ibox(0);
+                    for use_tree in items.iter().delimited() {
+                        self.print_use_tree(&use_tree.0);
+                        if !use_tree.is_last {
+                            self.word(",");
+                            if let ast::UseTreeKind::Nested(_) = use_tree.0.kind {
+                                self.hardbreak();
+                            } else {
+                                self.space();
+                            }
+                        }
+                    }
+                    self.end();
+                    self.trailing_comma();
+                    self.offset(-INDENT_UNIT);
+                    self.word("}");
+                    self.end();
                 }
-                self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
-                    this.print_use_tree(tree)
-                });
-                self.word("}");
             }
         }
     }
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index c401f65edda..a72681dbf4e 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -97,6 +97,7 @@ E0184: include_str!("./error_codes/E0184.md"),
 E0185: include_str!("./error_codes/E0185.md"),
 E0186: include_str!("./error_codes/E0186.md"),
 E0191: include_str!("./error_codes/E0191.md"),
+E0192: include_str!("./error_codes/E0192.md"),
 E0193: include_str!("./error_codes/E0193.md"),
 E0195: include_str!("./error_codes/E0195.md"),
 E0197: include_str!("./error_codes/E0197.md"),
@@ -522,7 +523,6 @@ E0787: include_str!("./error_codes/E0787.md"),
 //  E0188, // can not cast an immutable reference to a mutable pointer
 //  E0189, // deprecated: can only cast a boxed pointer to a boxed object
 //  E0190, // deprecated: can only cast a &-pointer to an &-object
-//  E0192, // negative impl only applicable to auto traits
 //  E0194, // merged into E0403
 //  E0196, // cannot determine a type for this closure
     E0208,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0192.md b/compiler/rustc_error_codes/src/error_codes/E0192.md
index 5fd951b2e86..deca042a91a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0192.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0192.md
@@ -1,15 +1,17 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A negative impl was added on a trait implementation.
 
 Erroneous code example:
 
-```compile_fail,E0192
+```compile_fail
 trait Trait {
     type Bar;
 }
 
 struct Foo;
 
-impl !Trait for Foo { } //~ ERROR E0192
+impl !Trait for Foo { } //~ ERROR
 
 fn main() {}
 ```
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 4898a4844b9..e9aa4adcaf7 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1457,9 +1457,9 @@ impl<'a> Parser<'a> {
         } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
             self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
         } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
-            // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the
-            // "must be followed by a colon" error, and the "expected one of" error.
-            self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly");
+            // We're probably inside of a `Path<'a>` that needs a turbofish
+            let msg = "expected `while`, `for`, `loop` or `{` after a label";
+            self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
             consume_colon = false;
             Ok(self.mk_expr_err(lo))
         } else {
diff --git a/src/test/pretty/use-tree.rs b/src/test/pretty/use-tree.rs
new file mode 100644
index 00000000000..5da95235245
--- /dev/null
+++ b/src/test/pretty/use-tree.rs
@@ -0,0 +1,23 @@
+// pp-exact
+// edition:2021
+
+#![allow(unused_imports)]
+
+use ::std::fmt::{self, Debug, Display, Write as _};
+
+use core::option::Option::*;
+
+use core::{
+    cmp::{Eq, Ord, PartialEq, PartialOrd},
+    convert::{AsMut, AsRef, From, Into},
+    iter::{
+        DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator,
+        IntoIterator, Iterator,
+    },
+    marker::{
+        Copy as Copy, Send as Send, Sized as Sized, Sync as Sync, Unpin as U,
+    },
+    ops::{*, Drop, Fn, FnMut, FnOnce},
+};
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-91069.rs b/src/test/ui/associated-types/issue-91069.rs
new file mode 100644
index 00000000000..109c2eed27a
--- /dev/null
+++ b/src/test/ui/associated-types/issue-91069.rs
@@ -0,0 +1,24 @@
+// check-pass
+
+pub trait Associate {
+    type Associated;
+}
+
+pub struct Wrap<'a> {
+    pub field: &'a i32,
+}
+
+pub trait Create<T> {
+    fn create() -> Self;
+}
+
+pub fn oh_no<'a, T>()
+where
+    Wrap<'a>: Associate,
+    <Wrap<'a> as Associate>::Associated: Create<T>,
+{
+    <Wrap<'a> as Associate>::Associated::create();
+}
+
+
+pub fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.rs b/src/test/ui/generic-associated-types/bugs/issue-80626.rs
new file mode 100644
index 00000000000..aea8aaf4bb3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-80626.rs
@@ -0,0 +1,17 @@
+// check-fail
+
+// This should pass, but it requires `Sized` to be coinductive.
+
+#![feature(generic_associated_types)]
+
+trait Allocator {
+    type Allocated<T>;
+}
+
+enum LinkedList<A: Allocator> {
+    Head,
+    Next(A::Allocated<Self>)
+    //~^ overflow
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr
new file mode 100644
index 00000000000..e18af9c257f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr
@@ -0,0 +1,20 @@
+error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized`
+  --> $DIR/issue-80626.rs:13:10
+   |
+LL |     Next(A::Allocated<Self>)
+   |          ^^^^^^^^^^^^^^^^^^
+   |
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     Next(&A::Allocated<Self>)
+   |          +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     Next(Box<A::Allocated<Self>>)
+   |          ++++                  +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/bugs/issue-86218.rs
new file mode 100644
index 00000000000..3f8776a3637
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-86218.rs
@@ -0,0 +1,27 @@
+// check-fail
+
+// This should pass, but seems to run into a TAIT issue.
+
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+pub trait Stream {
+    type Item;
+}
+
+impl Stream for () {
+    type Item = i32;
+}
+
+trait Yay<AdditionalValue> {
+    type InnerStream<'s>: Stream<Item = i32> + 's;
+    fn foo<'s>() -> Self::InnerStream<'s>;
+}
+
+impl<'a> Yay<&'a ()> for () {
+    type InnerStream<'s> = impl Stream<Item = i32> + 's;
+    //~^ the type
+    fn foo<'s>() -> Self::InnerStream<'s> { todo!() }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
new file mode 100644
index 00000000000..9f4efc0addb
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
@@ -0,0 +1,15 @@
+error[E0477]: the type `impl Stream<Item = i32>` does not fulfill the required lifetime
+  --> $DIR/issue-86218.rs:22:28
+   |
+LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must outlive the lifetime `'s` as defined here as required by this binding
+  --> $DIR/issue-86218.rs:22:22
+   |
+LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
+   |                      ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs
new file mode 100644
index 00000000000..5f7a42a740d
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87735.rs
@@ -0,0 +1,45 @@
+// check-fail
+
+// This should pass, but we need an extension of implied bounds (probably).
+
+#![feature(generic_associated_types)]
+
+pub trait AsRef2 {
+  type Output<'a> where Self: 'a;
+
+  fn as_ref2<'a>(&'a self) -> Self::Output<'a>;
+}
+
+impl<T> AsRef2 for Vec<T> {
+  type Output<'a> where Self: 'a = &'a [T];
+
+  fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
+    &self[..]
+  }
+}
+
+#[derive(Debug)]
+struct Foo<T>(T);
+#[derive(Debug)]
+struct FooRef<'a, U>(&'a [U]);
+
+impl<'b, T, U> AsRef2 for Foo<T> //~ the type parameter
+where
+    // * `for<'b, 'c> T: AsRef2<Output<'b> = &'c [U]>>` does not work
+    //
+    // * `U` is unconstrained but should be allowed in this context because `Output` is
+    // an associated type
+    T: AsRef2<Output<'b> = &'b [U]>,
+    U: 'b
+{
+  type Output<'a> where Self: 'a = FooRef<'a, U>;
+
+  fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
+    FooRef(self.0.as_ref2())
+  }
+}
+
+fn main() {
+    let foo = Foo(vec![1, 2, 3]);
+    dbg!(foo.as_ref2());
+}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.stderr b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr
new file mode 100644
index 00000000000..31b3a9619b6
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-87735.rs:26:13
+   |
+LL | impl<'b, T, U> AsRef2 for Foo<T>
+   |             ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs
new file mode 100644
index 00000000000..4dbaf429ead
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87748.rs
@@ -0,0 +1,22 @@
+// check-fail
+
+// This should pass, but unnormalized input args aren't treated as implied.
+
+#![feature(generic_associated_types)]
+
+trait MyTrait {
+    type Assoc<'a, 'b> where 'b: 'a;
+    fn do_sth(arg: Self::Assoc<'_, '_>);
+}
+
+struct Foo;
+
+impl MyTrait for Foo {
+    type Assoc<'a, 'b> where 'b: 'a = u32;
+
+    fn do_sth(_: u32) {} //~ lifetime bound
+    // fn do_sth(_: Self::Assoc<'static, 'static>) {}
+    // fn do_sth(_: Self::Assoc<'_, '_>) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
new file mode 100644
index 00000000000..c38d4478592
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
@@ -0,0 +1,20 @@
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/issue-87748.rs:17:5
+   |
+LL |     fn do_sth(_: u32) {}
+   |     ^^^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the anonymous lifetime #2 defined here
+  --> $DIR/issue-87748.rs:17:5
+   |
+LL |     fn do_sth(_: u32) {}
+   |     ^^^^^^^^^^^^^^^^^
+note: but lifetime parameter must outlive the anonymous lifetime #1 defined here
+  --> $DIR/issue-87748.rs:17:5
+   |
+LL |     fn do_sth(_: u32) {}
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0478`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.rs b/src/test/ui/generic-associated-types/bugs/issue-87755.rs
new file mode 100644
index 00000000000..1cd3534ba77
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87755.rs
@@ -0,0 +1,21 @@
+// check-fail
+
+// This should pass.
+
+#![feature(generic_associated_types)]
+
+use std::fmt::Debug;
+
+trait Foo {
+    type Ass where Self::Ass: Debug;
+}
+
+#[derive(Debug)]
+struct Bar;
+
+impl Foo for Bar {
+    type Ass = Bar;
+    //~^ overflow
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.stderr b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr
new file mode 100644
index 00000000000..d2dc991a2b6
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr
@@ -0,0 +1,9 @@
+error[E0275]: overflow evaluating the requirement `<Bar as Foo>::Ass == _`
+  --> $DIR/issue-87755.rs:17:16
+   |
+LL |     type Ass = Bar;
+   |                ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.rs b/src/test/ui/generic-associated-types/bugs/issue-87803.rs
new file mode 100644
index 00000000000..3d2ff38ab04
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87803.rs
@@ -0,0 +1,26 @@
+// check-fail
+
+// This should pass, but using a type alias vs a reference directly
+// changes late-bound -> early-bound.
+
+#![feature(generic_associated_types)]
+
+trait Scanner {
+    type Input<'a>;
+    type Token<'a>;
+
+    fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>;
+}
+
+struct IdScanner();
+
+impl Scanner for IdScanner {
+    type Input<'a> = &'a str;
+    type Token<'a> = &'a str;
+
+    fn scan<'a>(&mut self, s : &'a str) -> &'a str { //~ lifetime parameters
+        s
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.stderr b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr
new file mode 100644
index 00000000000..759c0440d07
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr
@@ -0,0 +1,12 @@
+error[E0195]: lifetime parameters or bounds on method `scan` do not match the trait declaration
+  --> $DIR/issue-87803.rs:21:12
+   |
+LL |     fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>;
+   |            ---- lifetimes in impl do not match this method in trait
+...
+LL |     fn scan<'a>(&mut self, s : &'a str) -> &'a str {
+   |            ^^^^ lifetimes do not match method in trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0195`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.rs b/src/test/ui/generic-associated-types/bugs/issue-88382.rs
new file mode 100644
index 00000000000..f4633ca5169
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-88382.rs
@@ -0,0 +1,31 @@
+// check-fail
+
+// This should pass, but has a missed normalization due to HRTB.
+
+#![feature(generic_associated_types)]
+
+trait Iterable {
+    type Iterator<'a> where Self: 'a;
+    fn iter(&self) -> Self::Iterator<'_>;
+}
+
+struct SomeImplementation();
+
+impl Iterable for SomeImplementation {
+    type Iterator<'a> = std::iter::Empty<usize>;
+    fn iter(&self) -> Self::Iterator<'_> {
+        std::iter::empty()
+    }
+}
+
+fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
+    f(&mut i.iter());
+}
+
+fn main() {
+    do_something(SomeImplementation(), |_| ());
+    do_something(SomeImplementation(), test);
+    //~^ type mismatch
+}
+
+fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr
new file mode 100644
index 00000000000..05bc58cbba4
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr
@@ -0,0 +1,20 @@
+error[E0631]: type mismatch in function arguments
+  --> $DIR/issue-88382.rs:27:40
+   |
+LL |     do_something(SomeImplementation(), test);
+   |     ------------                       ^^^^ expected signature of `for<'a> fn(&mut <SomeImplementation as Iterable>::Iterator<'a>) -> _`
+   |     |
+   |     required by a bound introduced by this call
+...
+LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
+   | ------------------------------------------------- found signature of `for<'r> fn(&'r mut std::iter::Empty<usize>) -> _`
+   |
+note: required by a bound in `do_something`
+  --> $DIR/issue-88382.rs:21:56
+   |
+LL | fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.rs b/src/test/ui/generic-associated-types/bugs/issue-88460.rs
new file mode 100644
index 00000000000..7e62790cc50
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-88460.rs
@@ -0,0 +1,31 @@
+// check-fail
+
+// This should pass, but has a missed normalization due to HRTB.
+
+#![feature(generic_associated_types)]
+
+pub trait Marker {}
+
+pub trait Trait {
+    type Assoc<'a>;
+}
+
+fn test<T>(value: T)
+where
+    T: Trait,
+    for<'a> T::Assoc<'a>: Marker,
+{
+}
+
+impl Marker for () {}
+
+struct Foo;
+
+impl Trait for Foo {
+    type Assoc<'a> = ();
+}
+
+fn main() {
+    test(Foo);
+    //~^ the trait bound
+}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.stderr b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr
new file mode 100644
index 00000000000..604658da7d2
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied
+  --> $DIR/issue-88460.rs:29:5
+   |
+LL |     test(Foo);
+   |     ^^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>`
+   |
+note: required by a bound in `test`
+  --> $DIR/issue-88460.rs:16:27
+   |
+LL | fn test<T>(value: T)
+   |    ---- required by a bound in this
+...
+LL |     for<'a> T::Assoc<'a>: Marker,
+   |                           ^^^^^^ required by this bound in `test`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.rs b/src/test/ui/generic-associated-types/bugs/issue-88526.rs
new file mode 100644
index 00000000000..90568fcb401
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-88526.rs
@@ -0,0 +1,34 @@
+// check-fail
+
+// This should pass, but requires more logic.
+
+#![feature(generic_associated_types)]
+
+trait A {
+    type I<'a>;
+}
+
+pub struct TestA<F>
+{
+    f: F,
+}
+
+impl<F> A for TestA<F> {
+    type I<'a> = &'a F;
+}
+
+struct TestB<Q, F>
+{
+    q: Q,
+    f: F,
+}
+
+impl<'q, Q, I, F> A for TestB<Q, F> //~ the type parameter
+where
+    Q: A<I<'q> = &'q I>,
+    F: Fn(I),
+{
+    type I<'a> = ();
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.stderr b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr
new file mode 100644
index 00000000000..ccc5ae0b621
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-88526.rs:26:13
+   |
+LL | impl<'q, Q, I, F> A for TestB<Q, F>
+   |             ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.rs b/src/test/ui/generic-associated-types/bugs/issue-89008.rs
new file mode 100644
index 00000000000..5d850849fd2
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-89008.rs
@@ -0,0 +1,43 @@
+// check-fail
+// edition:2021
+
+// This should pass, but seems to run into a TAIT bug.
+
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+use std::future::Future;
+
+trait Stream {
+    type Item;
+}
+
+struct Empty<T>(T);
+impl<T> Stream for Empty<T> {
+    type Item = ();
+}
+fn empty<T>() -> Empty<T> {
+    todo!()
+}
+
+trait X {
+    type LineStream<'a, Repr>: Stream<Item = Repr> where Self: 'a;
+
+    type LineStreamFut<'a,Repr>: Future<Output = Self::LineStream<'a, Repr>> where Self: 'a;
+
+    fn line_stream<'a,Repr>(&'a self) -> Self::LineStreamFut<'a,Repr>;
+}
+
+struct Y;
+
+impl X for Y {
+    type LineStream<'a, Repr> = impl Stream<Item = Repr>; //~ could not find
+
+    type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>> ;
+
+    fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { //~ type mismatch
+        async {empty()}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
new file mode 100644
index 00000000000..48745fe0fbd
--- /dev/null
+++ b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
@@ -0,0 +1,21 @@
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == impl Stream<Item = Repr>`
+  --> $DIR/issue-89008.rs:38:43
+   |
+LL |     type LineStream<'a, Repr> = impl Stream<Item = Repr>;
+   |                                 ------------------------ the expected opaque type
+...
+LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found struct `Empty`
+   |
+   = note: expected opaque type `impl Stream<Item = Repr>`
+                   found struct `Empty<_>`
+
+error: could not find defining uses
+  --> $DIR/issue-89008.rs:34:33
+   |
+LL |     type LineStream<'a, Repr> = impl Stream<Item = Repr>;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs
new file mode 100644
index 00000000000..2b82d2946b3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-91139.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Foo<T> {
+    type Type<'a>
+    where
+        T: 'a;
+}
+
+impl<T> Foo<T> for () {
+    type Type<'a>
+    where
+        T: 'a,
+    = ();
+}
+
+fn foo<T>() {
+    let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+}
+
+pub fn main() {}
diff --git a/src/test/ui/parser/issues/issue-93282.rs b/src/test/ui/parser/issues/issue-93282.rs
index 7be8b25363e..261fcb5f918 100644
--- a/src/test/ui/parser/issues/issue-93282.rs
+++ b/src/test/ui/parser/issues/issue-93282.rs
@@ -1,4 +1,15 @@
 fn main() {
     f<'a,>
     //~^ ERROR expected
+    //~| ERROR expected
+}
+
+fn bar(a: usize, b: usize) -> usize {
+    a + b
+}
+
+fn foo() {
+    let x = 1;
+    bar('y, x);
+    //~^ ERROR expected
 }
diff --git a/src/test/ui/parser/issues/issue-93282.stderr b/src/test/ui/parser/issues/issue-93282.stderr
index 20e6c3ed8a8..900f21a7cce 100644
--- a/src/test/ui/parser/issues/issue-93282.stderr
+++ b/src/test/ui/parser/issues/issue-93282.stderr
@@ -1,3 +1,9 @@
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/issue-93282.rs:2:9
+   |
+LL |     f<'a,>
+   |         ^ expected `while`, `for`, `loop` or `{` after a label
+
 error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `{`, `}`, or an operator, found `,`
   --> $DIR/issue-93282.rs:2:9
    |
@@ -9,5 +15,11 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
 LL |     f::<'a,>
    |      ++
 
-error: aborting due to previous error
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/issue-93282.rs:13:11
+   |
+LL |     bar('y, x);
+   |           ^ expected `while`, `for`, `loop` or `{` after a label
+
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs
index 68636f6b907..f29fd7a5472 100644
--- a/src/test/ui/parser/require-parens-for-chained-comparison.rs
+++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs
@@ -22,10 +22,12 @@ fn main() {
     let _ = f<'_, i8>();
     //~^ ERROR expected one of
     //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+    //~| ERROR expected
 
     f<'_>();
     //~^ comparison operators cannot be chained
     //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+    //~| ERROR expected
 
     let _ = f<u8>;
     //~^ ERROR comparison operators cannot be chained
diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr
index cde6f8c674f..92d700753dc 100644
--- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr
+++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr
@@ -53,6 +53,12 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
 LL |     let _ = f::<u8, i8>();
    |              ++
 
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/require-parens-for-chained-comparison.rs:22:17
+   |
+LL |     let _ = f<'_, i8>();
+   |                 ^ expected `while`, `for`, `loop` or `{` after a label
+
 error: expected one of `.`, `:`, `;`, `?`, `else`, `for`, `loop`, `while`, `{`, or an operator, found `,`
   --> $DIR/require-parens-for-chained-comparison.rs:22:17
    |
@@ -64,8 +70,14 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
 LL |     let _ = f::<'_, i8>();
    |              ++
 
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/require-parens-for-chained-comparison.rs:27:9
+   |
+LL |     f<'_>();
+   |         ^ expected `while`, `for`, `loop` or `{` after a label
+
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:26:6
+  --> $DIR/require-parens-for-chained-comparison.rs:27:6
    |
 LL |     f<'_>();
    |      ^  ^
@@ -76,7 +88,7 @@ LL |     f::<'_>();
    |      ++
 
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:30:14
+  --> $DIR/require-parens-for-chained-comparison.rs:32:14
    |
 LL |     let _ = f<u8>;
    |              ^  ^
@@ -84,5 +96,5 @@ LL |     let _ = f<u8>;
    = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    = help: or use `(...)` if you meant to specify fn arguments
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 94e82e3d9f7..46daaf42883 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -182,8 +182,9 @@ impl Checker {
     fn walk(&mut self, dir: &Path, report: &mut Report) {
         for entry in t!(dir.read_dir()).map(|e| t!(e)) {
             let path = entry.path();
-            let kind = t!(entry.file_type());
-            if kind.is_dir() {
+            // Goes through symlinks
+            let metadata = t!(fs::metadata(&path));
+            if metadata.is_dir() {
                 self.walk(&path, report);
             } else {
                 self.check(&path, report);
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 8ea6bb308b7..2a23d72edc0 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -1,7 +1,7 @@
 //! Checks that all error codes have at least one test to prevent having error
 //! codes that are silently not thrown by the compiler anymore.
 
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::ffi::OsStr;
 use std::fs::read_to_string;
 use std::path::Path;
@@ -205,6 +205,7 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
     let mut found_explanations = 0;
     let mut found_tests = 0;
     let mut error_codes: HashMap<String, ErrorCodeStatus> = HashMap::new();
+    let mut explanations: HashSet<String> = HashSet::new();
     // We want error codes which match the following cases:
     //
     // * foo(a, E0111, a)
@@ -218,17 +219,27 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
     for path in paths {
         super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
             let file_name = entry.file_name();
+            let entry_path = entry.path();
+
             if file_name == "error_codes.rs" {
                 extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
                 found_explanations += 1;
-            } else if entry.path().extension() == Some(OsStr::new("stderr")) {
+            } else if entry_path.extension() == Some(OsStr::new("stderr")) {
                 extract_error_codes_from_tests(contents, &mut error_codes);
                 found_tests += 1;
-            } else if entry.path().extension() == Some(OsStr::new("rs")) {
+            } else if entry_path.extension() == Some(OsStr::new("rs")) {
                 let path = entry.path().to_string_lossy();
                 if PATHS_TO_IGNORE_FOR_EXTRACTION.iter().all(|c| !path.contains(c)) {
                     extract_error_codes_from_source(contents, &mut error_codes, &regex);
                 }
+            } else if entry_path
+                .parent()
+                .and_then(|p| p.file_name())
+                .map(|p| p == "error_codes")
+                .unwrap_or(false)
+                && entry_path.extension() == Some(OsStr::new("md"))
+            {
+                explanations.insert(file_name.to_str().unwrap().replace(".md", ""));
             }
         });
     }
@@ -240,6 +251,10 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
         eprintln!("No error code was found in compilation errors!");
         *bad = true;
     }
+    if explanations.is_empty() {
+        eprintln!("No error code explanation was found!");
+        *bad = true;
+    }
     if errors.is_empty() {
         println!("Found {} error codes", error_codes.len());
 
@@ -282,11 +297,21 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
             }
         }
     }
+    if errors.is_empty() {
+        for explanation in explanations {
+            if !error_codes.contains_key(&explanation) {
+                errors.push(format!(
+                    "{} error code explanation should be listed in `error_codes.rs`",
+                    explanation
+                ));
+            }
+        }
+    }
     errors.sort();
     for err in &errors {
         eprintln!("{}", err);
     }
-    println!("Found {} error codes with no tests", errors.len());
+    println!("Found {} error(s) in error codes", errors.len());
     if !errors.is_empty() {
         *bad = true;
     }