diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 243313ee8767a..87300f5bb83c6 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -77,12 +77,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics.
         let mut prior_arm = None;
         for arm in arms {
+            self.diverges.set(Diverges::Maybe);
+
             if let Some(e) = &arm.guard {
-                self.diverges.set(Diverges::Maybe);
                 self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {});
+
+                // FIXME: If this is the first arm and the pattern is irrefutable,
+                // e.g. `_` or `x`, and the guard diverges, then the whole match
+                // may also be considered to diverge. We should warn on all subsequent
+                // arms, too, just like we do for diverging scrutinees above.
             }
 
-            self.diverges.set(Diverges::Maybe);
+            // N.B. We don't reset diverges here b/c we want to warn in the arm
+            // if the guard diverges, like: `x if { loop {} } => f()`, and we
+            // also want to consider the arm to diverge itself.
 
             let arm_ty = self.check_expr_with_expectation(arm.body, expected);
             all_arms_diverge &= self.diverges.get();
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8e89331ef03c3..9fe1caa4b58f5 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -841,6 +841,12 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     p!(
                         " upvar_tys=",
                         print(args.as_coroutine().tupled_upvars_ty()),
+                        " resume_ty=",
+                        print(args.as_coroutine().resume_ty()),
+                        " yield_ty=",
+                        print(args.as_coroutine().yield_ty()),
+                        " return_ty=",
+                        print(args.as_coroutine().return_ty()),
                         " witness=",
                         print(args.as_coroutine().witness())
                     );
