about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/clean/types.rs11
-rw-r--r--src/librustdoc/formats/cache.rs6
-rw-r--r--src/librustdoc/html/format.rs6
-rw-r--r--src/librustdoc/html/render/context.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/render/search_index.rs (renamed from src/librustdoc/html/render/cache.rs)72
-rw-r--r--src/librustdoc/json/mod.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs41
-rw-r--r--src/test/pretty/attr-fn-inner.rs4
-rw-r--r--src/test/pretty/attr-literals.rs4
-rw-r--r--src/test/pretty/attr-tokens-raw-ident.rs2
-rw-r--r--src/test/pretty/delimited-token-groups.rs2
-rw-r--r--src/test/pretty/doc-comments.rs10
-rw-r--r--src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs11
-rw-r--r--src/test/ui/error-codes/E0227.rs12
-rw-r--r--src/test/ui/error-codes/E0227.stderr9
-rw-r--r--src/test/ui/macros/stringify.rs4
-rw-r--r--src/test/ui/match/expr_before_ident_pat.rs15
-rw-r--r--src/test/ui/match/expr_before_ident_pat.stderr15
-rw-r--r--src/test/ui/match/issue-92100.rs7
-rw-r--r--src/test/ui/match/issue-92100.stderr9
-rw-r--r--src/test/ui/parser/type-alias-where.rs37
-rw-r--r--src/test/ui/parser/type-alias-where.stderr40
-rw-r--r--src/tools/tidy/src/error_codes_check.rs4
24 files changed, 249 insertions, 81 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d928b41cad4..2b1a1d4a600 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -39,7 +39,6 @@ use crate::clean::Clean;
 use crate::core::DocContext;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::html::render::cache::ExternalLocation;
 use crate::html::render::Context;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
@@ -339,6 +338,16 @@ impl ExternalCrate {
     }
 }
 
+/// Indicates where an external crate can be found.
+crate enum ExternalLocation {
+    /// Remote URL root of the external crate
+    Remote(String),
+    /// This external crate can be found in the local doc/ folder
+    Local,
+    /// The external crate could not be found.
+    Unknown,
+}
+
 /// Anything with a source location and set of attributes and, optionally, a
 /// name. That is, anything that can be documented. This doesn't correspond
 /// directly to the AST's concept of an item; it's a strict superset.
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 5813062ceab..6b9ccd37cfb 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -6,13 +6,13 @@ use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
-use crate::clean::{self, ExternalCrate, ItemId, PrimitiveType};
+use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
 use crate::html::markdown::short_markdown_summary;
-use crate::html::render::cache::{get_index_search_type, ExternalLocation};
+use crate::html::render::search_index::get_function_type_for_search;
 use crate::html::render::IndexItem;
 
 /// This cache is used to store information about the [`clean::Crate`] being
@@ -303,7 +303,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                             desc,
                             parent,
                             parent_idx: None,
-                            search_type: get_index_search_type(&item, self.tcx, self.cache),
+                            search_type: get_function_type_for_search(&item, self.tcx),
                             aliases: item.attrs.get_doc_aliases(),
                         });
                     }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e4c612aaab9..3a7c7186877 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -21,10 +21,12 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_target::spec::abi::Abi;
 
-use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType};
+use crate::clean::{
+    self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, ItemId,
+    PrimitiveType,
+};
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
-use crate::html::render::cache::ExternalLocation;
 use crate::html::render::Context;
 
 use super::url_parts_builder::UrlPartsBuilder;
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 45a436c4487..534a542d58e 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -13,8 +13,8 @@ use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 use rustc_span::symbol::sym;
 
-use super::cache::{build_index, ExternalLocation};
 use super::print_item::{full_path, item_path, print_item};
+use super::search_index::build_index;
 use super::templates;
 use super::write_shared::write_shared;
 use super::{
@@ -22,7 +22,7 @@ use super::{
     BASIC_KEYWORDS,
 };
 
-use crate::clean::{self, ExternalCrate};
+use crate::clean::{self, types::ExternalLocation, ExternalCrate};
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index eb606178d24..3e7711181f7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -23,7 +23,7 @@
 //! These threads are not parallelized (they haven't been a bottleneck yet), and
 //! both occur before the crate is rendered.
 
-crate mod cache;
+crate mod search_index;
 
 #[cfg(test)]
 mod tests;
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/search_index.rs
index 631eacc9618..0fbe090f219 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -7,22 +7,12 @@ use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
-use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate};
+use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, TypeWithKind};
 
-/// Indicates where an external crate can be found.
-crate enum ExternalLocation {
-    /// Remote URL root of the external crate
-    Remote(String),
-    /// This external crate can be found in the local doc/ folder
-    Local,
-    /// The external crate could not be found.
-    Unknown,
-}
-
 /// Builds the search index from the collected metadata
 crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String {
     let mut defid_to_pathid = FxHashMap::default();
@@ -42,7 +32,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
                 desc,
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_index_search_type(item, tcx, cache),
+                search_type: get_function_type_for_search(item, tcx),
                 aliases: item.attrs.get_doc_aliases(),
             });
         }
@@ -191,15 +181,14 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
     )
 }
 
-crate fn get_index_search_type<'tcx>(
+crate fn get_function_type_for_search<'tcx>(
     item: &clean::Item,
     tcx: TyCtxt<'tcx>,
-    cache: &Cache,
 ) -> Option<IndexItemFunctionType> {
     let (mut inputs, mut output) = match *item.kind {
-        clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx, cache),
-        clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx, cache),
-        clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx, cache),
+        clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx),
+        clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx),
+        clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx),
         _ => return None,
     };
 
@@ -211,12 +200,12 @@ crate fn get_index_search_type<'tcx>(
 
 fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> RenderType {
     RenderType {
-        name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
+        name: get_index_type_name(clean_type).map(|s| s.as_str().to_ascii_lowercase()),
         generics: if generics.is_empty() { None } else { Some(generics) },
     }
 }
 
-fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> {
+fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
     match *clean_type {
         clean::Type::Path { ref path, .. } => {
             let path_segment = path.segments.last().unwrap();
@@ -226,11 +215,10 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
             let path = &bounds[0].trait_;
             Some(path.segments.last().unwrap().name)
         }
-        clean::Generic(s) if accept_generic => Some(s),
+        clean::Generic(s) => Some(s),
         clean::Primitive(ref p) => Some(p.as_sym()),
-        clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
-        clean::Generic(_)
-        | clean::BareFunction(_)
+        clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
+        clean::BareFunction(_)
         | clean::Tuple(_)
         | clean::Slice(_)
         | clean::Array(_, _)
@@ -248,20 +236,19 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
 ///
 /// Important note: It goes through generics recursively. So if you have
 /// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
-crate fn get_real_types<'tcx>(
+#[instrument(level = "trace", skip(tcx, res))]
+fn add_generics_and_bounds_as_types<'tcx>(
     generics: &Generics,
     arg: &Type,
     tcx: TyCtxt<'tcx>,
     recurse: usize,
     res: &mut Vec<TypeWithKind>,
-    cache: &Cache,
 ) {
     fn insert_ty(
         res: &mut Vec<TypeWithKind>,
         tcx: TyCtxt<'_>,
         ty: Type,
         mut generics: Vec<TypeWithKind>,
-        _cache: &Cache,
     ) {
         let is_full_generic = ty.is_full_generic();
 
@@ -330,6 +317,7 @@ crate fn get_real_types<'tcx>(
 
     if recurse >= 10 {
         // FIXME: remove this whole recurse thing when the recursion bug is fixed
+        // See #59502 for the original issue.
         return;
     }
 
@@ -350,13 +338,12 @@ crate fn get_real_types<'tcx>(
                     for param_def in poly_trait.generic_params.iter() {
                         match &param_def.kind {
                             clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
-                                get_real_types(
+                                add_generics_and_bounds_as_types(
                                     generics,
                                     ty,
                                     tcx,
                                     recurse + 1,
                                     &mut ty_generics,
-                                    cache,
                                 )
                             }
                             _ => {}
@@ -364,7 +351,7 @@ crate fn get_real_types<'tcx>(
                     }
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
+            insert_ty(res, tcx, arg.clone(), ty_generics);
         }
         // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
         if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
@@ -372,10 +359,16 @@ crate fn get_real_types<'tcx>(
             for bound in bound.get_bounds().unwrap_or(&[]) {
                 if let Some(path) = bound.get_trait_path() {
                     let ty = Type::Path { path };
-                    get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache);
+                    add_generics_and_bounds_as_types(
+                        generics,
+                        &ty,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_generics,
+                    );
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
+            insert_ty(res, tcx, arg.clone(), ty_generics);
         }
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
@@ -386,10 +379,10 @@ crate fn get_real_types<'tcx>(
         let mut ty_generics = Vec::new();
         if let Some(arg_generics) = arg.generics() {
             for gen in arg_generics.iter() {
-                get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics, cache);
+                add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
             }
         }
-        insert_ty(res, tcx, arg.clone(), ty_generics, cache);
+        insert_ty(res, tcx, arg.clone(), ty_generics);
     }
 }
 
@@ -397,19 +390,20 @@ crate fn get_real_types<'tcx>(
 ///
 /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
 /// `[u32, Display, Option]`.
-crate fn get_all_types<'tcx>(
-    generics: &Generics,
-    decl: &FnDecl,
+fn get_fn_inputs_and_outputs<'tcx>(
+    func: &Function,
     tcx: TyCtxt<'tcx>,
-    cache: &Cache,
 ) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
+    let decl = &func.decl;
+    let generics = &func.generics;
+
     let mut all_types = Vec::new();
     for arg in decl.inputs.values.iter() {
         if arg.type_.is_self_type() {
             continue;
         }
         let mut args = Vec::new();
-        get_real_types(generics, &arg.type_, tcx, 0, &mut args, cache);
+        add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args);
         if !args.is_empty() {
             all_types.extend(args);
         } else {
@@ -423,7 +417,7 @@ crate fn get_all_types<'tcx>(
     let mut ret_types = Vec::new();
     match decl.output {
         FnRetTy::Return(ref return_type) => {
-            get_real_types(generics, return_type, tcx, 0, &mut ret_types, cache);
+            add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types);
             if ret_types.is_empty() {
                 if let Some(kind) =
                     return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 0031e3915fa..005da01b52b 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -19,12 +19,11 @@ use rustc_session::Session;
 use rustdoc_json_types as types;
 
 use crate::clean;
-use crate::clean::ExternalCrate;
+use crate::clean::types::{ExternalCrate, ExternalLocation};
 use crate::config::RenderOptions;
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
-use crate::html::render::cache::ExternalLocation;
 use crate::json::conversions::{from_item_id, IntoWithTcx};
 
 #[derive(Clone)]
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index ba355107ed6..10ef92e5f40 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -684,27 +684,36 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 if ns != Namespace::ValueNS {
                     return None;
                 }
-                debug!("looking for variants or fields named {} for {:?}", item_name, did);
+                debug!("looking for fields named {} for {:?}", item_name, did);
                 // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
-                // NOTE: it's different from variant_field because it resolves fields and variants,
+                // NOTE: it's different from variant_field because it only resolves struct fields,
                 // not variant fields (2 path segments, not 3).
+                //
+                // We need to handle struct (and union) fields in this code because
+                // syntactically their paths are identical to associated item paths:
+                // `module::Type::field` and `module::Type::Assoc`.
+                //
+                // On the other hand, variant fields can't be mistaken for associated
+                // items because they look like this: `module::Type::Variant::field`.
+                //
+                // Variants themselves don't need to be handled here, even though
+                // they also look like associated items (`module::Type::Variant`),
+                // because they are real Rust syntax (unlike the intra-doc links
+                // field syntax) and are handled by the compiler's resolver.
                 let def = match tcx.type_of(did).kind() {
-                    ty::Adt(def, _) => def,
+                    ty::Adt(def, _) if !def.is_enum() => def,
                     _ => return None,
                 };
-                let field = if def.is_enum() {
-                    def.all_fields().find(|item| item.ident.name == item_name)
-                } else {
-                    def.non_enum_variant().fields.iter().find(|item| item.ident.name == item_name)
-                }?;
-                let kind = if def.is_enum() { DefKind::Variant } else { DefKind::Field };
-                let fragment = if def.is_enum() {
-                    // FIXME: how can the field be a variant?
-                    UrlFragment::Variant(field.ident.name)
-                } else {
-                    UrlFragment::StructField(field.ident.name)
-                };
-                Some((root_res, fragment, Some((kind, field.did))))
+                let field = def
+                    .non_enum_variant()
+                    .fields
+                    .iter()
+                    .find(|item| item.ident.name == item_name)?;
+                Some((
+                    root_res,
+                    UrlFragment::StructField(field.ident.name),
+                    Some((DefKind::Field, field.did)),
+                ))
             }
             Res::Def(DefKind::Trait, did) => tcx
                 .associated_items(did)
diff --git a/src/test/pretty/attr-fn-inner.rs b/src/test/pretty/attr-fn-inner.rs
index 0a745e7d34f..6d9cb89f022 100644
--- a/src/test/pretty/attr-fn-inner.rs
+++ b/src/test/pretty/attr-fn-inner.rs
@@ -9,8 +9,8 @@
 fn main() {
     #![rustc_dummy]
     #[rustc_dummy]
-    fn f() { }
+    fn f() {}
 
     #[rustc_dummy]
-    fn g() { }
+    fn g() {}
 }
diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs
index 44d2c5db3e6..d132014420d 100644
--- a/src/test/pretty/attr-literals.rs
+++ b/src/test/pretty/attr-literals.rs
@@ -7,8 +7,8 @@
 fn main() {
     #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))]
     #[rustc_dummy = 8]
-    fn f() { }
+    fn f() {}
 
     #[rustc_dummy(1, 2, 3)]
-    fn g() { }
+    fn g() {}
 }
diff --git a/src/test/pretty/attr-tokens-raw-ident.rs b/src/test/pretty/attr-tokens-raw-ident.rs
index bb2c4bb558e..8486342b087 100644
--- a/src/test/pretty/attr-tokens-raw-ident.rs
+++ b/src/test/pretty/attr-tokens-raw-ident.rs
@@ -4,4 +4,4 @@
 // pp-exact
 
 #[rustfmt::r#final(final)]
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs
index 257c032b536..1137d804564 100644
--- a/src/test/pretty/delimited-token-groups.rs
+++ b/src/test/pretty/delimited-token-groups.rs
@@ -45,4 +45,4 @@ mac! {
   }]
 #[rustc_dummy =
   "aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"]
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/doc-comments.rs b/src/test/pretty/doc-comments.rs
index 2a98c9fc058..a49860daa6a 100644
--- a/src/test/pretty/doc-comments.rs
+++ b/src/test/pretty/doc-comments.rs
@@ -5,7 +5,7 @@
 // some single-line non-doc comment
 
 /// some single line outer-docs
-fn a() { }
+fn a() {}
 
 fn b() {
     //! some single line inner-docs
@@ -17,7 +17,7 @@ fn b() {
 //////////////////////////////////
 /// some single-line outer-docs preceded by a separator
 /// (and trailing whitespaces)
-fn c() { }
+fn c() {}
 
 /*
  * some multi-line non-doc comment
@@ -26,7 +26,7 @@ fn c() { }
 /**
  * some multi-line outer-docs
  */
-fn d() { }
+fn d() {}
 
 fn e() {
     /*!
@@ -43,10 +43,10 @@ fn e() {
 /**
  * some multi-line outer-docs preceded by a separator
  */
-fn f() { }
+fn f() {}
 
 #[doc = "unsugared outer doc-comments work also"]
-fn g() { }
+fn g() {}
 
 fn h() {
     #![doc = "as do inner ones"]
diff --git a/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs
new file mode 100644
index 00000000000..ce51556dd41
--- /dev/null
+++ b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+// Minimization of issue #59502
+
+trait MyTrait<T> {
+    type Output;
+}
+
+pub fn pow<T: MyTrait<T, Output = T>>(arg: T) -> T {
+    arg
+}
diff --git a/src/test/ui/error-codes/E0227.rs b/src/test/ui/error-codes/E0227.rs
new file mode 100644
index 00000000000..0f0a781d2f9
--- /dev/null
+++ b/src/test/ui/error-codes/E0227.rs
@@ -0,0 +1,12 @@
+trait Foo<'foo>: 'foo {}
+trait Bar<'bar>: 'bar {}
+
+trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {}
+
+struct Baz<'foo, 'bar> {
+    baz: dyn FooBar<'foo, 'bar>,
+    //~^ ERROR ambiguous lifetime bound, explicit lifetime bound required
+}
+
+fn main() {
+}
diff --git a/src/test/ui/error-codes/E0227.stderr b/src/test/ui/error-codes/E0227.stderr
new file mode 100644
index 00000000000..26de5b4c400
--- /dev/null
+++ b/src/test/ui/error-codes/E0227.stderr
@@ -0,0 +1,9 @@
+error[E0227]: ambiguous lifetime bound, explicit lifetime bound required
+  --> $DIR/E0227.rs:7:10
+   |
+LL |     baz: dyn FooBar<'foo, 'bar>,
+   |          ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0227`.
diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs
index fcf6a9278d8..90bc7dc1da2 100644
--- a/src/test/ui/macros/stringify.rs
+++ b/src/test/ui/macros/stringify.rs
@@ -235,7 +235,7 @@ fn test_expr() {
             #[attr]
             {}
         ),
-        "#[attr] { }", // FIXME
+        "#[attr] {}",
     );
     assert_eq!(
         stringify_expr!(
@@ -803,7 +803,7 @@ fn test_ty() {
     assert_eq!(stringify_ty!(fn(x: u8)), "fn(x: u8)");
     #[rustfmt::skip]
     assert_eq!(stringify_ty!(for<> fn()), "fn()");
-    assert_eq!(stringify_ty!(for<'a> fn()), "for<'a>fn()"); // FIXME
+    assert_eq!(stringify_ty!(for<'a> fn()), "for<'a> fn()");
 
     // TyKind::Never
     assert_eq!(stringify_ty!(!), "!");
diff --git a/src/test/ui/match/expr_before_ident_pat.rs b/src/test/ui/match/expr_before_ident_pat.rs
new file mode 100644
index 00000000000..47db6c3f488
--- /dev/null
+++ b/src/test/ui/match/expr_before_ident_pat.rs
@@ -0,0 +1,15 @@
+#![feature(half_open_range_patterns)]
+
+macro_rules! funny {
+    ($a:expr, $b:ident) => {
+        match [1, 2] {
+            [$a, $b] => {}
+        }
+    };
+}
+
+fn main() {
+    funny!(a, a);
+    //~^ ERROR cannot find value `a` in this scope
+    //~| ERROR arbitrary expressions aren't allowed in patterns
+}
diff --git a/src/test/ui/match/expr_before_ident_pat.stderr b/src/test/ui/match/expr_before_ident_pat.stderr
new file mode 100644
index 00000000000..1ac8274ffd5
--- /dev/null
+++ b/src/test/ui/match/expr_before_ident_pat.stderr
@@ -0,0 +1,15 @@
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/expr_before_ident_pat.rs:12:12
+   |
+LL |     funny!(a, a);
+   |            ^
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/expr_before_ident_pat.rs:12:12
+   |
+LL |     funny!(a, a);
+   |            ^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/match/issue-92100.rs b/src/test/ui/match/issue-92100.rs
new file mode 100644
index 00000000000..021166b2ba5
--- /dev/null
+++ b/src/test/ui/match/issue-92100.rs
@@ -0,0 +1,7 @@
+#![feature(half_open_range_patterns)]
+
+fn main() {
+    match [1, 2] {
+        [a.., a] => {} //~ ERROR cannot find value `a` in this scope
+    }
+}
diff --git a/src/test/ui/match/issue-92100.stderr b/src/test/ui/match/issue-92100.stderr
new file mode 100644
index 00000000000..0f694c587fc
--- /dev/null
+++ b/src/test/ui/match/issue-92100.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/issue-92100.rs:5:10
+   |
+LL |         [a.., a] => {}
+   |          ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/parser/type-alias-where.rs b/src/test/ui/parser/type-alias-where.rs
new file mode 100644
index 00000000000..a9fa23dd95e
--- /dev/null
+++ b/src/test/ui/parser/type-alias-where.rs
@@ -0,0 +1,37 @@
+// check-fail
+
+#![feature(generic_associated_types)]
+
+// Fine, but lints as unused
+type Foo where u32: Copy = ();
+// Not fine.
+type Bar = () where u32: Copy;
+//~^ ERROR where clause not allowed here
+type Baz = () where;
+//~^ ERROR where clause not allowed here
+
+trait Trait {
+    // Fine.
+    type Assoc where u32: Copy;
+    // Fine.
+    type Assoc2 where u32: Copy, i32: Copy;
+}
+
+impl Trait for u32 {
+    // Fine.
+    type Assoc where u32: Copy = ();
+    // Not fine, suggests moving `i32: Copy`
+    type Assoc2 where u32: Copy = () where i32: Copy;
+    //~^ ERROR where clause not allowed here
+}
+
+impl Trait for i32 {
+    // Not fine, suggests moving `u32: Copy`
+    type Assoc = () where u32: Copy;
+    //~^ ERROR where clause not allowed here
+    // Not fine, suggests moving both.
+    type Assoc2 = () where u32: Copy, i32: Copy;
+    //~^ ERROR where clause not allowed here
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/type-alias-where.stderr b/src/test/ui/parser/type-alias-where.stderr
new file mode 100644
index 00000000000..7ab0b28c864
--- /dev/null
+++ b/src/test/ui/parser/type-alias-where.stderr
@@ -0,0 +1,40 @@
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:8:15
+   |
+LL | type Bar = () where u32: Copy;
+   |         -     ^^^^^^^^^^^^^^^
+   |         |
+   |         help: move it here: `where u32: Copy`
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:10:15
+   |
+LL | type Baz = () where;
+   |               ^^^^^
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:24:38
+   |
+LL |     type Assoc2 where u32: Copy = () where i32: Copy;
+   |                                -     ^^^^^^^^^^^^^^^
+   |                                |
+   |                                help: move it here: `, i32: Copy`
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:30:21
+   |
+LL |     type Assoc = () where u32: Copy;
+   |               -     ^^^^^^^^^^^^^^^
+   |               |
+   |               help: move it here: `where u32: Copy`
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:33:22
+   |
+LL |     type Assoc2 = () where u32: Copy, i32: Copy;
+   |                -     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                help: move it here: `where u32: Copy, i32: Copy`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 6d3e470bf43..8ea6bb308b7 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -10,8 +10,8 @@ use regex::Regex;
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514",
-    "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
+    "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", "E0519",
+    "E0523", "E0554", "E0640", "E0717", "E0729",
 ];
 
 // Some error codes don't have any tests apparently...