about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-01 17:33:42 +0000
committerbors <bors@rust-lang.org>2022-07-01 17:33:42 +0000
commit5018181c79a6fe37913fd931005ad2a63c85be7b (patch)
treedf5eaa91d921af448f7bcccb3f4c4641090dd6bb
parent5b9775fe17893cba641a071de7e0a7c8f478c41b (diff)
parent6404620f18da68a07299d6fe02d886141b9d0347 (diff)
downloadrust-5018181c79a6fe37913fd931005ad2a63c85be7b.tar.gz
rust-5018181c79a6fe37913fd931005ad2a63c85be7b.zip
Auto merge of #98767 - Dylan-DPC:rollup-j1gq5sr, r=Dylan-DPC
Rollup of 6 pull requests

Successful merges:

 - #97488 (Suggest blanket impl to the local traits)
 - #98585 (Make `ThinBox<T>` covariant in `T`)
 - #98644 (fix ICE with -Wrust-2021-incompatible-closure-captures)
 - #98739 (fix grammar in useless doc comment lint)
 - #98741 (Many small deriving cleanups)
 - #98756 (Use const instead of function and make it private)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs56
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs20
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs23
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs25
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs131
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs120
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs8
-rw-r--r--compiler/rustc_lint/src/builtin.rs4
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs72
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs6
-rw-r--r--library/alloc/src/boxed/thin.rs33
-rw-r--r--library/alloc/tests/thin_box.rs7
-rw-r--r--src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr2
-rw-r--r--src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs18
-rw-r--r--src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr93
-rw-r--r--src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs15
-rw-r--r--src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr24
-rw-r--r--src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs58
-rw-r--r--src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr107
-rwxr-xr-xsuggest-blanket-impl-local-traitbin0 -> 479160 bytes
27 files changed, 545 insertions, 331 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 12ef166b8b0..5ef68c6aeaa 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -19,7 +19,6 @@ pub fn expand_deriving_copy(
         path: path_std!(marker::Copy),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: true,
         methods: Vec::new(),
         associated_types: Vec::new(),
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 83317106990..1c507678489 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -15,23 +15,22 @@ pub fn expand_deriving_clone(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    // check if we can use a short form
+    // The simple form is `fn clone(&self) -> Self { *self }`, possibly with
+    // some additional `AssertParamIsClone` assertions.
     //
-    // the short form is `fn clone(&self) -> Self { *self }`
-    //
-    // we can use the short form if:
-    // - the item is Copy (unfortunately, all we can check is whether it's also deriving Copy)
-    // - there are no generic parameters (after specialization this limitation can be removed)
-    //      if we used the short form with generics, we'd have to bound the generics with
-    //      Clone + Copy, and then there'd be no Clone impl at all if the user fills in something
-    //      that is Clone but not Copy. and until specialization we can't write both impls.
-    // - the item is a union with Copy fields
-    //      Unions with generic parameters still can derive Clone because they require Copy
-    //      for deriving, Clone alone is not enough.
-    //      Wherever Clone is implemented for fields is irrelevant so we don't assert it.
+    // We can use the simple form if either of the following are true.
+    // - The type derives Copy and there are no generic parameters.  (If we
+    //   used the simple form with generics, we'd have to bound the generics
+    //   with Clone + Copy, and then there'd be no Clone impl at all if the
+    //   user fills in something that is Clone but not Copy. After
+    //   specialization we can remove this no-generics limitation.)
+    // - The item is a union. (Unions with generic parameters still can derive
+    //   Clone because they require Copy for deriving, Clone alone is not
+    //   enough. Whether Clone is implemented for fields is irrelevant so we
+    //   don't assert it.)
     let bounds;
     let substructure;
-    let is_shallow;
+    let is_simple;
     match *item {
         Annotatable::Item(ref annitem) => match annitem.kind {
             ItemKind::Struct(_, Generics { ref params, .. })
@@ -44,30 +43,25 @@ pub fn expand_deriving_clone(
                         .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
                 {
                     bounds = vec![];
-                    is_shallow = true;
+                    is_simple = true;
                     substructure = combine_substructure(Box::new(|c, s, sub| {
-                        cs_clone_shallow("Clone", c, s, sub, false)
+                        cs_clone_simple("Clone", c, s, sub, false)
                     }));
                 } else {
                     bounds = vec![];
-                    is_shallow = false;
+                    is_simple = false;
                     substructure =
                         combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
                 }
             }
             ItemKind::Union(..) => {
-                bounds = vec![Literal(path_std!(marker::Copy))];
-                is_shallow = true;
+                bounds = vec![Path(path_std!(marker::Copy))];
+                is_simple = true;
                 substructure = combine_substructure(Box::new(|c, s, sub| {
-                    cs_clone_shallow("Clone", c, s, sub, true)
+                    cs_clone_simple("Clone", c, s, sub, true)
                 }));
             }
-            _ => {
-                bounds = vec![];
-                is_shallow = false;
-                substructure =
-                    combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
-            }
+            _ => cx.span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
         },
 
         _ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
@@ -81,26 +75,24 @@ pub fn expand_deriving_clone(
         path: path_std!(clone::Clone),
         additional_bounds: bounds,
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: true,
         methods: vec![MethodDef {
             name: sym::clone,
             generics: Bounds::empty(),
-            explicit_self: borrowed_explicit_self(),
+            explicit_self: true,
             args: Vec::new(),
             ret_ty: Self_,
             attributes: attrs,
-            is_unsafe: false,
             unify_fieldless_variants: false,
             combine_substructure: substructure,
         }],
         associated_types: Vec::new(),
     };
 
-    trait_def.expand_ext(cx, mitem, item, push, is_shallow)
+    trait_def.expand_ext(cx, mitem, item, push, is_simple)
 }
 
-fn cs_clone_shallow(
+fn cs_clone_simple(
     name: &str,
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
@@ -143,7 +135,7 @@ fn cs_clone_shallow(
             }
             _ => cx.span_bug(
                 trait_span,
-                &format!("unexpected substructure in shallow `derive({})`", name),
+                &format!("unexpected substructure in simple `derive({})`", name),
             ),
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index f54ded3c87c..cb2ad283a19 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -27,16 +27,14 @@ pub fn expand_deriving_eq(
         path: path_std!(cmp::Eq),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: true,
         methods: vec![MethodDef {
             name: sym::assert_receiver_is_total_eq,
             generics: Bounds::empty(),
-            explicit_self: borrowed_explicit_self(),
+            explicit_self: true,
             args: vec![],
-            ret_ty: nil_ty(),
+            ret_ty: Unit,
             attributes: attrs,
-            is_unsafe: false,
             unify_fieldless_variants: true,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 cs_total_eq_assert(a, b, c)
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 2b3ac0a86c1..c7850cd4b4c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -23,16 +23,14 @@ pub fn expand_deriving_ord(
         path: path_std!(cmp::Ord),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::cmp,
             generics: Bounds::empty(),
-            explicit_self: borrowed_explicit_self(),
-            args: vec![(borrowed_self(), sym::other)],
-            ret_ty: Literal(path_std!(cmp::Ordering)),
+            explicit_self: true,
+            args: vec![(self_ref(), sym::other)],
+            ret_ty: Path(path_std!(cmp::Ordering)),
             attributes: attrs,
-            is_unsafe: false,
             unify_fieldless_variants: true,
             combine_substructure: combine_substructure(Box::new(|a, b, c| cs_cmp(a, b, c))),
         }],
@@ -99,8 +97,8 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
             cx.expr_match(span, new, vec![eq_arm, neq_arm])
         },
         cx.expr_path(equals_path.clone()),
-        Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
-            if self_args.len() != 2 {
+        Box::new(|cx, span, tag_tuple| {
+            if tag_tuple.len() != 2 {
                 cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
             } else {
                 ordering_collapsed(cx, span, tag_tuple)
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index eead8b37024..ca5ca29eb82 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -48,7 +48,7 @@ pub fn expand_deriving_partial_eq(
                     None => cx.expr_bool(span, base),
                 }
             },
-            Box::new(|cx, span, _, _| cx.expr_bool(span, !base)),
+            Box::new(|cx, span, _| cx.expr_bool(span, !base)),
             cx,
             span,
             substr,
@@ -69,11 +69,10 @@ pub fn expand_deriving_partial_eq(
             MethodDef {
                 name: $name,
                 generics: Bounds::empty(),
-                explicit_self: borrowed_explicit_self(),
-                args: vec![(borrowed_self(), sym::other)],
-                ret_ty: Literal(path_local!(bool)),
+                explicit_self: true,
+                args: vec![(self_ref(), sym::other)],
+                ret_ty: Path(path_local!(bool)),
                 attributes: attrs,
-                is_unsafe: false,
                 unify_fieldless_variants: true,
                 combine_substructure: combine_substructure(Box::new(|a, b, c| $f(a, b, c))),
             }
@@ -102,7 +101,6 @@ pub fn expand_deriving_partial_eq(
         path: path_std!(cmp::PartialEq),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods,
         associated_types: Vec::new(),
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index d28ac822a1e..07db82fee93 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -15,13 +15,9 @@ pub fn expand_deriving_partial_ord(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let ordering_ty = Literal(path_std!(cmp::Ordering));
-    let ret_ty = Literal(Path::new_(
-        pathvec_std!(option::Option),
-        None,
-        vec![Box::new(ordering_ty)],
-        PathKind::Std,
-    ));
+    let ordering_ty = Path(path_std!(cmp::Ordering));
+    let ret_ty =
+        Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
 
     let inline = cx.meta_word(span, sym::inline);
     let attrs = vec![cx.attribute(inline)];
@@ -29,11 +25,10 @@ pub fn expand_deriving_partial_ord(
     let partial_cmp_def = MethodDef {
         name: sym::partial_cmp,
         generics: Bounds::empty(),
-        explicit_self: borrowed_explicit_self(),
-        args: vec![(borrowed_self(), sym::other)],
+        explicit_self: true,
+        args: vec![(self_ref(), sym::other)],
         ret_ty,
         attributes: attrs,
-        is_unsafe: false,
         unify_fieldless_variants: true,
         combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
             cs_partial_cmp(cx, span, substr)
@@ -46,7 +41,6 @@ pub fn expand_deriving_partial_ord(
         path: path_std!(cmp::PartialOrd),
         additional_bounds: vec![],
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods: vec![partial_cmp_def],
         associated_types: Vec::new(),
@@ -102,8 +96,8 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
             cx.expr_match(span, new, vec![eq_arm, neq_arm])
         },
         equals_expr,
-        Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
-            if self_args.len() != 2 {
+        Box::new(|cx, span, tag_tuple| {
+            if tag_tuple.len() != 2 {
                 cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
             } else {
                 let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 1fffd6f9727..1411c60c0bf 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -16,8 +16,7 @@ pub fn expand_deriving_debug(
     push: &mut dyn FnMut(Annotatable),
 ) {
     // &mut ::std::fmt::Formatter
-    let fmtr =
-        Ptr(Box::new(Literal(path_std!(fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));
+    let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut);
 
     let trait_def = TraitDef {
         span,
@@ -25,16 +24,14 @@ pub fn expand_deriving_debug(
         path: path_std!(fmt::Debug),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::fmt,
             generics: Bounds::empty(),
-            explicit_self: borrowed_explicit_self(),
+            explicit_self: true,
             args: vec![(fmtr, sym::f)],
-            ret_ty: Literal(path_std!(fmt::Result)),
+            ret_ty: Path(path_std!(fmt::Result)),
             attributes: Vec::new(),
-            is_unsafe: false,
             unify_fieldless_variants: false,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 show_substructure(a, b, c)
@@ -64,8 +61,6 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     let (is_struct, args_per_field) = match vdata {
         ast::VariantData::Unit(..) => {
             // Special fast path for unit variants.
-            //let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
-            //return cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
             assert!(fields.is_empty());
             (false, 0)
         }
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index b39f35a9d40..16154fb4d03 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -23,40 +23,29 @@ pub fn expand_deriving_rustc_decodable(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: Path::new_(vec![krate, sym::Decodable], None, vec![], PathKind::Global),
+        path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::decode,
             generics: Bounds {
                 bounds: vec![(
                     typaram,
-                    vec![Path::new_(vec![krate, sym::Decoder], None, vec![], PathKind::Global)],
+                    vec![Path::new_(vec![krate, sym::Decoder], vec![], PathKind::Global)],
                 )],
             },
-            explicit_self: None,
-            args: vec![(
-                Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
-                sym::d,
-            )],
-            ret_ty: Literal(Path::new_(
+            explicit_self: false,
+            args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::d)],
+            ret_ty: Path(Path::new_(
                 pathvec_std!(result::Result),
-                None,
                 vec![
                     Box::new(Self_),
-                    Box::new(Literal(Path::new_(
-                        vec![typaram, sym::Error],
-                        None,
-                        vec![],
-                        PathKind::Local,
-                    ))),
+                    Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
                 ],
                 PathKind::Std,
             )),
             attributes: Vec::new(),
-            is_unsafe: false,
             unify_fieldless_variants: false,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 decodable_substructure(a, b, c, krate)
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index b49331e2875..d41b25343b0 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -30,16 +30,14 @@ pub fn expand_deriving_default(
         path: Path::new(vec![kw::Default, sym::Default]),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: kw::Default,
             generics: Bounds::empty(),
-            explicit_self: None,
+            explicit_self: false,
             args: Vec::new(),
             ret_ty: Self_,
             attributes: attrs,
-            is_unsafe: false,
             unify_fieldless_variants: false,
             combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
                 match substr.fields {
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 6151a80a56d..7dc0584618d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -108,40 +108,29 @@ pub fn expand_deriving_rustc_encodable(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global),
+        path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::encode,
             generics: Bounds {
                 bounds: vec![(
                     typaram,
-                    vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)],
+                    vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)],
                 )],
             },
-            explicit_self: borrowed_explicit_self(),
-            args: vec![(
-                Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
-                sym::s,
-            )],
-            ret_ty: Literal(Path::new_(
+            explicit_self: true,
+            args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::s)],
+            ret_ty: Path(Path::new_(
                 pathvec_std!(result::Result),
-                None,
                 vec![
-                    Box::new(Tuple(Vec::new())),
-                    Box::new(Literal(Path::new_(
-                        vec![typaram, sym::Error],
-                        None,
-                        vec![],
-                        PathKind::Local,
-                    ))),
+                    Box::new(Unit),
+                    Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
                 ],
                 PathKind::Std,
             )),
             attributes: Vec::new(),
-            is_unsafe: false,
             unify_fieldless_variants: false,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 encodable_substructure(a, b, c, krate)
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 8347cded2fe..ff431c8de5d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -146,8 +146,6 @@
 //!
 //! ```{.text}
 //! EnumNonMatchingCollapsed(
-//!     vec![<ident of self>, <ident of __arg_1>],
-//!     &[<ast::Variant for C0>, <ast::Variant for C1>],
 //!     &[<ident for self index value>, <ident of __arg_1 index value>])
 //! ```
 //!
@@ -190,7 +188,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 
-use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty};
+use ty::{Bounds, Path, Ref, Self_, Ty};
 
 use crate::deriving;
 
@@ -212,9 +210,6 @@ pub struct TraitDef<'a> {
     /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
     pub generics: Bounds,
 
-    /// Is it an `unsafe` trait?
-    pub is_unsafe: bool,
-
     /// Can this trait be derived for unions?
     pub supports_unions: bool,
 
@@ -229,10 +224,8 @@ pub struct MethodDef<'a> {
     /// List of generics, e.g., `R: rand::Rng`
     pub generics: Bounds,
 
-    /// Whether there is a self argument (outer Option) i.e., whether
-    /// this is a static function, and whether it is a pointer (inner
-    /// Option)
-    pub explicit_self: Option<Option<PtrTy>>,
+    /// Is there is a `&self` argument? If not, it is a static function.
+    pub explicit_self: bool,
 
     /// Arguments other than the self argument
     pub args: Vec<(Ty, Symbol)>,
@@ -242,9 +235,6 @@ pub struct MethodDef<'a> {
 
     pub attributes: Vec<ast::Attribute>,
 
-    // Is it an `unsafe fn`?
-    pub is_unsafe: bool,
-
     /// Can we combine fieldless variants for enums into a single match arm?
     pub unify_fieldless_variants: bool,
 
@@ -255,14 +245,7 @@ pub struct MethodDef<'a> {
 pub struct Substructure<'a> {
     /// ident of self
     pub type_ident: Ident,
-    /// ident of the method
-    pub method_ident: Ident,
-    /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments
-    ///
-    /// [`Self_`]: ty::Ty::Self_
-    /// [ptr]: ty::Ty::Ptr
-    pub self_args: &'a [P<Expr>],
-    /// verbatim access to any other arguments
+    /// verbatim access to any non-self arguments
     pub nonself_args: &'a [P<Expr>],
     pub fields: &'a SubstructureFields<'a>,
 }
@@ -299,13 +282,10 @@ pub enum SubstructureFields<'a> {
     /// variant.
     EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
 
-    /// Non-matching variants of the enum, but with all state hidden from
-    /// the consequent code. The first component holds `Ident`s for all of
-    /// the `Self` arguments; the second component is a slice of all of the
-    /// variants for the enum itself, and the third component is a list of
-    /// `Ident`s bound to the variant index values for each of the actual
-    /// input `Self` arguments.
-    EnumNonMatchingCollapsed(Vec<Ident>, &'a [ast::Variant], &'a [Ident]),
+    /// Non-matching variants of the enum, but with all state hidden from the
+    /// consequent code. The field is a list of `Ident`s bound to the variant
+    /// index values for each of the actual input `Self` arguments.
+    EnumNonMatchingCollapsed(&'a [Ident]),
 
     /// A static method where `Self` is a struct.
     StaticStruct(&'a ast::VariantData, StaticFields),
@@ -318,13 +298,10 @@ pub enum SubstructureFields<'a> {
 pub type CombineSubstructureFunc<'a> =
     Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> P<Expr> + 'a>;
 
-/// Deal with non-matching enum variants. The tuple is a list of
-/// identifiers (one for each `Self` argument, which could be any of the
-/// variants since they have been collapsed together) and the identifiers
-/// holding the variant index value for each of the `Self` arguments. The
-/// last argument is all the non-`Self` args of the method being derived.
+/// Deal with non-matching enum variants. The slice is the identifiers holding
+/// the variant index value for each of the `Self` arguments.
 pub type EnumNonMatchCollapsedFunc<'a> =
-    Box<dyn FnMut(&mut ExtCtxt<'_>, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
+    Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &[Ident]) -> P<Expr> + 'a>;
 
 pub fn combine_substructure(
     f: CombineSubstructureFunc<'_>,
@@ -727,14 +704,12 @@ impl<'a> TraitDef<'a> {
         let mut a = vec![attr, unused_qual];
         a.extend(self.attributes.iter().cloned());
 
-        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No };
-
         cx.item(
             self.span,
             Ident::empty(),
             a,
             ast::ItemKind::Impl(Box::new(ast::Impl {
-                unsafety,
+                unsafety: ast::Unsafe::No,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
                 constness: ast::Const::No,
@@ -771,7 +746,6 @@ impl<'a> TraitDef<'a> {
                         self,
                         struct_def,
                         type_ident,
-                        &self_args,
                         &nonself_args,
                     )
                 } else {
@@ -820,7 +794,6 @@ impl<'a> TraitDef<'a> {
                         self,
                         enum_def,
                         type_ident,
-                        &self_args,
                         &nonself_args,
                     )
                 } else {
@@ -848,18 +821,11 @@ impl<'a> MethodDef<'a> {
         cx: &mut ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
-        self_args: &[P<Expr>],
         nonself_args: &[P<Expr>],
         fields: &SubstructureFields<'_>,
     ) -> P<Expr> {
         let span = trait_.span;
-        let substructure = Substructure {
-            type_ident,
-            method_ident: Ident::new(self.name, span),
-            self_args,
-            nonself_args,
-            fields,
-        };
+        let substructure = Substructure { type_ident, nonself_args, fields };
         let mut f = self.combine_substructure.borrow_mut();
         let f: &mut CombineSubstructureFunc<'_> = &mut *f;
         f(cx, span, &substructure)
@@ -876,7 +842,7 @@ impl<'a> MethodDef<'a> {
     }
 
     fn is_static(&self) -> bool {
-        self.explicit_self.is_none()
+        !self.explicit_self
     }
 
     fn split_self_nonself_args(
@@ -889,17 +855,15 @@ impl<'a> MethodDef<'a> {
         let mut self_args = Vec::new();
         let mut nonself_args = Vec::new();
         let mut arg_tys = Vec::new();
-        let mut nonstatic = false;
         let span = trait_.span;
 
-        let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
-            let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
-
+        let ast_explicit_self = if self.explicit_self {
+            let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
             self_args.push(self_expr);
-            nonstatic = true;
-
-            explicit_self
-        });
+            Some(explicit_self)
+        } else {
+            None
+        };
 
         for (ty, name) in self.args.iter() {
             let ast_ty = ty.to_ty(cx, span, type_ident, generics);
@@ -911,10 +875,10 @@ impl<'a> MethodDef<'a> {
             match *ty {
                 // for static methods, just treat any Self
                 // arguments as a normal arg
-                Self_ if nonstatic => {
+                Self_ if !self.is_static() => {
                     self_args.push(arg_expr);
                 }
-                Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
+                Ref(ref ty, _) if matches!(**ty, Self_) && !self.is_static() => {
                     self_args.push(cx.expr_deref(span, arg_expr))
                 }
                 _ => {
@@ -955,15 +919,9 @@ impl<'a> MethodDef<'a> {
         let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
         let body_block = cx.block_expr(body);
 
-        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
-
         let trait_lo_sp = span.shrink_to_lo();
 
-        let sig = ast::FnSig {
-            header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
-            decl: fn_decl,
-            span,
-        };
+        let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
         let defaultness = ast::Defaultness::Final;
 
         // Create the method.
@@ -1083,7 +1041,6 @@ impl<'a> MethodDef<'a> {
             cx,
             trait_,
             type_ident,
-            self_args,
             nonself_args,
             &Struct(struct_def, fields),
         );
@@ -1104,7 +1061,6 @@ impl<'a> MethodDef<'a> {
         trait_: &TraitDef<'_>,
         struct_def: &VariantData,
         type_ident: Ident,
-        self_args: &[P<Expr>],
         nonself_args: &[P<Expr>],
     ) -> P<Expr> {
         let summary = trait_.summarise_struct(cx, struct_def);
@@ -1113,7 +1069,6 @@ impl<'a> MethodDef<'a> {
             cx,
             trait_,
             type_ident,
-            self_args,
             nonself_args,
             &StaticStruct(struct_def, summary),
         )
@@ -1184,11 +1139,6 @@ impl<'a> MethodDef<'a> {
             )
             .collect::<Vec<String>>();
 
-        let self_arg_idents = self_arg_names
-            .iter()
-            .map(|name| Ident::from_str_and_span(name, span))
-            .collect::<Vec<Ident>>();
-
         // The `vi_idents` will be bound, solely in the catch-all, to
         // a series of let statements mapping each self_arg to an int
         // value corresponding to its discriminant.
@@ -1203,8 +1153,7 @@ impl<'a> MethodDef<'a> {
         // Builds, via callback to call_substructure_method, the
         // delegated expression that handles the catch-all case,
         // using `__variants_tuple` to drive logic if necessary.
-        let catch_all_substructure =
-            EnumNonMatchingCollapsed(self_arg_idents, &variants, &vi_idents);
+        let catch_all_substructure = EnumNonMatchingCollapsed(&vi_idents);
 
         let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
 
@@ -1303,7 +1252,6 @@ impl<'a> MethodDef<'a> {
                     cx,
                     trait_,
                     type_ident,
-                    &self_args[..],
                     nonself_args,
                     &substructure,
                 );
@@ -1322,7 +1270,6 @@ impl<'a> MethodDef<'a> {
                     cx,
                     trait_,
                     type_ident,
-                    &self_args[..],
                     nonself_args,
                     &substructure,
                 ))
@@ -1393,7 +1340,6 @@ impl<'a> MethodDef<'a> {
                 cx,
                 trait_,
                 type_ident,
-                &self_args[..],
                 nonself_args,
                 &catch_all_substructure,
             );
@@ -1491,7 +1437,6 @@ impl<'a> MethodDef<'a> {
         trait_: &TraitDef<'_>,
         enum_def: &EnumDef,
         type_ident: Ident,
-        self_args: &[P<Expr>],
         nonself_args: &[P<Expr>],
     ) -> P<Expr> {
         let summary = enum_def
@@ -1507,7 +1452,6 @@ impl<'a> MethodDef<'a> {
             cx,
             trait_,
             type_ident,
-            self_args,
             nonself_args,
             &StaticEnum(enum_def, summary),
         )
@@ -1628,7 +1572,7 @@ impl<'a> TraitDef<'a> {
 
 // helpful premade recipes
 
-pub fn cs_fold_fields<'a, F>(
+fn cs_fold_fields<'a, F>(
     use_foldl: bool,
     mut f: F,
     base: P<Expr>,
@@ -1650,21 +1594,19 @@ where
     }
 }
 
-pub fn cs_fold_enumnonmatch(
+fn cs_fold_enumnonmatch(
     mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substructure: &Substructure<'_>,
 ) -> P<Expr> {
     match *substructure.fields {
-        EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
-            enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), substructure.nonself_args)
-        }
+        EnumNonMatchingCollapsed(tuple) => enum_nonmatch_f(cx, trait_span, tuple),
         _ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"),
     }
 }
 
-pub fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
+fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
     cx.span_bug(trait_span, "static function in `derive`")
 }
 
@@ -1717,22 +1659,21 @@ where
 {
     match *substructure.fields {
         EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
-            let (base, all_fields) = match (all_fields.is_empty(), use_foldl) {
+            let (base, rest) = match (all_fields.is_empty(), use_foldl) {
                 (false, true) => {
-                    let field = &all_fields[0];
-                    let args = (field.span, field.self_.clone(), &field.other[..]);
-                    (b(cx, Some(args)), &all_fields[1..])
+                    let (first, rest) = all_fields.split_first().unwrap();
+                    let args = (first.span, first.self_.clone(), &first.other[..]);
+                    (b(cx, Some(args)), rest)
                 }
                 (false, false) => {
-                    let idx = all_fields.len() - 1;
-                    let field = &all_fields[idx];
-                    let args = (field.span, field.self_.clone(), &field.other[..]);
-                    (b(cx, Some(args)), &all_fields[..idx])
+                    let (last, rest) = all_fields.split_last().unwrap();
+                    let args = (last.span, last.self_.clone(), &last.other[..]);
+                    (b(cx, Some(args)), rest)
                 }
                 (true, _) => (b(cx, None), &all_fields[..]),
             };
 
-            cs_fold_fields(use_foldl, f, base, cx, all_fields)
+            cs_fold_fields(use_foldl, f, base, cx, rest)
         }
         EnumNonMatchingCollapsed(..) => {
             cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 7a418003250..4b20d87629d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -1,7 +1,6 @@
 //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
 //! when specifying impls to be derived.
 
-pub use PtrTy::*;
 pub use Ty::*;
 
 use rustc_ast::ptr::P;
@@ -11,22 +10,11 @@ use rustc_span::source_map::{respan, DUMMY_SP};
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 
-/// The types of pointers
-#[derive(Clone)]
-pub enum PtrTy {
-    /// &'lifetime mut
-    Borrowed(Option<Ident>, ast::Mutability),
-    /// *mut
-    #[allow(dead_code)]
-    Raw(ast::Mutability),
-}
-
 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
-/// for type parameters and a lifetime.
+/// for type parameters.
 #[derive(Clone)]
 pub struct Path {
     path: Vec<Symbol>,
-    lifetime: Option<Ident>,
     params: Vec<Box<Ty>>,
     kind: PathKind,
 }
@@ -40,18 +28,13 @@ pub enum PathKind {
 
 impl Path {
     pub fn new(path: Vec<Symbol>) -> Path {
-        Path::new_(path, None, Vec::new(), PathKind::Std)
+        Path::new_(path, Vec::new(), PathKind::Std)
     }
     pub fn new_local(path: Symbol) -> Path {
-        Path::new_(vec![path], None, Vec::new(), PathKind::Local)
+        Path::new_(vec![path], Vec::new(), PathKind::Local)
     }
-    pub fn new_(
-        path: Vec<Symbol>,
-        lifetime: Option<Ident>,
-        params: Vec<Box<Ty>>,
-        kind: PathKind,
-    ) -> Path {
-        Path { path, lifetime, params, kind }
+    pub fn new_(path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind) -> Path {
+        Path { path, params, kind }
     }
 
     pub fn to_ty(
@@ -71,10 +54,8 @@ impl Path {
         self_generics: &Generics,
     ) -> ast::Path {
         let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
-        let lt = mk_lifetimes(cx, span, &self.lifetime);
         let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
-        let params =
-            lt.into_iter().map(GenericArg::Lifetime).chain(tys.map(GenericArg::Type)).collect();
+        let params = tys.map(GenericArg::Type).collect();
 
         match self.kind {
             PathKind::Global => cx.path_all(span, true, idents, params),
@@ -92,40 +73,17 @@ impl Path {
 #[derive(Clone)]
 pub enum Ty {
     Self_,
-    /// &/Box/ Ty
-    Ptr(Box<Ty>, PtrTy),
+    /// A reference.
+    Ref(Box<Ty>, ast::Mutability),
     /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
     /// parameter, and things like `i32`
-    Literal(Path),
-    /// includes unit
-    Tuple(Vec<Ty>),
-}
-
-pub fn borrowed_ptrty() -> PtrTy {
-    Borrowed(None, ast::Mutability::Not)
-}
-pub fn borrowed(ty: Box<Ty>) -> Ty {
-    Ptr(ty, borrowed_ptrty())
-}
-
-pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
-    Some(Some(borrowed_ptrty()))
-}
-
-pub fn borrowed_self() -> Ty {
-    borrowed(Box::new(Self_))
+    Path(Path),
+    /// For () return types.
+    Unit,
 }
 
-pub fn nil_ty() -> Ty {
-    Tuple(Vec::new())
-}
-
-fn mk_lifetime(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Option<ast::Lifetime> {
-    lt.map(|ident| cx.lifetime(span, ident))
-}
-
-fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Lifetime> {
-    mk_lifetime(cx, span, lt).into_iter().collect()
+pub fn self_ref() -> Ty {
+    Ref(Box::new(Self_), ast::Mutability::Not)
 }
 
 impl Ty {
@@ -136,23 +94,15 @@ impl Ty {
         self_ty: Ident,
         self_generics: &Generics,
     ) -> P<ast::Ty> {
-        match *self {
-            Ptr(ref ty, ref ptr) => {
+        match self {
+            Ref(ty, mutbl) => {
                 let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
-                match *ptr {
-                    Borrowed(ref lt, mutbl) => {
-                        let lt = mk_lifetime(cx, span, lt);
-                        cx.ty_rptr(span, raw_ty, lt, mutbl)
-                    }
-                    Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
-                }
+                cx.ty_rptr(span, raw_ty, None, *mutbl)
             }
-            Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
+            Path(p) => p.to_ty(cx, span, self_ty, self_generics),
             Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
-            Tuple(ref fields) => {
-                let ty = ast::TyKind::Tup(
-                    fields.iter().map(|f| f.to_ty(cx, span, self_ty, self_generics)).collect(),
-                );
+            Unit => {
+                let ty = ast::TyKind::Tup(vec![]);
                 cx.ty(span, ty)
             }
         }
@@ -185,9 +135,9 @@ impl Ty {
 
                 cx.path_all(span, false, vec![self_ty], params)
             }
-            Literal(ref p) => p.to_path(cx, span, self_ty, generics),
-            Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
-            Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
+            Path(ref p) => p.to_path(cx, span, self_ty, generics),
+            Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"),
+            Unit => cx.span_bug(span, "unit in a path in generic `derive`"),
         }
     }
 }
@@ -245,28 +195,10 @@ impl Bounds {
     }
 }
 
-pub fn get_explicit_self(
-    cx: &ExtCtxt<'_>,
-    span: Span,
-    self_ptr: &Option<PtrTy>,
-) -> (P<Expr>, ast::ExplicitSelf) {
+pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
     // this constructs a fresh `self` path
     let self_path = cx.expr_self(span);
-    match *self_ptr {
-        None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Not))),
-        Some(ref ptr) => {
-            let self_ty = respan(
-                span,
-                match *ptr {
-                    Borrowed(ref lt, mutbl) => {
-                        let lt = lt.map(|s| cx.lifetime(span, s));
-                        SelfKind::Region(lt, mutbl)
-                    }
-                    Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition"),
-                },
-            );
-            let self_expr = cx.expr_deref(span, self_path);
-            (self_expr, self_ty)
-        }
-    }
+    let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
+    let self_expr = cx.expr_deref(span, self_path);
+    (self_expr, self_ty)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index f1d46f03bad..9790449c4b3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -15,7 +15,7 @@ pub fn expand_deriving_hash(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let path = Path::new_(pathvec_std!(hash::Hash), None, vec![], PathKind::Std);
+    let path = Path::new_(pathvec_std!(hash::Hash), vec![], PathKind::Std);
 
     let typaram = sym::__H;
 
@@ -26,16 +26,14 @@ pub fn expand_deriving_hash(
         path,
         additional_bounds: Vec::new(),
         generics: Bounds::empty(),
-        is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
             name: sym::hash,
             generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] },
-            explicit_self: borrowed_explicit_self(),
-            args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), sym::state)],
-            ret_ty: nil_ty(),
+            explicit_self: true,
+            args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
+            ret_ty: Unit,
             attributes: vec![],
-            is_unsafe: false,
             unify_fieldless_variants: true,
             combine_substructure: combine_substructure(Box::new(|a, b, c| {
                 hash_substructure(a, b, c)
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 09a2977af04..0dac4f8978e 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -19,11 +19,9 @@ use rustc_target::abi::{self, Abi};
 use std::borrow::Cow;
 use std::convert::TryInto;
 
-pub fn note_on_undefined_behavior_error() -> &'static str {
-    "The rules on what exactly is undefined behavior aren't clear, \
+const NOTE_ON_UNDEFINED_BEHAVIOR_ERROR: &str = "The rules on what exactly is undefined behavior aren't clear, \
      so this check might be overzealous. Please open an issue on the rustc \
-     repository if you believe it should not be considered undefined behavior."
-}
+     repository if you believe it should not be considered undefined behavior.";
 
 // Returns a pointer to where the result lives
 fn eval_body_using_ecx<'mir, 'tcx>(
@@ -375,7 +373,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                     ecx.tcx,
                     "it is undefined behavior to use this value",
                     |diag| {
-                        diag.note(note_on_undefined_behavior_error());
+                        diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR);
                         diag.note(&format!(
                             "the raw bytes of the constant ({}",
                             display_allocation(
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 8266f1566c4..c0cf8c6b76b 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1098,12 +1098,12 @@ impl EarlyLintPass for UnusedDocComment {
     }
 
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-        warn_if_doc(cx, block.span, "block", &block.attrs());
+        warn_if_doc(cx, block.span, "blocks", &block.attrs());
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
         if let ast::ItemKind::ForeignMod(_) = item.kind {
-            warn_if_doc(cx, item.span, "extern block", &item.attrs);
+            warn_if_doc(cx, item.span, "extern blocks", &item.attrs);
         }
     }
 }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index eec3b24aec2..37958cc0f40 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -38,7 +38,9 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::astconv_object_safety_violations;
-use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
+use rustc_trait_selection::traits::error_reporting::{
+    report_object_safety_error, suggestions::NextTypeParamName,
+};
 use rustc_trait_selection::traits::wf::object_region_bounds;
 
 use smallvec::SmallVec;
@@ -2986,6 +2988,50 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         Some(r)
     }
 
+    /// Make sure that we are in the condition to suggest the blanket implementation.
+    fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
+        &self,
+        self_ty: &hir::Ty<'_>,
+        diag: &mut DiagnosticBuilder<'_, T>,
+    ) {
+        let tcx = self.tcx();
+        let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
+        if let hir::Node::Item(hir::Item {
+            kind:
+                hir::ItemKind::Impl(hir::Impl {
+                    self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
+                }),
+            ..
+        }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
+        {
+            if !of_trait_ref.trait_def_id().map_or(false, |def_id| def_id.is_local()) {
+                return;
+            }
+            let of_trait_span = of_trait_ref.path.span;
+            // make sure that we are not calling unwrap to abort during the compilation
+            let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
+            let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
+            // check if the trait has generics, to make a correct suggestion
+            let param_name = generics.params.next_type_param_name(None);
+
+            let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
+                (span, format!(", {}: {}", param_name, impl_trait_name))
+            } else {
+                (generics.span, format!("<{}: {}>", param_name, impl_trait_name))
+            };
+            diag.multipart_suggestion(
+            format!("alternatively use a blanket \
+                     implementation to implement `{of_trait_name}` for \
+                     all types that also implement `{impl_trait_name}`"),
+                vec![
+                    (self_ty.span, param_name),
+                    add_generic_sugg,
+                ],
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
         let tcx = self.tcx();
         if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
@@ -3021,9 +3067,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             if self_ty.span.edition() >= Edition::Edition2021 {
                 let msg = "trait objects must include the `dyn` keyword";
                 let label = "add `dyn` keyword before this trait";
-                rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg)
-                    .multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable)
-                    .emit();
+                let mut diag =
+                    rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
+                diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+                // check if the impl trait that we are considering is a impl of a local trait
+                self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
+                diag.emit();
             } else {
                 let msg = "trait objects without an explicit `dyn` are deprecated";
                 tcx.struct_span_lint_hir(
@@ -3031,13 +3080,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     self_ty.hir_id,
                     self_ty.span,
                     |lint| {
-                        lint.build(msg)
-                            .multipart_suggestion_verbose(
-                                "use `dyn`",
-                                sugg,
-                                Applicability::MachineApplicable,
-                            )
-                            .emit();
+                        let mut diag = lint.build(msg);
+                        diag.multipart_suggestion_verbose(
+                            "use `dyn`",
+                            sugg,
+                            Applicability::MachineApplicable,
+                        );
+                        self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
+                        diag.emit();
                     },
                 );
             }
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 0837d9c4a20..87f85a9842f 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -1707,12 +1707,14 @@ fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: hir::HirId) -> Span {
         hir::Node::Item(item) => match item.kind {
             hir::ItemKind::Fn(_, _, owner_id) => tcx.hir().span(owner_id.hir_id),
             _ => {
-                bug!("Drop location span error: need to handle more ItemKind {:?}", item.kind);
+                bug!("Drop location span error: need to handle more ItemKind '{:?}'", item.kind);
             }
         },
         hir::Node::Block(block) => tcx.hir().span(block.hir_id),
+        hir::Node::TraitItem(item) => tcx.hir().span(item.hir_id()),
+        hir::Node::ImplItem(item) => tcx.hir().span(item.hir_id()),
         _ => {
-            bug!("Drop location span error: need to handle more Node {:?}", owner_node);
+            bug!("Drop location span error: need to handle more Node '{:?}'", owner_node);
         }
     };
     tcx.sess.source_map().end_point(owner_span)
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 09308d4d090..649ccfcaa9e 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -31,7 +31,9 @@ use core::ptr::{self, NonNull};
 /// ```
 #[unstable(feature = "thin_box", issue = "92791")]
 pub struct ThinBox<T: ?Sized> {
-    ptr: WithHeader<<T as Pointee>::Metadata>,
+    // This is essentially `WithHeader<<T as Pointee>::Metadata>`,
+    // but that would be invariant in `T`, and we want covariance.
+    ptr: WithOpaqueHeader,
     _marker: PhantomData<T>,
 }
 
@@ -59,7 +61,7 @@ impl<T> ThinBox<T> {
     #[cfg(not(no_global_oom_handling))]
     pub fn new(value: T) -> Self {
         let meta = ptr::metadata(&value);
-        let ptr = WithHeader::new(meta, value);
+        let ptr = WithOpaqueHeader::new(meta, value);
         ThinBox { ptr, _marker: PhantomData }
     }
 }
@@ -83,7 +85,7 @@ impl<Dyn: ?Sized> ThinBox<Dyn> {
         T: Unsize<Dyn>,
     {
         let meta = ptr::metadata(&value as &Dyn);
-        let ptr = WithHeader::new(meta, value);
+        let ptr = WithOpaqueHeader::new(meta, value);
         ThinBox { ptr, _marker: PhantomData }
     }
 }
@@ -130,7 +132,7 @@ impl<T: ?Sized> Drop for ThinBox<T> {
         unsafe {
             let value = self.deref_mut();
             let value = value as *mut T;
-            self.ptr.drop::<T>(value);
+            self.with_header().drop::<T>(value);
         }
     }
 }
@@ -140,11 +142,16 @@ impl<T: ?Sized> ThinBox<T> {
     fn meta(&self) -> <T as Pointee>::Metadata {
         //  Safety:
         //  -   NonNull and valid.
-        unsafe { *self.ptr.header() }
+        unsafe { *self.with_header().header() }
     }
 
     fn data(&self) -> *mut u8 {
-        self.ptr.value()
+        self.with_header().value()
+    }
+
+    fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata> {
+        // SAFETY: both types are transparent to `NonNull<u8>`
+        unsafe { &*((&self.ptr) as *const WithOpaqueHeader as *const WithHeader<_>) }
     }
 }
 
@@ -153,8 +160,22 @@ impl<T: ?Sized> ThinBox<T> {
 ///    metadata (`H`) are ZSTs.
 /// 2. A pointer to a valid `T` that has a header `H` directly before the
 ///    pointed-to location.
+#[repr(transparent)]
 struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
 
+/// An opaque representation of `WithHeader<H>` to avoid the
+/// projection invariance of `<T as Pointee>::Metadata`.
+#[repr(transparent)]
+struct WithOpaqueHeader(NonNull<u8>);
+
+impl WithOpaqueHeader {
+    #[cfg(not(no_global_oom_handling))]
+    fn new<H, T>(header: H, value: T) -> Self {
+        let ptr = WithHeader::new(header, value);
+        Self(ptr.0)
+    }
+}
+
 impl<H> WithHeader<H> {
     #[cfg(not(no_global_oom_handling))]
     fn new<T>(header: H, value: T) -> WithHeader<H> {
diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs
index 70d1db8b457..368aa564f94 100644
--- a/library/alloc/tests/thin_box.rs
+++ b/library/alloc/tests/thin_box.rs
@@ -26,6 +26,13 @@ fn want_thin() {
     assert!(is_thin::<i32>());
 }
 
+#[allow(dead_code)]
+fn assert_covariance() {
+    fn thin_box<'new>(b: ThinBox<[&'static str]>) -> ThinBox<[&'new str]> {
+        b
+    }
+}
+
 #[track_caller]
 fn verify_aligned<T>(ptr: *const T) {
     // Use `black_box` to attempt to obscure the fact that we're calling this
diff --git a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr
index 30a96af583a..1a022c30938 100644
--- a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr
+++ b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr
@@ -71,7 +71,7 @@ LL |
 LL | / extern "C" {
 LL | |     fn foo();
 LL | | }
-   | |_- rustdoc does not generate documentation for extern block
+   | |_- rustdoc does not generate documentation for extern blocks
    |
    = help: use `//` for a plain comment
 
diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs
new file mode 100644
index 00000000000..b280c8ab6e2
--- /dev/null
+++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs
@@ -0,0 +1,18 @@
+// compile-flags: -Wrust-2021-incompatible-closure-captures
+
+pub struct A {}
+
+impl A {
+    async fn create(path: impl AsRef<std::path::Path>)  { //~ ERROR  `async fn` is not permitted in Rust 2015
+    //~^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
+    ;
+    crate(move || {} ).await //~ ERROR expected function, found module `crate`
+    }
+}
+
+trait C{async fn new(val: T) {} //~ ERROR  `async fn` is not permitted in Rust 2015
+//~^ ERROR functions in traits cannot be declared `async`
+//~^^ ERROR cannot find type `T` in this scope
+//~^^^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
+
+//~ ERROR  this file contains an unclosed delimiter
diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
new file mode 100644
index 00000000000..50de2322907
--- /dev/null
+++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
@@ -0,0 +1,93 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:18:53
+   |
+LL | trait C{async fn new(val: T) {}
+   |        - unclosed delimiter
+...
+LL |
+   |                                                     ^
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:5
+   |
+LL |     async fn create(path: impl AsRef<std::path::Path>)  {
+   |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
+   |
+LL | trait C{async fn new(val: T) {}
+   |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
+   |
+LL | trait C{async fn new(val: T) {}
+   |         -----^^^^^^^^^^^^^^^^^^
+   |         |
+   |         `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+error[E0423]: expected function, found module `crate`
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:9:5
+   |
+LL |     crate(move || {} ).await
+   |     ^^^^^ not a function
+
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:27
+   |
+LL | pub struct A {}
+   | ------------ similarly named struct `A` defined here
+...
+LL | trait C{async fn new(val: T) {}
+   |                           ^ help: a struct with a similar name exists: `A`
+
+warning: changes to closure capture in Rust 2021 will affect drop order
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:57
+   |
+LL |       async fn create(path: impl AsRef<std::path::Path>)  {
+   |  _____________________----_____________________________-__^
+   | |                     |                                |
+   | |                     |                                in Rust 2018, `path` is dropped here along with the closure, but in Rust 2021 `path` is not part of the closure
+   | |                     in Rust 2018, this causes the closure to capture `path`, but in Rust 2021, it has no effect
+LL | |
+LL | |     ;
+LL | |     crate(move || {} ).await
+LL | |     }
+   | |_____^
+   |
+   = note: requested on the command line with `-W rust-2021-incompatible-closure-captures`
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `path` to be fully captured
+   |
+LL |     async fn create(path: impl AsRef<std::path::Path>)  { let _ = &path;
+   |                                                           ++++++++++++++
+
+warning: changes to closure capture in Rust 2021 will affect drop order
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30
+   |
+LL | trait C{async fn new(val: T) {}
+   |                      ---   - ^^
+   |                      |     |
+   |                      |     in Rust 2018, `val` is dropped here along with the closure, but in Rust 2021 `val` is not part of the closure
+   |                      in Rust 2018, this causes the closure to capture `val`, but in Rust 2021, it has no effect
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `val` to be fully captured
+   |
+LL | trait C{async fn new(val: T) { let _ = &val;}
+   |                                +++++++++++++
+
+error: aborting due to 6 previous errors; 2 warnings emitted
+
+Some errors have detailed explanations: E0412, E0423, E0670, E0706.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
new file mode 100644
index 00000000000..a776e508907
--- /dev/null
+++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
@@ -0,0 +1,15 @@
+// compile-flags -Wrust-2021-incompatible-closure-captures
+
+fn main() {}
+
+pub(crate) struct Numberer {}
+
+impl Numberer {
+    pub(crate) async fn new(
+    //~^ ERROR `async fn` is not permitted in Rust 2015
+        interval: Duration,
+        //~^ ERROR cannot find type `Duration` in this scope
+    ) -> Numberer {
+        Numberer {}
+    }
+}
diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
new file mode 100644
index 00000000000..37b2f413860
--- /dev/null
+++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
@@ -0,0 +1,24 @@
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:8:16
+   |
+LL |     pub(crate) async fn new(
+   |                ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0412]: cannot find type `Duration` in this scope
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:10:19
+   |
+LL |         interval: Duration,
+   |                   ^^^^^^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL | use std::time::Duration;
+   |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0412, E0670.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs
new file mode 100644
index 00000000000..7cf536f7966
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs
@@ -0,0 +1,58 @@
+// Ensure that the compiler include the blanklet implementation suggestion
+// when inside a `impl` statment are used two local traits.
+//
+// edition:2021
+use std::fmt;
+
+trait LocalTraitOne { }
+
+trait LocalTraitTwo { }
+
+trait GenericTrait<T> {}
+
+impl LocalTraitTwo for LocalTraitOne {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
+
+impl fmt::Display for LocalTraitOne {
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        todo!();
+    }
+}
+
+impl fmt::Display for LocalTraitTwo + Send {
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        todo!();
+    }
+}
+
+impl LocalTraitOne for fmt::Display {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
+
+
+impl LocalTraitOne for fmt::Display + Send {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
+
+
+impl<E> GenericTrait<E> for LocalTraitOne {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
+
+trait GenericTraitTwo<T> {}
+
+impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
+//~^ ERROR trait objects must include the `dyn` keyword
+//~| HELP add `dyn` keyword before this trait
+//~| HELP alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr
new file mode 100644
index 00000000000..d739a8272f1
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.stderr
@@ -0,0 +1,107 @@
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:13:24
+   |
+LL | impl LocalTraitTwo for LocalTraitOne {}
+   |                        ^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl LocalTraitTwo for LocalTraitOne {}
+LL + impl LocalTraitTwo for dyn LocalTraitOne {}
+   |
+help: alternatively use a blanket implementation to implement `LocalTraitTwo` for all types that also implement `LocalTraitOne`
+   |
+LL | impl<T: LocalTraitOne> LocalTraitTwo for T {}
+   |     ++++++++++++++++++                   ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:18:23
+   |
+LL | impl fmt::Display for LocalTraitOne {
+   |                       ^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl fmt::Display for LocalTraitOne {
+LL + impl fmt::Display for dyn LocalTraitOne {
+   |
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:26:23
+   |
+LL | impl fmt::Display for LocalTraitTwo + Send {
+   |                       ^^^^^^^^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl fmt::Display for LocalTraitTwo + Send {
+LL + impl fmt::Display for dyn LocalTraitTwo + Send {
+   |
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:34:24
+   |
+LL | impl LocalTraitOne for fmt::Display {}
+   |                        ^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl LocalTraitOne for fmt::Display {}
+LL + impl LocalTraitOne for dyn fmt::Display {}
+   |
+help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display`
+   |
+LL | impl<T: fmt::Display> LocalTraitOne for T {}
+   |     +++++++++++++++++                   ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:40:24
+   |
+LL | impl LocalTraitOne for fmt::Display + Send {}
+   |                        ^^^^^^^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl LocalTraitOne for fmt::Display + Send {}
+LL + impl LocalTraitOne for dyn fmt::Display + Send {}
+   |
+help: alternatively use a blanket implementation to implement `LocalTraitOne` for all types that also implement `fmt::Display + Send`
+   |
+LL | impl<T: fmt::Display + Send> LocalTraitOne for T {}
+   |     ++++++++++++++++++++++++                   ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:46:29
+   |
+LL | impl<E> GenericTrait<E> for LocalTraitOne {}
+   |                             ^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl<E> GenericTrait<E> for LocalTraitOne {}
+LL + impl<E> GenericTrait<E> for dyn LocalTraitOne {}
+   |
+help: alternatively use a blanket implementation to implement `GenericTrait<E>` for all types that also implement `LocalTraitOne`
+   |
+LL | impl<E, T: LocalTraitOne> GenericTrait<E> for T {}
+   |       ++++++++++++++++++                      ~
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/suggest-blanket-impl-local-trait.rs:53:35
+   |
+LL | impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
+   |                                   ^^^^^^^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - impl<T, E> GenericTraitTwo<E> for GenericTrait<T> {}
+LL + impl<T, E> GenericTraitTwo<E> for dyn GenericTrait<T> {}
+   |
+help: alternatively use a blanket implementation to implement `GenericTraitTwo<E>` for all types that also implement `GenericTrait<T>`
+   |
+LL | impl<T, E, U: GenericTrait<T>> GenericTraitTwo<E> for U {}
+   |          ++++++++++++++++++++                         ~
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0782`.
diff --git a/suggest-blanket-impl-local-trait b/suggest-blanket-impl-local-trait
new file mode 100755
index 00000000000..0a357e006c3
--- /dev/null
+++ b/suggest-blanket-impl-local-trait
Binary files differ