diff --git a/src/doc/unstable-book/src/language-features/arbitrary-self-types-pointers.md b/src/doc/unstable-book/src/language-features/arbitrary-self-types-pointers.md
new file mode 100644
index 0000000000000..f73bcaffa8003
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/arbitrary-self-types-pointers.md
@@ -0,0 +1,57 @@
+# `arbitrary_self_types_pointers`
+
+The tracking issue for this feature is: [#44874]
+
+[#38788]: https://github.com/rust-lang/rust/issues/44874
+
+------------------------
+
+This extends the [arbitrary self types] feature to allow methods to
+receive `self` by pointer. For example:
+
+```rust
+#![feature(arbitrary_self_types_pointers)]
+
+struct A;
+
+impl A {
+    fn m(self: *const Self) {}
+}
+
+fn main() {
+    let a = A;
+    let a_ptr: *const A = &a as *const A;
+    a_ptr.m();
+}
+```
+
+In general this is not advised: it's thought to be better practice to wrap
+raw pointers in a newtype wrapper which implements the `core::ops::Receiver`
+trait, then you need "only" the `arbitrary_self_types` feature. For example:
+
+```rust
+#![feature(arbitrary_self_types)]
+#![allow(dead_code)]
+
+struct A;
+
+impl A {
+    fn m(self: Wrapper<Self>) {} // can extract the pointer and do
+        // what it needs
+}
+
+struct Wrapper<T>(*const T);
+
+impl<T> core::ops::Receiver for Wrapper<T> {
+    type Target = T;
+}
+
+fn main() {
+    let a = A;
+    let a_ptr: *const A = &a as *const A;
+    let a_wrapper = Wrapper(a_ptr);
+    a_wrapper.m();
+}
+```
+
+[arbitrary self types]: arbitrary-self-types.md
diff --git a/src/doc/unstable-book/src/language-features/arbitrary-self-types.md b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md
new file mode 100644
index 0000000000000..2f8b52d404393
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md
@@ -0,0 +1,154 @@
+# `arbitrary_self_types`
+
+The tracking issue for this feature is: [#44874]
+
+[#38788]: https://github.com/rust-lang/rust/issues/44874
+
+------------------------
+
+Allows any type implementing `core::ops::Receiver<Target=T>` to be used as the type
+of `self` in a method belonging to `T`.
+
+For example,
+
+```rust
+#![feature(arbitrary_self_types)]
+
+struct A;
+
+impl A {
+    fn f(self: SmartPtr<Self>) -> i32 { 1 }  // note self type
+}
+
+struct SmartPtr<T>(T);
+
+impl<T> core::ops::Receiver for SmartPtr<T> {
+    type Target = T;
+}
+
+fn main() {
+    let smart_ptr = SmartPtr(A);
+    assert_eq!(smart_ptr.f(), 1);
+}
+```
+
+The `Receiver` trait has a blanket implementation for all `T: Deref`, so in fact
+things like this work too:
+
+```rust
+#![feature(arbitrary_self_types)]
+
+use std::rc::Rc;
+
+struct A;
+
+impl A {
+    fn f(self: Rc<Self>) -> i32 { 1 } // Rc implements Deref
+}
+
+fn main() {
+    let smart_ptr = Rc::new(A);
+    assert_eq!(smart_ptr.f(), 1);
+}
+```
+
+Interestingly, that works even without the `arbitrary_self_types` feature
+- but that's because certain types are _effectively_ hard coded, including
+`Rc`. ("Hard coding" isn't quite true; they use a lang-item called
+`LegacyReceiver` to denote their special-ness in this way). With the
+`arbitrary_self_types` feature, their special-ness goes away, and custom
+smart pointers can achieve the same.
+
+## Changes to method lookup
+
+Method lookup previously used to work by stepping through the `Deref`
+chain then using the resulting list of steps in two different ways:
+
+* To identify types that might contribute methods via their `impl`
+  blocks (inherent methods) or via traits
+* To identify the types that the method receiver (`a` in the above
+  examples) can be converted to.
+
+With this feature, these lists are created by instead stepping through
+the `Receiver` chain. However, a note is kept about whether the type
+can be reached also via the `Deref` chain.
+
+The full chain (via `Receiver` hops) is used for the first purpose
+(identifying relevant `impl` blocks and traits); whereas the shorter
+list (reachable via `Deref`) is used for the second purpose. That's
+because, to convert the method target (`a` in `a.b()`) to the self
+type, Rust may need to be able to use `Deref::deref`. Type conversions,
+then, can only proceed as far as the end of the `Deref` chain whereas
+the longer `Receiver` chain can be used to explore more places where
+useful methods might reside.
+
+## Types suitable for use as smart pointers
+
+This feature allows the creation of customised smart pointers - for example
+your own equivalent to `Rc` or `Box` with whatever capabilities you like.
+Those smart pointers can either implement `Deref` (if it's safe to
+create a reference to the referent) or `Receiver` (if it isn't).
+
+Either way, smart pointer types should mostly _avoid having methods_.
+Calling methods on a smart pointer leads to ambiguity about whether you're
+aiming for a method on the pointer, or on the referent.
+
+Best practice is therefore to put smart pointer functionality into
+associated functions instead - that's what's done in all the smart pointer
+types within Rust's standard library which implement `Receiver`.
+
+If you choose to add any methods to your smart pointer type, your users
+may run into errors from deshadowing, as described in the next section.
+
+## Avoiding shadowing
+
+With or without this feature, Rust emits an error if it finds two method
+candidates, like this:
+
+```rust,compile_fail
+use std::pin::Pin;
+use std::pin::pin;
+
+struct A;
+
+impl A {
+    fn get_ref(self: Pin<&A>) {}
+}
+
+fn main() {
+    let pinned_a: Pin<&A> = pin!(A).as_ref();
+    let pinned_a: Pin<&A> = pinned_a.as_ref();
+    pinned_a.get_ref(); // error[E0034]: multiple applicable items in scope
+}
+```
+
+(this is why Rust's smart pointers are mostly carefully designed to avoid
+having methods at all, and shouldn't add new methods in future.)
+
+With `arbitrary_self_types`, we take care to spot some other kinds of
+conflict:
+
+```rust,compile_fail
+#![feature(arbitrary_self_types)]
+
+use std::pin::Pin;
+use std::pin::pin;
+
+struct A;
+
+impl A {
+    fn get_ref(self: &Pin<&A>) {}  // note &Pin
+}
+
+fn main() {
+    let pinned_a: Pin<&mut A> = pin!(A);
+    let pinned_a: Pin<&A> = pinned_a.as_ref();
+    pinned_a.get_ref();
+}
+```
+
+This is to guard against the case where an inner (referent) type has a
+method of a given name, taking the smart pointer by reference, and then
+the smart pointer implementer adds a similar method taking self by value.
+As noted in the previous section, the safe option is simply
+not to add methods to smart pointers, and then these errors can't occur.
diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr
index cf25b2d2d2328..13ebaf67e54ad 100644
--- a/tests/ui/async-await/async-closures/def-path.stderr
+++ b/tests/ui/async-await/async-closures/def-path.stderr
@@ -5,11 +5,11 @@ LL |     let x = async || {};
    |                      -- the expected `async` closure body
 LL |
 LL |     let () = x();
-   |         ^^   --- this expression has type `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t witness=?6t}`
+   |         ^^   --- this expression has type `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}`
    |         |
    |         expected `async` closure body, found `()`
    |
-   = note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t witness=?6t}`
+   = note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}`
                          found unit type `()`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr
index 2ab9d35f05ab9..8877d45dddad2 100644
--- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr
+++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr
@@ -9,7 +9,7 @@ LL | |         drop(a);
 LL | |     });
    | |______^ coroutine is not `Sync`
    |
-   = help: within `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`
+   = help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`
 note: coroutine is not `Sync` as this value is used across a yield
   --> $DIR/coroutine-print-verbose-2.rs:20:9
    |
@@ -34,7 +34,7 @@ LL | |         drop(a);
 LL | |     });
    | |______^ coroutine is not `Send`
    |
-   = help: within `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`
+   = help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/coroutine-print-verbose-2.rs:27:9
    |
diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr
index dce45aeae56a9..2f9f20cf1ffbf 100644
--- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr
+++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr
@@ -11,7 +11,7 @@ LL | |     };
    | |_____^ expected `()`, found coroutine
    |
    = note: expected unit type `()`
-              found coroutine `{main::{closure#0} upvar_tys=?4t witness=?6t}`
+              found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness=?6t}`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/reachable/expr_match.rs b/tests/ui/reachable/expr_match.rs
index 2fd26b54e15ee..1bae061c98421 100644
--- a/tests/ui/reachable/expr_match.rs
+++ b/tests/ui/reachable/expr_match.rs
@@ -21,9 +21,13 @@ fn d() {
 }
 
 fn e() {
-    // Here the compiler fails to figure out that the `println` is dead.
-    match () { () if return => (), () => return }
+    match () {
+        () if return => (),
+        //~^ ERROR unreachable expression
+        () => return,
+    }
     println!("I am dead");
+    //~^ ERROR unreachable statement
 }
 
 fn f() {
diff --git a/tests/ui/reachable/expr_match.stderr b/tests/ui/reachable/expr_match.stderr
index d15208609cff8..ae202a6e0c34a 100644
--- a/tests/ui/reachable/expr_match.stderr
+++ b/tests/ui/reachable/expr_match.stderr
@@ -23,5 +23,27 @@ LL |     println!("I am dead");
    |
    = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error: unreachable expression
+  --> $DIR/expr_match.rs:25:25
+   |
+LL |         () if return => (),
+   |               ------    ^^ unreachable expression
+   |               |
+   |               any code following this expression is unreachable
+
+error: unreachable statement
+  --> $DIR/expr_match.rs:29:5
+   |
+LL | /     match () {
+LL | |         () if return => (),
+LL | |
+LL | |         () => return,
+LL | |     }
+   | |_____- any code following this `match` expression is unreachable, as all arms diverge
+LL |       println!("I am dead");
+   |       ^^^^^^^^^^^^^^^^^^^^^ unreachable statement
+   |
+   = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors