From 95aac4487d1cb89913539619c201079d0fc2b463 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 11 Oct 2020 23:59:32 +0200
Subject: [PATCH 01/24] transmute_copy: explain that alignment is handled
 correctly

---
 library/core/src/mem/mod.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index a2c7da6e6958e..e84014c68a676 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -884,10 +884,10 @@ pub fn drop<T>(_x: T) {}
 /// Interprets `src` as having type `&U`, and then reads `src` without moving
 /// the contained value.
 ///
-/// This function will unsafely assume the pointer `src` is valid for
-/// [`size_of::<U>`][size_of] bytes by transmuting `&T` to `&U` and then reading
-/// the `&U`. It will also unsafely create a copy of the contained value instead of
-/// moving out of `src`.
+/// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of]
+/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way
+/// that is correct even when `&U` makes stricter alignment requirements than `&T`). It will also
+/// unsafely create a copy of the contained value instead of moving out of `src`.
 ///
 /// It is not a compile-time error if `T` and `U` have different sizes, but it
 /// is highly encouraged to only invoke this function where `T` and `U` have the

From 08d5e9673677d5874484b2f9837a42db9fea9331 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= <tomasz.miasko@gmail.com>
Date: Tue, 20 Oct 2020 00:00:00 +0000
Subject: [PATCH 02/24] Initialize tracing subscriber in compiletest tool

The logging in compiletest was migrated from log crate to a tracing, but
the initialization code was never changed, so logging is non-functional.

Initialize tracing subscriber using default settings.
---
 Cargo.lock                        | 2 +-
 src/tools/compiletest/Cargo.toml  | 2 +-
 src/tools/compiletest/src/main.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 0d2170a992747..722632e53c75d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -639,7 +639,6 @@ name = "compiletest"
 version = "0.0.0"
 dependencies = [
  "diff",
- "env_logger 0.7.1",
  "getopts",
  "glob",
  "lazy_static",
@@ -650,6 +649,7 @@ dependencies = [
  "serde",
  "serde_json",
  "tracing",
+ "tracing-subscriber",
  "walkdir",
  "winapi 0.3.9",
 ]
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index c601084d11917..209254a5d5e2f 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -6,9 +6,9 @@ edition = "2018"
 
 [dependencies]
 diff = "0.1.10"
-env_logger = { version = "0.7", default-features = false }
 getopts = "0.2"
 tracing = "0.1"
+tracing-subscriber = { version = "0.2.13", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 regex = "1.0"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 190a9c6221060..2b2a6cfa8bd6f 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -35,7 +35,7 @@ pub mod runtest;
 pub mod util;
 
 fn main() {
-    env_logger::init();
+    tracing_subscriber::fmt::init();
 
     let config = parse_config(env::args().collect());
 

From 2ec4d82e159c7d8437721ee53645c3620aaa69b3 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Tue, 20 Oct 2020 21:26:02 +0200
Subject: [PATCH 03/24] Add issue template link to IRLO

---
 .github/ISSUE_TEMPLATE/config.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index bd7dc0ac95c1f..898b983ba3790 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -3,3 +3,6 @@ contact_links:
   - name: Rust Programming Language Forum
     url: https://users.rust-lang.org
     about: Please ask and answer questions about Rust here.
+  - name: Rust Internals Forum
+    url: https://internals.rust-lang.org/
+    about: Please discuss language feature requests here.

From 95cbfb1aa458d336a0425144117b2e5262a51380 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Tue, 20 Oct 2020 21:36:39 +0200
Subject: [PATCH 04/24] Retitle forum links

---
 .github/ISSUE_TEMPLATE/config.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 898b983ba3790..7d4cfaece4481 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,8 +1,8 @@
 blank_issues_enabled: true
 contact_links:
-  - name: Rust Programming Language Forum
+  - name: Question
     url: https://users.rust-lang.org
-    about: Please ask and answer questions about Rust here.
-  - name: Rust Internals Forum
+    about: Please ask and answer questions about Rust on the user forum.
+  - name: Feature Request
     url: https://internals.rust-lang.org/
-    about: Please discuss language feature requests here.
+    about: Please discuss language feature requests on the internals forum.

From 57d01a9aeea505b2f4b0c420e1b9975d51690ff8 Mon Sep 17 00:00:00 2001
From: Simon Vandel Sillesen <simon.vandel@gmail.com>
Date: Thu, 22 Oct 2020 22:22:17 +0200
Subject: [PATCH 05/24] Check which places are dead

Fixes #78192
---
 .../rustc_mir/src/transform/instcombine.rs    | 20 +++++++++----
 .../const_prop/ref_deref.main.ConstProp.diff  |  2 +-
 .../ref_deref_project.main.ConstProp.diff     |  2 +-
 src/test/mir-opt/inst_combine_deref.rs        |  2 +-
 src/test/mir-opt/issue-78192.rs               |  9 ++++++
 .../mir-opt/issue_78192.f.InstCombine.diff    | 29 +++++++++++++++++++
 6 files changed, 55 insertions(+), 9 deletions(-)
 create mode 100644 src/test/mir-opt/issue-78192.rs
 create mode 100644 src/test/mir-opt/issue_78192.f.InstCombine.diff

diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
index c0b3d5ff18b5c..c5c14ca7caeb5 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir/src/transform/instcombine.rs
@@ -119,11 +119,6 @@ impl OptimizationFinder<'b, 'tcx> {
     }
 
     fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> {
-        // FIXME(#78192): This optimization can result in unsoundness.
-        if !self.tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return None;
-        }
-
         // Look for the sequence
         //
         // _2 = &_1;
@@ -137,6 +132,8 @@ impl OptimizationFinder<'b, 'tcx> {
                 _ => None,
             }?;
 
+            let mut dead_locals_seen = vec![];
+
             let stmt_index = location.statement_index;
             // Look behind for statement that assigns the local from a address of operator.
             // 6 is chosen as a heuristic determined by seeing the number of times
@@ -160,6 +157,11 @@ impl OptimizationFinder<'b, 'tcx> {
                                 BorrowKind::Shared,
                                 place_taken_address_of,
                             ) => {
+                                // Make sure that the place has not been marked dead
+                                if dead_locals_seen.contains(&place_taken_address_of.local) {
+                                    return None;
+                                }
+
                                 self.optimizations
                                     .unneeded_deref
                                     .insert(location, *place_taken_address_of);
@@ -178,13 +180,19 @@ impl OptimizationFinder<'b, 'tcx> {
                     // Inline asm can do anything, so bail out of the optimization.
                     rustc_middle::mir::StatementKind::LlvmInlineAsm(_) => return None,
 
+                    // Remember `StorageDead`s, as the local being marked dead could be the
+                    // place RHS we are looking for, in which case we need to abort to avoid UB
+                    // using an uninitialized place
+                    rustc_middle::mir::StatementKind::StorageDead(dead) => {
+                        dead_locals_seen.push(*dead)
+                    }
+
                     // Check that `local_being_deref` is not being used in a mutating way which can cause misoptimization.
                     rustc_middle::mir::StatementKind::Assign(box (_, _))
                     | rustc_middle::mir::StatementKind::Coverage(_)
                     | rustc_middle::mir::StatementKind::Nop
                     | rustc_middle::mir::StatementKind::FakeRead(_, _)
                     | rustc_middle::mir::StatementKind::StorageLive(_)
-                    | rustc_middle::mir::StatementKind::StorageDead(_)
                     | rustc_middle::mir::StatementKind::Retag(_, _)
                     | rustc_middle::mir::StatementKind::AscribeUserType(_, _)
                     | rustc_middle::mir::StatementKind::SetDiscriminant { .. } => {
diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
index 4fd1b8b227649..feef65f52ebe0 100644
--- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
@@ -19,7 +19,7 @@
                                            // + span: $DIR/ref_deref.rs:5:6: 5:10
                                            // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
--         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+-         _1 = (*_4);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 +         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
index 812c7c9771801..7ec0751263fb1 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
@@ -19,7 +19,7 @@
                                            // + span: $DIR/ref_deref_project.rs:5:6: 5:17
                                            // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
-          _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
+          _1 = ((*_4).1: i32);             // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
           _0 = const ();                   // scope 0 at $DIR/ref_deref_project.rs:4:11: 6:2
diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs
index 78361c336607c..3be8c2f3ac732 100644
--- a/src/test/mir-opt/inst_combine_deref.rs
+++ b/src/test/mir-opt/inst_combine_deref.rs
@@ -1,4 +1,4 @@
-// compile-flags: -O -Zunsound-mir-opts
+// compile-flags: -O
 // EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff
 fn simple_opt() -> u64 {
     let x = 5;
diff --git a/src/test/mir-opt/issue-78192.rs b/src/test/mir-opt/issue-78192.rs
new file mode 100644
index 0000000000000..906d094f72b4a
--- /dev/null
+++ b/src/test/mir-opt/issue-78192.rs
@@ -0,0 +1,9 @@
+// EMIT_MIR issue_78192.f.InstCombine.diff
+pub fn f<T>(a: &T) -> *const T {
+    let b: &*const T = &(a as *const T);
+    *b
+}
+
+fn main() {
+    f(&2);
+}
diff --git a/src/test/mir-opt/issue_78192.f.InstCombine.diff b/src/test/mir-opt/issue_78192.f.InstCombine.diff
new file mode 100644
index 0000000000000..ec3be78525802
--- /dev/null
+++ b/src/test/mir-opt/issue_78192.f.InstCombine.diff
@@ -0,0 +1,29 @@
+- // MIR for `f` before InstCombine
++ // MIR for `f` after InstCombine
+  
+  fn f(_1: &T) -> *const T {
+      debug a => _1;                       // in scope 0 at $DIR/issue-78192.rs:2:13: 2:14
+      let mut _0: *const T;                // return place in scope 0 at $DIR/issue-78192.rs:2:23: 2:31
+      let _2: &*const T;                   // in scope 0 at $DIR/issue-78192.rs:3:9: 3:10
+      let _3: &*const T;                   // in scope 0 at $DIR/issue-78192.rs:3:24: 3:40
+      let _4: *const T;                    // in scope 0 at $DIR/issue-78192.rs:3:25: 3:40
+      scope 1 {
+          debug b => _2;                   // in scope 1 at $DIR/issue-78192.rs:3:9: 3:10
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/issue-78192.rs:3:9: 3:10
+          StorageLive(_3);                 // scope 0 at $DIR/issue-78192.rs:3:24: 3:40
+          StorageLive(_4);                 // scope 0 at $DIR/issue-78192.rs:3:25: 3:40
+          _4 = &raw const (*_1);           // scope 0 at $DIR/issue-78192.rs:3:26: 3:27
+          _3 = &_4;                        // scope 0 at $DIR/issue-78192.rs:3:24: 3:40
+-         _2 = &(*_3);                     // scope 0 at $DIR/issue-78192.rs:3:24: 3:40
++         _2 = _3;                         // scope 0 at $DIR/issue-78192.rs:3:24: 3:40
+          StorageDead(_3);                 // scope 0 at $DIR/issue-78192.rs:3:40: 3:41
+          _0 = (*_2);                      // scope 1 at $DIR/issue-78192.rs:4:5: 4:7
+          StorageDead(_4);                 // scope 0 at $DIR/issue-78192.rs:5:1: 5:2
+          StorageDead(_2);                 // scope 0 at $DIR/issue-78192.rs:5:1: 5:2
+          return;                          // scope 0 at $DIR/issue-78192.rs:5:2: 5:2
+      }
+  }
+  

From 3815c6abbaf077fbfe798578953dbe332090917e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A1niel=20Buga?= <bugadani@gmail.com>
Date: Fri, 23 Oct 2020 00:12:20 +0200
Subject: [PATCH 06/24] Add codegen test for #45964

---
 .../issue-45964-bounds-check-slice-pos.rs     | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 src/test/codegen/issue-45964-bounds-check-slice-pos.rs

diff --git a/src/test/codegen/issue-45964-bounds-check-slice-pos.rs b/src/test/codegen/issue-45964-bounds-check-slice-pos.rs
new file mode 100644
index 0000000000000..aa59c713b7846
--- /dev/null
+++ b/src/test/codegen/issue-45964-bounds-check-slice-pos.rs
@@ -0,0 +1,38 @@
+// This test case checks that slice::{r}position functions do not
+// prevent optimizing away bounds checks
+
+// compile-flags: -O
+
+#![crate_type="rlib"]
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test(y: &[u32], x: &u32, z: &u32) -> bool {
+    let result = match y.iter().position(|a| a == x) {
+        Some(p) => Ok(p),
+        None => Err(()),
+    };
+
+    if let Ok(p) = result {
+        // CHECK-NOT: panic
+        y[p] == *z
+    } else {
+        false
+    }
+}
+
+// CHECK-LABEL: @rtest
+#[no_mangle]
+pub fn rtest(y: &[u32], x: &u32, z: &u32) -> bool {
+    let result = match y.iter().rposition(|a| a == x) {
+        Some(p) => Ok(p),
+        None => Err(()),
+    };
+
+    if let Ok(p) = result {
+        // CHECK-NOT: panic
+        y[p] == *z
+    } else {
+        false
+    }
+}

From 86df9039b2a49dde3a2453d75c4c58540a568a1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 21 Oct 2020 14:25:09 -0700
Subject: [PATCH 07/24] Tweak "use `.await`" suggestion

---
 .../src/traits/error_reporting/suggestions.rs  | 10 +++++-----
 .../src/check/fn_ctxt/suggestions.rs           | 16 ++++++----------
 .../incorrect-syntax-suggestions.stderr        |  9 +++++----
 src/test/ui/async-await/issue-61076.stderr     | 18 ++++++++++--------
 .../suggest-missing-await-closure.fixed        |  4 ++--
 .../suggest-missing-await-closure.rs           |  4 ++--
 .../suggest-missing-await-closure.stderr       |  9 +++++----
 .../ui/async-await/suggest-missing-await.fixed |  8 ++++----
 .../ui/async-await/suggest-missing-await.rs    |  8 ++++----
 .../async-await/suggest-missing-await.stderr   | 13 +++++++------
 src/test/ui/suggestions/issue-72766.stderr     |  9 +++++----
 11 files changed, 55 insertions(+), 53 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index efa9bd633ba8c..fa837e04db35e 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use std::fmt;
 
@@ -2114,10 +2114,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if self.predicate_may_hold(&try_obligation) && impls_future {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                         if snippet.ends_with('?') {
-                            err.span_suggestion(
-                                span,
-                                "consider using `.await` here",
-                                format!("{}.await?", snippet.trim_end_matches('?')),
+                            err.span_suggestion_verbose(
+                                span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
+                                "consider `await`ing on the `Future`",
+                                ".await".to_string(),
                                 Applicability::MaybeIncorrect,
                             );
                         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 9bad02c41b4b1..18db8d63850b2 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -497,16 +497,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 if self.infcx.predicate_may_hold(&obligation) {
                     debug!("suggest_missing_await: obligation held: {:?}", obligation);
-                    if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
-                        err.span_suggestion(
-                            sp,
-                            "consider using `.await` here",
-                            format!("{}.await", code),
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        debug!("suggest_missing_await: no snippet for {:?}", sp);
-                    }
+                    err.span_suggestion_verbose(
+                        sp.shrink_to_hi(),
+                        "consider `await`ing on the `Future`",
+                        ".await".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
                 } else {
                     debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
                 }
diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
index 6a653fc060b1d..d90ce0f1bb482 100644
--- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
+++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
@@ -237,13 +237,14 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
   --> $DIR/incorrect-syntax-suggestions.rs:16:19
    |
 LL |     let _ = await bar()?;
-   |                   ^^^^^^
-   |                   |
-   |                   the `?` operator cannot be applied to type `impl Future`
-   |                   help: consider using `.await` here: `bar().await?`
+   |                   ^^^^^^ the `?` operator cannot be applied to type `impl Future`
    |
    = help: the trait `Try` is not implemented for `impl Future`
    = note: required by `into_result`
+help: consider `await`ing on the `Future`
+   |
+LL |     let _ = await bar().await?;
+   |                        ^^^^^^
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
   --> $DIR/incorrect-syntax-suggestions.rs:63:19
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
index 88ea7251eaf1f..afba889f014fe 100644
--- a/src/test/ui/async-await/issue-61076.stderr
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -2,25 +2,27 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
   --> $DIR/issue-61076.rs:42:5
    |
 LL |     foo()?;
-   |     ^^^^^^
-   |     |
-   |     the `?` operator cannot be applied to type `impl Future`
-   |     help: consider using `.await` here: `foo().await?`
+   |     ^^^^^^ the `?` operator cannot be applied to type `impl Future`
    |
    = help: the trait `Try` is not implemented for `impl Future`
    = note: required by `into_result`
+help: consider `await`ing on the `Future`
+   |
+LL |     foo().await?;
+   |          ^^^^^^
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
   --> $DIR/issue-61076.rs:56:5
    |
 LL |     t?;
-   |     ^^
-   |     |
-   |     the `?` operator cannot be applied to type `T`
-   |     help: consider using `.await` here: `t.await?`
+   |     ^^ the `?` operator cannot be applied to type `T`
    |
    = help: the trait `Try` is not implemented for `T`
    = note: required by `into_result`
+help: consider `await`ing on the `Future`
+   |
+LL |     t.await?;
+   |      ^^^^^^
 
 error[E0609]: no field `0` on type `impl Future`
   --> $DIR/issue-61076.rs:58:26
diff --git a/src/test/ui/async-await/suggest-missing-await-closure.fixed b/src/test/ui/async-await/suggest-missing-await-closure.fixed
index 37b30ffe6800f..febcd02184261 100644
--- a/src/test/ui/async-await/suggest-missing-await-closure.fixed
+++ b/src/test/ui/async-await/suggest-missing-await-closure.fixed
@@ -15,8 +15,8 @@ async fn suggest_await_in_async_closure() {
         let x = make_u32();
         take_u32(x.await)
         //~^ ERROR mismatched types [E0308]
-        //~| HELP consider using `.await` here
-        //~| SUGGESTION x.await
+        //~| HELP consider `await`ing on the `Future`
+        //~| SUGGESTION .await
     };
 }
 
diff --git a/src/test/ui/async-await/suggest-missing-await-closure.rs b/src/test/ui/async-await/suggest-missing-await-closure.rs
index 18076a1516171..faabf6ee3f16f 100644
--- a/src/test/ui/async-await/suggest-missing-await-closure.rs
+++ b/src/test/ui/async-await/suggest-missing-await-closure.rs
@@ -15,8 +15,8 @@ async fn suggest_await_in_async_closure() {
         let x = make_u32();
         take_u32(x)
         //~^ ERROR mismatched types [E0308]
-        //~| HELP consider using `.await` here
-        //~| SUGGESTION x.await
+        //~| HELP consider `await`ing on the `Future`
+        //~| SUGGESTION .await
     };
 }
 
diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr
index ed2c4cbfccc98..2151057aa7fc0 100644
--- a/src/test/ui/async-await/suggest-missing-await-closure.stderr
+++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr
@@ -5,13 +5,14 @@ LL | async fn make_u32() -> u32 {
    |                        --- the `Output` of this `async fn`'s found opaque type
 ...
 LL |         take_u32(x)
-   |                  ^
-   |                  |
-   |                  expected `u32`, found opaque type
-   |                  help: consider using `.await` here: `x.await`
+   |                  ^ expected `u32`, found opaque type
    |
    = note:     expected type `u32`
            found opaque type `impl Future`
+help: consider `await`ing on the `Future`
+   |
+LL |         take_u32(x.await)
+   |                   ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed
index 1ec59d906206e..e548fda7cb4f5 100644
--- a/src/test/ui/async-await/suggest-missing-await.fixed
+++ b/src/test/ui/async-await/suggest-missing-await.fixed
@@ -12,8 +12,8 @@ async fn suggest_await_in_async_fn() {
     let x = make_u32();
     take_u32(x.await)
     //~^ ERROR mismatched types [E0308]
-    //~| HELP consider using `.await` here
-    //~| SUGGESTION x.await
+    //~| HELP consider `await`ing on the `Future`
+    //~| SUGGESTION .await
 }
 
 async fn dummy() {}
@@ -23,8 +23,8 @@ async fn suggest_await_in_async_fn_return() {
     dummy().await;
     //~^ ERROR mismatched types [E0308]
     //~| HELP try adding a semicolon
-    //~| HELP consider using `.await` here
-    //~| SUGGESTION dummy().await
+    //~| HELP consider `await`ing on the `Future`
+    //~| SUGGESTION .await
 }
 
 fn main() {}
diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs
index 70cc1f1d5a2c6..464a9602119e1 100644
--- a/src/test/ui/async-await/suggest-missing-await.rs
+++ b/src/test/ui/async-await/suggest-missing-await.rs
@@ -12,8 +12,8 @@ async fn suggest_await_in_async_fn() {
     let x = make_u32();
     take_u32(x)
     //~^ ERROR mismatched types [E0308]
-    //~| HELP consider using `.await` here
-    //~| SUGGESTION x.await
+    //~| HELP consider `await`ing on the `Future`
+    //~| SUGGESTION .await
 }
 
 async fn dummy() {}
@@ -23,8 +23,8 @@ async fn suggest_await_in_async_fn_return() {
     dummy()
     //~^ ERROR mismatched types [E0308]
     //~| HELP try adding a semicolon
-    //~| HELP consider using `.await` here
-    //~| SUGGESTION dummy().await
+    //~| HELP consider `await`ing on the `Future`
+    //~| SUGGESTION .await
 }
 
 fn main() {}
diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr
index c6355680e253b..d729420e93019 100644
--- a/src/test/ui/async-await/suggest-missing-await.stderr
+++ b/src/test/ui/async-await/suggest-missing-await.stderr
@@ -5,13 +5,14 @@ LL | async fn make_u32() -> u32 {
    |                        --- the `Output` of this `async fn`'s found opaque type
 ...
 LL |     take_u32(x)
-   |              ^
-   |              |
-   |              expected `u32`, found opaque type
-   |              help: consider using `.await` here: `x.await`
+   |              ^ expected `u32`, found opaque type
    |
    = note:     expected type `u32`
            found opaque type `impl Future`
+help: consider `await`ing on the `Future`
+   |
+LL |     take_u32(x.await)
+   |               ^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:23:5
@@ -28,10 +29,10 @@ help: try adding a semicolon
    |
 LL |     dummy();
    |            ^
-help: consider using `.await` here
+help: consider `await`ing on the `Future`
    |
 LL |     dummy().await
-   |
+   |            ^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr
index a1a5949b19660..5c9c549fa0779 100644
--- a/src/test/ui/suggestions/issue-72766.stderr
+++ b/src/test/ui/suggestions/issue-72766.stderr
@@ -2,13 +2,14 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try
   --> $DIR/issue-72766.rs:14:5
    |
 LL |     SadGirl {}.call()?;
-   |     ^^^^^^^^^^^^^^^^^^
-   |     |
-   |     the `?` operator cannot be applied to type `impl Future`
-   |     help: consider using `.await` here: `SadGirl {}.call().await?`
+   |     ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future`
    |
    = help: the trait `Try` is not implemented for `impl Future`
    = note: required by `into_result`
+help: consider `await`ing on the `Future`
+   |
+LL |     SadGirl {}.call().await?;
+   |                      ^^^^^^
 
 error: aborting due to previous error
 

From a4ee3ca1e4f1177516139a4704456958c7d08c91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 21 Oct 2020 19:08:28 -0700
Subject: [PATCH 08/24] Suggest semicolon removal on prior match arm

---
 compiler/rustc_typeck/src/check/_match.rs     |  9 +++-
 .../match-prev-arm-needing-semi.rs            | 32 +++++++++++
 .../match-prev-arm-needing-semi.stderr        | 53 +++++++++++++++++++
 3 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/suggestions/match-prev-arm-needing-semi.rs
 create mode 100644 src/test/ui/suggestions/match-prev-arm-needing-semi.stderr

diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 398e013e62fb5..94e886be54dcf 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -188,11 +188,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
             } else {
-                let (arm_span, semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind {
+                let (arm_span, mut semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind
+                {
                     self.find_block_span(blk, prior_arm_ty)
                 } else {
                     (arm.body.span, None)
                 };
+                if semi_span.is_none() && i > 0 {
+                    if let hir::ExprKind::Block(blk, _) = &arms[i - 1].body.kind {
+                        let (_, semi_span_prev) = self.find_block_span(blk, Some(arm_ty));
+                        semi_span = semi_span_prev;
+                    }
+                }
                 let (span, code) = match i {
                     // The reason for the first arm to fail is not that the match arms diverge,
                     // but rather that there's a prior obligation that doesn't hold.
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
new file mode 100644
index 0000000000000..d8d6de4bf5591
--- /dev/null
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
@@ -0,0 +1,32 @@
+// edition:2018
+
+fn dummy() -> i32 { 42 }
+
+fn extra_semicolon() {
+    let _ = match true { //~ NOTE `match` arms have incompatible types
+        true => {
+            dummy(); //~ NOTE this is found to be
+            //~^ HELP consider removing this semicolon
+        }
+        false => dummy(), //~ ERROR `match` arms have incompatible types
+        //~^ NOTE expected `()`, found `i32`
+    };
+}
+
+async fn async_dummy() {} //~ NOTE the `Output` of this `async fn`'s found opaque type
+
+async fn async_extra_semicolon_same() {
+    let _ = match true { //~ NOTE `match` arms have incompatible types
+        true => {
+            async_dummy(); //~ NOTE this is found to be
+            //~^ HELP consider removing this semicolon
+        }
+        false => async_dummy(), //~ ERROR `match` arms have incompatible types
+        //~^ NOTE expected `()`, found opaque type
+        //~| NOTE expected type `()`
+        //~| HELP consider `await`ing on the `Future`
+    };
+}
+
+fn main() {}
+
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
new file mode 100644
index 0000000000000..e242a018843a2
--- /dev/null
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
@@ -0,0 +1,53 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/match-prev-arm-needing-semi.rs:24:18
+   |
+LL |   async fn async_dummy() {}
+   |                          - the `Output` of this `async fn`'s found opaque type
+...
+LL |       let _ = match true {
+   |  _____________-
+LL | |         true => {
+LL | |             async_dummy();
+   | |             -------------- this is found to be of type `()`
+LL | |
+LL | |         }
+LL | |         false => async_dummy(),
+   | |                  ^^^^^^^^^^^^^ expected `()`, found opaque type
+...  |
+LL | |
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note:     expected type `()`
+           found opaque type `impl Future`
+help: consider removing this semicolon
+   |
+LL |             async_dummy()
+   |                         --
+help: consider `await`ing on the `Future`
+   |
+LL |         false => async_dummy().await,
+   |                               ^^^^^^
+
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/match-prev-arm-needing-semi.rs:11:18
+   |
+LL |       let _ = match true {
+   |  _____________-
+LL | |         true => {
+LL | |             dummy();
+   | |             --------
+   | |             |      |
+   | |             |      help: consider removing this semicolon
+   | |             this is found to be of type `()`
+LL | |
+LL | |         }
+LL | |         false => dummy(),
+   | |                  ^^^^^^^ expected `()`, found `i32`
+LL | |
+LL | |     };
+   | |_____- `match` arms have incompatible types
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.

From 671d7c4afb36a7dcedf9ec8a6f3ef00c19bfc260 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 21 Oct 2020 19:43:15 -0700
Subject: [PATCH 09/24] Account for possible boxable `impl Future` in semicolon
 removal suggestions

---
 .../src/infer/error_reporting/mod.rs          | 46 ++++++++++-----
 compiler/rustc_middle/src/traits/mod.rs       |  4 +-
 compiler/rustc_typeck/src/check/_match.rs     |  2 +-
 .../rustc_typeck/src/check/fn_ctxt/_impl.rs   | 57 +++++++++++++++++--
 .../rustc_typeck/src/check/fn_ctxt/checks.rs  | 23 +++++---
 .../match-prev-arm-needing-semi.rs            | 15 ++++-
 .../match-prev-arm-needing-semi.stderr        | 37 +++++++++++-
 7 files changed, 152 insertions(+), 32 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 3a0ec6327c186..f6aa3c3d5ba6b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -688,13 +688,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     };
                     let msg = "`match` arms have incompatible types";
                     err.span_label(outer_error_span, msg);
-                    if let Some(sp) = semi_span {
-                        err.span_suggestion_short(
-                            sp,
-                            "consider removing this semicolon",
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        );
+                    if let Some((sp, boxed)) = semi_span {
+                        if boxed {
+                            err.span_suggestion_verbose(
+                                sp,
+                                "consider removing this semicolon and boxing the expression",
+                                String::new(),
+                                Applicability::HasPlaceholders,
+                            );
+                        } else {
+                            err.span_suggestion_short(
+                                sp,
+                                "consider removing this semicolon",
+                                String::new(),
+                                Applicability::MachineApplicable,
+                            );
+                        }
                     }
                     if let Some(ret_sp) = opt_suggest_box_span {
                         // Get return type span and point to it.
@@ -717,13 +726,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 if let Some(sp) = outer {
                     err.span_label(sp, "`if` and `else` have incompatible types");
                 }
-                if let Some(sp) = semicolon {
-                    err.span_suggestion_short(
-                        sp,
-                        "consider removing this semicolon",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
+                if let Some((sp, boxed)) = semicolon {
+                    if boxed {
+                        err.span_suggestion_verbose(
+                            sp,
+                            "consider removing this semicolon and boxing the expression",
+                            String::new(),
+                            Applicability::HasPlaceholders,
+                        );
+                    } else {
+                        err.span_suggestion_short(
+                            sp,
+                            "consider removing this semicolon",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
                 }
                 if let Some(ret_sp) = opt_suggest_box_span {
                     self.suggest_boxing_for_return_impl_trait(
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index bbc46b8d60835..daa3010abb544 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -344,7 +344,7 @@ static_assert_size!(ObligationCauseCode<'_>, 32);
 pub struct MatchExpressionArmCause<'tcx> {
     pub arm_span: Span,
     pub scrut_span: Span,
-    pub semi_span: Option<Span>,
+    pub semi_span: Option<(Span, bool)>,
     pub source: hir::MatchSource,
     pub prior_arms: Vec<Span>,
     pub last_ty: Ty<'tcx>,
@@ -357,7 +357,7 @@ pub struct IfExpressionCause {
     pub then: Span,
     pub else_sp: Span,
     pub outer: Option<Span>,
-    pub semicolon: Option<Span>,
+    pub semicolon: Option<(Span, bool)>,
     pub opt_suggest_box_span: Option<Span>,
 }
 
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 94e886be54dcf..27c85317e82f9 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -521,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         block: &'tcx hir::Block<'tcx>,
         expected_ty: Option<Ty<'tcx>>,
-    ) -> (Span, Option<Span>) {
+    ) -> (Span, Option<(Span, bool)>) {
         if let Some(expr) = &block.expr {
             (expr.span, None)
         } else if let Some(stmt) = block.stmts.last() {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 017b0abd1d607..f26a168bcb288 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1061,7 +1061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         blk: &'tcx hir::Block<'tcx>,
         expected_ty: Ty<'tcx>,
-    ) -> Option<Span> {
+    ) -> Option<(Span, bool)> {
         // Be helpful when the user wrote `{... expr;}` and
         // taking the `;` off is enough to fix the error.
         let last_stmt = blk.stmts.last()?;
@@ -1070,13 +1070,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => return None,
         };
         let last_expr_ty = self.node_ty(last_expr.hir_id);
-        if matches!(last_expr_ty.kind(), ty::Error(_))
-            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
+        let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
+            (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
+                debug!(
+                    "both opaque, likely future {:?} {:?} {:?} {:?}",
+                    last_def_id, last_bounds, exp_def_id, exp_bounds
+                );
+                let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local());
+                let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local());
+                if let (
+                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
+                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
+                ) = (
+                    &self.tcx.hir().expect_item(last_hir_id).kind,
+                    &self.tcx.hir().expect_item(exp_hir_id).kind,
+                ) {
+                    debug!("{:?} {:?}", last_bounds, exp_bounds);
+                    last_bounds.iter().zip(exp_bounds.iter()).all(|(left, right)| {
+                        match (left, right) {
+                            (
+                                hir::GenericBound::Trait(tl, ml),
+                                hir::GenericBound::Trait(tr, mr),
+                            ) => {
+                                tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
+                                    && ml == mr
+                            }
+                            (
+                                hir::GenericBound::LangItemTrait(langl, _, _, argsl),
+                                hir::GenericBound::LangItemTrait(langr, _, _, argsr),
+                            ) => {
+                                // FIXME: consider the bounds!
+                                debug!("{:?} {:?}", argsl, argsr);
+                                langl == langr
+                            }
+                            _ => false,
+                        }
+                    })
+                } else {
+                    false
+                }
+            }
+            _ => false,
+        };
+        debug!(
+            "needs_box {:?} {:?} {:?}",
+            needs_box,
+            last_expr_ty.kind(),
+            self.can_sub(self.param_env, last_expr_ty, expected_ty)
+        );
+        if (matches!(last_expr_ty.kind(), ty::Error(_))
+            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err())
+            && !needs_box
         {
             return None;
         }
         let original_span = original_sp(last_stmt.span, blk.span);
-        Some(original_span.with_lo(original_span.hi() - BytePos(1)))
+        Some((original_span.with_lo(original_span.hi() - BytePos(1)), needs_box))
     }
 
     // Instantiates the given path, which must refer to an item with the given
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index fd2f5eb5018d4..a124ad16612b1 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -758,13 +758,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty: Ty<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
     ) {
-        if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
-            err.span_suggestion(
-                span_semi,
-                "consider removing this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
+        if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
+            if boxed {
+                err.span_suggestion_verbose(
+                    span_semi,
+                    "consider removing this semicolon and boxing the expression",
+                    String::new(),
+                    Applicability::HasPlaceholders,
+                );
+            } else {
+                err.span_suggestion_short(
+                    span_semi,
+                    "consider removing this semicolon",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            }
         }
     }
 
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
index d8d6de4bf5591..9704242e10541 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
@@ -14,6 +14,7 @@ fn extra_semicolon() {
 }
 
 async fn async_dummy() {} //~ NOTE the `Output` of this `async fn`'s found opaque type
+async fn async_dummy2() {} //~ NOTE the `Output` of this `async fn`'s found opaque type
 
 async fn async_extra_semicolon_same() {
     let _ = match true { //~ NOTE `match` arms have incompatible types
@@ -28,5 +29,17 @@ async fn async_extra_semicolon_same() {
     };
 }
 
-fn main() {}
+async fn async_extra_semicolon_different() {
+    let _ = match true { //~ NOTE `match` arms have incompatible types
+        true => {
+            async_dummy(); //~ NOTE this is found to be
+            //~^ HELP consider removing this semicolon
+        }
+        false => async_dummy2(), //~ ERROR `match` arms have incompatible types
+        //~^ NOTE expected `()`, found opaque type
+        //~| NOTE expected type `()`
+        //~| HELP consider `await`ing on the `Future`
+    };
+}
 
+fn main() {}
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
index e242a018843a2..00b02fbc0072f 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
@@ -1,5 +1,5 @@
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:24:18
+  --> $DIR/match-prev-arm-needing-semi.rs:25:18
    |
 LL |   async fn async_dummy() {}
    |                          - the `Output` of this `async fn`'s found opaque type
@@ -20,7 +20,7 @@ LL | |     };
    |
    = note:     expected type `()`
            found opaque type `impl Future`
-help: consider removing this semicolon
+help: consider removing this semicolon and boxing the expression
    |
 LL |             async_dummy()
    |                         --
@@ -29,6 +29,37 @@ help: consider `await`ing on the `Future`
 LL |         false => async_dummy().await,
    |                               ^^^^^^
 
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/match-prev-arm-needing-semi.rs:38:18
+   |
+LL |   async fn async_dummy2() {}
+   |                           - the `Output` of this `async fn`'s found opaque type
+...
+LL |       let _ = match true {
+   |  _____________-
+LL | |         true => {
+LL | |             async_dummy();
+   | |             -------------- this is found to be of type `()`
+LL | |
+LL | |         }
+LL | |         false => async_dummy2(),
+   | |                  ^^^^^^^^^^^^^^ expected `()`, found opaque type
+...  |
+LL | |
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note:     expected type `()`
+           found opaque type `impl Future`
+help: consider removing this semicolon and boxing the expression
+   |
+LL |             async_dummy()
+   |                         --
+help: consider `await`ing on the `Future`
+   |
+LL |         false => async_dummy2().await,
+   |                                ^^^^^^
+
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-prev-arm-needing-semi.rs:11:18
    |
@@ -48,6 +79,6 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.

From 62ba365195e37b0508dc35f73b55243cb1aef7f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 22 Oct 2020 10:27:40 -0700
Subject: [PATCH 10/24] Review comments: use newtype instead of `bool`

---
 .../src/infer/error_reporting/mod.rs          |  5 +-
 compiler/rustc_middle/src/traits/mod.rs       | 17 ++++++-
 compiler/rustc_typeck/src/check/_match.rs     | 39 ++++++++++------
 .../rustc_typeck/src/check/fn_ctxt/_impl.rs   | 46 +++++++++----------
 .../rustc_typeck/src/check/fn_ctxt/checks.rs  |  4 +-
 5 files changed, 68 insertions(+), 43 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index f6aa3c3d5ba6b..9e93cfc27d0dd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -54,6 +54,7 @@ use crate::infer::OriginalQueryValues;
 use crate::traits::error_reporting::report_object_safety_error;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+    StatementAsExpression,
 };
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -689,7 +690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     let msg = "`match` arms have incompatible types";
                     err.span_label(outer_error_span, msg);
                     if let Some((sp, boxed)) = semi_span {
-                        if boxed {
+                        if matches!(boxed, StatementAsExpression::NeedsBoxing) {
                             err.span_suggestion_verbose(
                                 sp,
                                 "consider removing this semicolon and boxing the expression",
@@ -727,7 +728,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     err.span_label(sp, "`if` and `else` have incompatible types");
                 }
                 if let Some((sp, boxed)) = semicolon {
-                    if boxed {
+                    if matches!(boxed, StatementAsExpression::NeedsBoxing) {
                         err.span_suggestion_verbose(
                             sp,
                             "consider removing this semicolon and boxing the expression",
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index daa3010abb544..4deb7225dcb61 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -340,11 +340,24 @@ impl ObligationCauseCode<'_> {
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(ObligationCauseCode<'_>, 32);
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum StatementAsExpression {
+    CorrectType,
+    NeedsBoxing,
+}
+
+impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
+    type Lifted = StatementAsExpression;
+    fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
+        Some(self)
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
 pub struct MatchExpressionArmCause<'tcx> {
     pub arm_span: Span,
     pub scrut_span: Span,
-    pub semi_span: Option<(Span, bool)>,
+    pub semi_span: Option<(Span, StatementAsExpression)>,
     pub source: hir::MatchSource,
     pub prior_arms: Vec<Span>,
     pub last_ty: Ty<'tcx>,
@@ -357,7 +370,7 @@ pub struct IfExpressionCause {
     pub then: Span,
     pub else_sp: Span,
     pub outer: Option<Span>,
-    pub semicolon: Option<(Span, bool)>,
+    pub semicolon: Option<(Span, StatementAsExpression)>,
     pub opt_suggest_box_span: Option<Span>,
 }
 
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 27c85317e82f9..e8eea65137ff7 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -9,6 +9,7 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+    StatementAsExpression,
 };
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -188,18 +189,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
             } else {
-                let (arm_span, mut semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind
-                {
-                    self.find_block_span(blk, prior_arm_ty)
-                } else {
-                    (arm.body.span, None)
-                };
-                if semi_span.is_none() && i > 0 {
-                    if let hir::ExprKind::Block(blk, _) = &arms[i - 1].body.kind {
-                        let (_, semi_span_prev) = self.find_block_span(blk, Some(arm_ty));
-                        semi_span = semi_span_prev;
-                    }
-                }
+                let (arm_span, semi_span) =
+                    self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
                 let (span, code) = match i {
                     // The reason for the first arm to fail is not that the match arms diverge,
                     // but rather that there's a prior obligation that doesn't hold.
@@ -249,6 +240,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         coercion.complete(self)
     }
 
+    fn get_appropriate_arm_semicolon_removal_span(
+        &self,
+        arms: &'tcx [hir::Arm<'tcx>],
+        i: usize,
+        prior_arm_ty: Option<Ty<'tcx>>,
+        arm_ty: Ty<'tcx>,
+    ) -> (Span, Option<(Span, StatementAsExpression)>) {
+        let arm = &arms[i];
+        let (arm_span, mut semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind {
+            self.find_block_span(blk, prior_arm_ty)
+        } else {
+            (arm.body.span, None)
+        };
+        if semi_span.is_none() && i > 0 {
+            if let hir::ExprKind::Block(blk, _) = &arms[i - 1].body.kind {
+                let (_, semi_span_prev) = self.find_block_span(blk, Some(arm_ty));
+                semi_span = semi_span_prev;
+            }
+        }
+        (arm_span, semi_span)
+    }
+
     /// When the previously checked expression (the scrutinee) diverges,
     /// warn the user about the match arms being unreachable.
     fn warn_arms_when_scrutinee_diverges(
@@ -521,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         block: &'tcx hir::Block<'tcx>,
         expected_ty: Option<Ty<'tcx>>,
-    ) -> (Span, Option<(Span, bool)>) {
+    ) -> (Span, Option<(Span, StatementAsExpression)>) {
         if let Some(expr) = &block.expr {
             (expr.span, None)
         } else if let Some(stmt) = block.stmts.last() {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index f26a168bcb288..f87e6b607d46e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -33,7 +33,9 @@ use rustc_span::{self, BytePos, MultiSpan, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::{
+    self, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
+};
 
 use std::collections::hash_map::Entry;
 use std::slice;
@@ -1061,7 +1063,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         blk: &'tcx hir::Block<'tcx>,
         expected_ty: Ty<'tcx>,
-    ) -> Option<(Span, bool)> {
+    ) -> Option<(Span, StatementAsExpression)> {
         // Be helpful when the user wrote `{... expr;}` and
         // taking the `;` off is enough to fix the error.
         let last_stmt = blk.stmts.last()?;
@@ -1078,49 +1080,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
                 let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local());
                 let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local());
-                if let (
-                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
-                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
-                ) = (
+                match (
                     &self.tcx.hir().expect_item(last_hir_id).kind,
                     &self.tcx.hir().expect_item(exp_hir_id).kind,
                 ) {
-                    debug!("{:?} {:?}", last_bounds, exp_bounds);
-                    last_bounds.iter().zip(exp_bounds.iter()).all(|(left, right)| {
+                    (
+                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
+                        hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }),
+                    ) if last_bounds.iter().zip(exp_bounds.iter()).all(|(left, right)| {
                         match (left, right) {
                             (
                                 hir::GenericBound::Trait(tl, ml),
                                 hir::GenericBound::Trait(tr, mr),
-                            ) => {
-                                tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
-                                    && ml == mr
+                            ) if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
+                                && ml == mr =>
+                            {
+                                true
                             }
                             (
                                 hir::GenericBound::LangItemTrait(langl, _, _, argsl),
                                 hir::GenericBound::LangItemTrait(langr, _, _, argsr),
-                            ) => {
+                            ) if langl == langr => {
                                 // FIXME: consider the bounds!
                                 debug!("{:?} {:?}", argsl, argsr);
-                                langl == langr
+                                true
                             }
                             _ => false,
                         }
-                    })
-                } else {
-                    false
+                    }) =>
+                    {
+                        StatementAsExpression::NeedsBoxing
+                    }
+                    _ => StatementAsExpression::CorrectType,
                 }
             }
-            _ => false,
+            _ => StatementAsExpression::CorrectType,
         };
-        debug!(
-            "needs_box {:?} {:?} {:?}",
-            needs_box,
-            last_expr_ty.kind(),
-            self.can_sub(self.param_env, last_expr_ty, expected_ty)
-        );
         if (matches!(last_expr_ty.kind(), ty::Error(_))
             || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err())
-            && !needs_box
+            && matches!(needs_box, StatementAsExpression::CorrectType)
         {
             return None;
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index a124ad16612b1..a820661d8432a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{self, MultiSpan, Span};
-use rustc_trait_selection::traits::{self, ObligationCauseCode};
+use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
 
 use std::mem::replace;
 use std::slice;
@@ -759,7 +759,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err: &mut DiagnosticBuilder<'_>,
     ) {
         if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
-            if boxed {
+            if let StatementAsExpression::NeedsBoxing = boxed {
                 err.span_suggestion_verbose(
                     span_semi,
                     "consider removing this semicolon and boxing the expression",

From 3a0227bc49397879b240373d84b2a80e05569724 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 22 Oct 2020 10:51:49 -0700
Subject: [PATCH 11/24] Silence unnecessary `await foo?` knock-down error

---
 .../rustc_parse/src/parser/diagnostics.rs     |  8 +-
 .../incorrect-syntax-suggestions.rs           |  5 +-
 .../incorrect-syntax-suggestions.stderr       | 95 +++++++------------
 3 files changed, 40 insertions(+), 68 deletions(-)

diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 1ea01d95a134e..39e1256a57835 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1207,7 +1207,13 @@ impl<'a> Parser<'a> {
             self.recover_await_prefix(await_sp)?
         };
         let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question);
-        let expr = self.mk_expr(lo.to(sp), ExprKind::Await(expr), attrs);
+        let kind = match expr.kind {
+            // Avoid knock-down errors as we don't know whether to interpret this as `foo().await?`
+            // or `foo()?.await` (the very reason we went with postfix syntax 😅).
+            ExprKind::Try(_) => ExprKind::Err,
+            _ => ExprKind::Await(expr),
+        };
+        let expr = self.mk_expr(lo.to(sp), kind, attrs);
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs
index 337487fc80b0e..554ac673d5155 100644
--- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs
+++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs
@@ -14,7 +14,6 @@ async fn foo2() -> Result<(), ()> {
 }
 async fn foo3() -> Result<(), ()> {
     let _ = await bar()?; //~ ERROR incorrect use of `await`
-    //~^ ERROR the `?` operator can only be applied to values that implement `Try`
     Ok(())
 }
 async fn foo21() -> Result<(), ()> {
@@ -60,9 +59,7 @@ fn foo10() -> Result<(), ()> {
     Ok(())
 }
 fn foo11() -> Result<(), ()> {
-    let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
-    //~^ ERROR incorrect use of `await`
-    //~| ERROR the `?` operator can only be applied to values that implement `Try`
+    let _ = await bar()?; //~ ERROR incorrect use of `await`
     Ok(())
 }
 fn foo12() -> Result<(), ()> {
diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
index d90ce0f1bb482..52615df6008ff 100644
--- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
+++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
@@ -17,103 +17,103 @@ LL |     let _ = await bar()?;
    |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:21:13
+  --> $DIR/incorrect-syntax-suggestions.rs:20:13
    |
 LL |     let _ = await { bar() };
    |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:25:13
+  --> $DIR/incorrect-syntax-suggestions.rs:24:13
    |
 LL |     let _ = await(bar());
    |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:29:13
+  --> $DIR/incorrect-syntax-suggestions.rs:28:13
    |
 LL |     let _ = await { bar() }?;
    |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:33:14
+  --> $DIR/incorrect-syntax-suggestions.rs:32:14
    |
 LL |     let _ = (await bar())?;
    |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:37:24
+  --> $DIR/incorrect-syntax-suggestions.rs:36:24
    |
 LL |     let _ = bar().await();
    |                        ^^ help: `await` is not a method call, remove the parentheses
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:41:24
+  --> $DIR/incorrect-syntax-suggestions.rs:40:24
    |
 LL |     let _ = bar().await()?;
    |                        ^^ help: `await` is not a method call, remove the parentheses
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:53:13
+  --> $DIR/incorrect-syntax-suggestions.rs:52:13
    |
 LL |     let _ = await bar();
    |             ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:58:13
+  --> $DIR/incorrect-syntax-suggestions.rs:57:13
    |
 LL |     let _ = await? bar();
    |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:63:13
+  --> $DIR/incorrect-syntax-suggestions.rs:62:13
    |
 LL |     let _ = await bar()?;
    |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:69:14
+  --> $DIR/incorrect-syntax-suggestions.rs:66:14
    |
 LL |     let _ = (await bar())?;
    |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:74:24
+  --> $DIR/incorrect-syntax-suggestions.rs:71:24
    |
 LL |     let _ = bar().await();
    |                        ^^ help: `await` is not a method call, remove the parentheses
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:79:24
+  --> $DIR/incorrect-syntax-suggestions.rs:76:24
    |
 LL |     let _ = bar().await()?;
    |                        ^^ help: `await` is not a method call, remove the parentheses
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:107:13
+  --> $DIR/incorrect-syntax-suggestions.rs:104:13
    |
 LL |     let _ = await!(bar());
    |             ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:111:13
+  --> $DIR/incorrect-syntax-suggestions.rs:108:13
    |
 LL |     let _ = await!(bar())?;
    |             ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:116:17
+  --> $DIR/incorrect-syntax-suggestions.rs:113:17
    |
 LL |         let _ = await!(bar())?;
    |                 ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:124:17
+  --> $DIR/incorrect-syntax-suggestions.rs:121:17
    |
 LL |         let _ = await!(bar())?;
    |                 ^^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
 
 error: expected expression, found `=>`
-  --> $DIR/incorrect-syntax-suggestions.rs:132:25
+  --> $DIR/incorrect-syntax-suggestions.rs:129:25
    |
 LL |     match await { await => () }
    |                   ----- ^^ expected expression
@@ -121,13 +121,13 @@ LL |     match await { await => () }
    |                   while parsing this incorrect await expression
 
 error: incorrect use of `await`
-  --> $DIR/incorrect-syntax-suggestions.rs:132:11
+  --> $DIR/incorrect-syntax-suggestions.rs:129:11
    |
 LL |     match await { await => () }
    |           ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
 
 error: expected one of `.`, `?`, `{`, or an operator, found `}`
-  --> $DIR/incorrect-syntax-suggestions.rs:135:1
+  --> $DIR/incorrect-syntax-suggestions.rs:132:1
    |
 LL |     match await { await => () }
    |     -----                      - expected one of `.`, `?`, `{`, or an operator
@@ -138,7 +138,7 @@ LL | }
    | ^ unexpected token
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:53:13
+  --> $DIR/incorrect-syntax-suggestions.rs:52:13
    |
 LL | fn foo9() -> Result<(), ()> {
    |    ---- this is not `async`
@@ -146,7 +146,7 @@ LL |     let _ = await bar();
    |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:58:13
+  --> $DIR/incorrect-syntax-suggestions.rs:57:13
    |
 LL | fn foo10() -> Result<(), ()> {
    |    ----- this is not `async`
@@ -154,15 +154,7 @@ LL |     let _ = await? bar();
    |             ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:63:13
-   |
-LL | fn foo11() -> Result<(), ()> {
-   |    ----- this is not `async`
-LL |     let _ = await bar()?;
-   |             ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
-
-error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:69:14
+  --> $DIR/incorrect-syntax-suggestions.rs:66:14
    |
 LL | fn foo12() -> Result<(), ()> {
    |    ----- this is not `async`
@@ -170,7 +162,7 @@ LL |     let _ = (await bar())?;
    |              ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:74:13
+  --> $DIR/incorrect-syntax-suggestions.rs:71:13
    |
 LL | fn foo13() -> Result<(), ()> {
    |    ----- this is not `async`
@@ -178,7 +170,7 @@ LL |     let _ = bar().await();
    |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:79:13
+  --> $DIR/incorrect-syntax-suggestions.rs:76:13
    |
 LL | fn foo14() -> Result<(), ()> {
    |    ----- this is not `async`
@@ -186,7 +178,7 @@ LL |     let _ = bar().await()?;
    |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:84:13
+  --> $DIR/incorrect-syntax-suggestions.rs:81:13
    |
 LL | fn foo15() -> Result<(), ()> {
    |    ----- this is not `async`
@@ -194,7 +186,7 @@ LL |     let _ = bar().await;
    |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:88:13
+  --> $DIR/incorrect-syntax-suggestions.rs:85:13
    |
 LL | fn foo16() -> Result<(), ()> {
    |    ----- this is not `async`
@@ -202,7 +194,7 @@ LL |     let _ = bar().await?;
    |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:93:17
+  --> $DIR/incorrect-syntax-suggestions.rs:90:17
    |
 LL |     fn foo() -> Result<(), ()> {
    |        --- this is not `async`
@@ -210,7 +202,7 @@ LL |         let _ = bar().await?;
    |                 ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:100:17
+  --> $DIR/incorrect-syntax-suggestions.rs:97:17
    |
 LL |     let foo = || {
    |               -- this is not `async`
@@ -218,7 +210,7 @@ LL |         let _ = bar().await?;
    |                 ^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:116:17
+  --> $DIR/incorrect-syntax-suggestions.rs:113:17
    |
 LL |     fn foo() -> Result<(), ()> {
    |        --- this is not `async`
@@ -226,36 +218,13 @@ LL |         let _ = await!(bar())?;
    |                 ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/incorrect-syntax-suggestions.rs:124:17
+  --> $DIR/incorrect-syntax-suggestions.rs:121:17
    |
 LL |     let foo = || {
    |               -- this is not `async`
 LL |         let _ = await!(bar())?;
    |                 ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
-error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/incorrect-syntax-suggestions.rs:16:19
-   |
-LL |     let _ = await bar()?;
-   |                   ^^^^^^ the `?` operator cannot be applied to type `impl Future`
-   |
-   = help: the trait `Try` is not implemented for `impl Future`
-   = note: required by `into_result`
-help: consider `await`ing on the `Future`
-   |
-LL |     let _ = await bar().await?;
-   |                        ^^^^^^
-
-error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/incorrect-syntax-suggestions.rs:63:19
-   |
-LL |     let _ = await bar()?;
-   |                   ^^^^^^ the `?` operator cannot be applied to type `impl Future`
-   |
-   = help: the trait `Try` is not implemented for `impl Future`
-   = note: required by `into_result`
-
-error: aborting due to 36 previous errors
+error: aborting due to 33 previous errors
 
-Some errors have detailed explanations: E0277, E0728.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0728`.

From 1829b4a887553797d6fa018ae2518ca0d45b67ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 22 Oct 2020 11:34:46 -0700
Subject: [PATCH 12/24] Add test case for different `impl Future`s

---
 .../match-prev-arm-needing-semi.rs            | 11 ++++++++
 .../match-prev-arm-needing-semi.stderr        | 28 +++++++++++++++++--
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
index 9704242e10541..81e6abf7d7ba4 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
@@ -15,6 +15,7 @@ fn extra_semicolon() {
 
 async fn async_dummy() {} //~ NOTE the `Output` of this `async fn`'s found opaque type
 async fn async_dummy2() {} //~ NOTE the `Output` of this `async fn`'s found opaque type
+//~^ NOTE the `Output` of this `async fn`'s found opaque type
 
 async fn async_extra_semicolon_same() {
     let _ = match true { //~ NOTE `match` arms have incompatible types
@@ -42,4 +43,14 @@ async fn async_extra_semicolon_different() {
     };
 }
 
+async fn async_different_futures() {
+    let _ = match true { //~ NOTE `match` arms have incompatible types
+        true => async_dummy(), //~ NOTE this is found to be
+        false => async_dummy2(), //~ ERROR `match` arms have incompatible types
+        //~^ NOTE expected opaque type, found a different opaque type
+        //~| NOTE expected type `impl Future`
+        //~| NOTE distinct uses of `impl Trait` result in different opaque types
+    };
+}
+
 fn main() {}
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
index 00b02fbc0072f..8f4b860589efd 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
@@ -1,5 +1,5 @@
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:25:18
+  --> $DIR/match-prev-arm-needing-semi.rs:26:18
    |
 LL |   async fn async_dummy() {}
    |                          - the `Output` of this `async fn`'s found opaque type
@@ -30,7 +30,7 @@ LL |         false => async_dummy().await,
    |                               ^^^^^^
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:38:18
+  --> $DIR/match-prev-arm-needing-semi.rs:39:18
    |
 LL |   async fn async_dummy2() {}
    |                           - the `Output` of this `async fn`'s found opaque type
@@ -60,6 +60,28 @@ help: consider `await`ing on the `Future`
 LL |         false => async_dummy2().await,
    |                                ^^^^^^
 
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/match-prev-arm-needing-semi.rs:49:18
+   |
+LL |   async fn async_dummy2() {}
+   |                           - the `Output` of this `async fn`'s found opaque type
+...
+LL |       let _ = match true {
+   |  _____________-
+LL | |         true => async_dummy(),
+   | |                 ------------- this is found to be of type `impl Future`
+LL | |         false => async_dummy2(),
+   | |                  ^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
+LL | |
+LL | |
+LL | |
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note:     expected type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
+           found opaque type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:17:25>)
+   = note: distinct uses of `impl Trait` result in different opaque types
+
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-prev-arm-needing-semi.rs:11:18
    |
@@ -79,6 +101,6 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0308`.

From c5485115dcbbb5a0837c2ac8cabd5ead8a3b8a66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 22 Oct 2020 19:03:36 -0700
Subject: [PATCH 13/24] Add more `.await` suggestions on E0308

---
 .../src/infer/error_reporting/mod.rs          | 157 +++++++++++++-----
 compiler/rustc_middle/src/ty/error.rs         |  37 ++---
 compiler/rustc_typeck/src/check/demand.rs     |   1 -
 .../src/check/fn_ctxt/suggestions.rs          |  79 ---------
 .../dont-suggest-missing-await.stderr         |   4 +
 src/test/ui/async-await/issue-61076.stderr    |   4 +
 .../async-await/suggest-missing-await.fixed   |  30 ----
 .../ui/async-await/suggest-missing-await.rs   |   1 -
 .../async-await/suggest-missing-await.stderr  |  12 +-
 .../match-prev-arm-needing-semi.rs            |   1 +
 .../match-prev-arm-needing-semi.stderr        |  23 ++-
 .../ui/suggestions/opaque-type-error.stderr   |   6 +
 12 files changed, 167 insertions(+), 188 deletions(-)
 delete mode 100644 src/test/ui/async-await/suggest-missing-await.fixed

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 9e93cfc27d0dd..fcf21c61d8fd9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -50,7 +50,6 @@ use super::region_constraints::GenericKind;
 use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
 
 use crate::infer;
-use crate::infer::OriginalQueryValues;
 use crate::traits::error_reporting::report_object_safety_error;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -65,7 +64,6 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Item, ItemKind, Node};
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::ParamEnvAnd;
 use rustc_middle::ty::{
     self,
     subst::{Subst, SubstsRef},
@@ -1621,6 +1619,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             Mismatch::Variable(exp_found) => Some(exp_found),
             Mismatch::Fixed(_) => None,
         };
+        let exp_found = match terr {
+            // `terr` has more accurate type information than `exp_found` in match expressions.
+            ty::error::TypeError::Sorts(terr)
+                if exp_found.map_or(false, |ef| terr.found == ef.found) =>
+            {
+                Some(*terr)
+            }
+            _ => exp_found,
+        };
+        debug!("exp_found {:?} terr {:?}", exp_found, terr);
         if let Some(exp_found) = exp_found {
             self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
             self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
@@ -1642,6 +1650,53 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.note_error_origin(diag, cause, exp_found);
     }
 
+    fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+        if let ty::Opaque(def_id, substs) = ty.kind() {
+            let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+            // Future::Output
+            let item_def_id = self
+                .tcx
+                .associated_items(future_trait)
+                .in_definition_order()
+                .next()
+                .unwrap()
+                .def_id;
+
+            let bounds = self.tcx.explicit_item_bounds(*def_id);
+
+            for (predicate, _) in bounds {
+                let predicate = predicate.subst(self.tcx, substs);
+                if let ty::PredicateAtom::Projection(projection_predicate) =
+                    predicate.skip_binders()
+                {
+                    if projection_predicate.projection_ty.item_def_id == item_def_id {
+                        // We don't account for multiple `Future::Output = Ty` contraints.
+                        return Some(projection_predicate.ty);
+                    }
+                }
+            }
+        }
+        None
+    }
+
+    /// A possible error is to forget to add `.await` when using futures:
+    ///
+    /// ```
+    /// async fn make_u32() -> u32 {
+    ///     22
+    /// }
+    ///
+    /// fn take_u32(x: u32) {}
+    ///
+    /// async fn foo() {
+    ///     let x = make_u32();
+    ///     take_u32(x);
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
+    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
+    /// `.await` to the tail of the expression.
     fn suggest_await_on_expect_found(
         &self,
         cause: &ObligationCause<'tcx>,
@@ -1651,50 +1706,76 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     ) {
         debug!(
             "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}",
-            exp_span, exp_found.expected, exp_found.found
+            exp_span, exp_found.expected, exp_found.found,
         );
 
-        if let ty::Opaque(def_id, _) = *exp_found.expected.kind() {
-            let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
-            // Future::Output
-            let item_def_id = self
-                .tcx
-                .associated_items(future_trait)
-                .in_definition_order()
-                .next()
-                .unwrap()
-                .def_id;
+        if let ObligationCauseCode::CompareImplMethodObligation { .. } = &cause.code {
+            return;
+        }
 
-            let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id));
-            if let Some(projection_ty) = projection_ty {
-                let projection_query = self.canonicalize_query(
-                    &ParamEnvAnd { param_env: self.tcx.param_env(def_id), value: projection_ty },
-                    &mut OriginalQueryValues::default(),
-                );
-                if let Ok(resp) = self.tcx.normalize_projection_ty(projection_query) {
-                    let normalized_ty = resp.value.value.normalized_ty;
-                    debug!("suggest_await_on_expect_found: normalized={:?}", normalized_ty);
-                    if ty::TyS::same_type(normalized_ty, exp_found.found) {
-                        let span = if let ObligationCauseCode::Pattern {
-                            span,
-                            origin_expr: _,
-                            root_ty: _,
-                        } = cause.code
-                        {
-                            // scrutinee's span
-                            span.unwrap_or(exp_span)
-                        } else {
-                            exp_span
-                        };
-                        diag.span_suggestion_verbose(
-                            span.shrink_to_hi(),
-                            "consider awaiting on the future",
-                            ".await".to_string(),
+        match (
+            self.get_impl_future_output_ty(exp_found.expected),
+            self.get_impl_future_output_ty(exp_found.found),
+        ) {
+            (Some(exp), Some(found)) if ty::TyS::same_type(exp, found) => match &cause.code {
+                ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
+                    diag.multipart_suggestion(
+                        "consider `await`ing on both `Future`s",
+                        vec![
+                            (then.shrink_to_hi(), ".await".to_string()),
+                            (exp_span.shrink_to_hi(), ".await".to_string()),
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                    prior_arms,
+                    ..
+                }) => {
+                    if let [.., arm_span] = &prior_arms[..] {
+                        diag.multipart_suggestion(
+                            "consider `await`ing on both `Future`s",
+                            vec![
+                                (arm_span.shrink_to_hi(), ".await".to_string()),
+                                (exp_span.shrink_to_hi(), ".await".to_string()),
+                            ],
                             Applicability::MaybeIncorrect,
                         );
+                    } else {
+                        diag.help("consider `await`ing on both `Future`s");
                     }
                 }
+                _ => {
+                    diag.help("consider `await`ing on both `Future`s");
+                }
+            },
+            (_, Some(ty)) if ty::TyS::same_type(exp_found.expected, ty) => {
+                let span = match cause.code {
+                    // scrutinee's span
+                    ObligationCauseCode::Pattern { span: Some(span), .. } => span,
+                    _ => exp_span,
+                };
+                diag.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    "consider `await`ing on the `Future`",
+                    ".await".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (Some(ty), _) if ty::TyS::same_type(ty, exp_found.found) => {
+                let span = match cause.code {
+                    // scrutinee's span
+                    ObligationCauseCode::Pattern { span: Some(span), .. } => span,
+                    _ => exp_span,
+                };
+                diag.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    "consider `await`ing on the `Future`",
+                    ".await".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
             }
+            _ => {}
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 235f8749cf917..5ec0ec0c56ad6 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -334,26 +334,15 @@ impl<'tcx> TyCtxt<'tcx> {
         debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
         match err {
             Sorts(values) => {
-                let expected_str = values.expected.sort_string(self);
-                let found_str = values.found.sort_string(self);
-                if expected_str == found_str && expected_str == "closure" {
-                    db.note("no two closures, even if identical, have the same type");
-                    db.help("consider boxing your closure and/or using it as a trait object");
-                }
-                if expected_str == found_str && expected_str == "opaque type" {
-                    // Issue #63167
-                    db.note("distinct uses of `impl Trait` result in different opaque types");
-                    let e_str = values.expected.to_string();
-                    let f_str = values.found.to_string();
-                    if e_str == f_str && &e_str == "impl std::future::Future" {
-                        // FIXME: use non-string based check.
-                        db.help(
-                            "if both `Future`s have the same `Output` type, consider \
-                                 `.await`ing on both of them",
-                        );
-                    }
-                }
                 match (values.expected.kind(), values.found.kind()) {
+                    (ty::Closure(..), ty::Closure(..)) => {
+                        db.note("no two closures, even if identical, have the same type");
+                        db.help("consider boxing your closure and/or using it as a trait object");
+                    }
+                    (ty::Opaque(..), ty::Opaque(..)) => {
+                        // Issue #63167
+                        db.note("distinct uses of `impl Trait` result in different opaque types");
+                    }
                     (ty::Float(_), ty::Infer(ty::IntVar(_))) => {
                         if let Ok(
                             // Issue #53280
@@ -382,12 +371,12 @@ impl<'tcx> TyCtxt<'tcx> {
                         }
                         db.note(
                             "a type parameter was expected, but a different one was found; \
-                                 you might be missing a type parameter or trait bound",
+                             you might be missing a type parameter or trait bound",
                         );
                         db.note(
                             "for more information, visit \
-                                 https://doc.rust-lang.org/book/ch10-02-traits.html\
-                                 #traits-as-parameters",
+                             https://doc.rust-lang.org/book/ch10-02-traits.html\
+                             #traits-as-parameters",
                         );
                     }
                     (ty::Projection(_), ty::Projection(_)) => {
@@ -471,8 +460,8 @@ impl<T> Trait<T> for X {
                         }
                         db.note(
                             "for more information, visit \
-                                 https://doc.rust-lang.org/book/ch10-02-traits.html\
-                                 #traits-as-parameters",
+                             https://doc.rust-lang.org/book/ch10-02-traits.html\
+                             #traits-as-parameters",
                         );
                     }
                     (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index b8143787a2ddf..241803fab1e68 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -33,7 +33,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
-        self.suggest_missing_await(err, expr, expected, expr_ty);
         self.suggest_missing_parentheses(err, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 18db8d63850b2..a8ad9f4fdf8af 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -3,7 +3,6 @@ use crate::astconv::AstConv;
 
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_span::{self, Span};
-use rustc_trait_selection::traits;
 
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -13,7 +12,6 @@ use rustc_hir::{ExprKind, ItemKind, Node};
 use rustc_infer::infer;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::kw;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 use std::iter;
 
@@ -433,83 +431,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    /// A possible error is to forget to add `.await` when using futures:
-    ///
-    /// ```
-    /// async fn make_u32() -> u32 {
-    ///     22
-    /// }
-    ///
-    /// fn take_u32(x: u32) {}
-    ///
-    /// async fn foo() {
-    ///     let x = make_u32();
-    ///     take_u32(x);
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
-    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
-    /// `.await` to the tail of the expression.
-    pub(in super::super) fn suggest_missing_await(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
-        // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
-        // body isn't `async`.
-        let item_id = self.tcx().hir().get_parent_node(self.body_id);
-        if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
-            let body = self.tcx().hir().body(body_id);
-            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
-                let sp = expr.span;
-                // Check for `Future` implementations by constructing a predicate to
-                // prove: `<T as Future>::Output == U`
-                let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
-                let item_def_id = self
-                    .tcx
-                    .associated_items(future_trait)
-                    .in_definition_order()
-                    .next()
-                    .unwrap()
-                    .def_id;
-                // `<T as Future>::Output`
-                let projection_ty = ty::ProjectionTy {
-                    // `T`
-                    substs: self
-                        .tcx
-                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
-                    // `Future::Output`
-                    item_def_id,
-                };
-
-                let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
-                    projection_ty,
-                    ty: expected,
-                })
-                .potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
-                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
-
-                debug!("suggest_missing_await: trying obligation {:?}", obligation);
-
-                if self.infcx.predicate_may_hold(&obligation) {
-                    debug!("suggest_missing_await: obligation held: {:?}", obligation);
-                    err.span_suggestion_verbose(
-                        sp.shrink_to_hi(),
-                        "consider `await`ing on the `Future`",
-                        ".await".to_string(),
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
-                }
-            }
-        }
-    }
-
     pub(in super::super) fn suggest_missing_parentheses(
         &self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr
index e70ed9badbd33..14e72c2b1e7e2 100644
--- a/src/test/ui/async-await/dont-suggest-missing-await.stderr
+++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr
@@ -9,6 +9,10 @@ LL |         take_u32(x)
    |
    = note:     expected type `u32`
            found opaque type `impl Future`
+help: consider `await`ing on the `Future`
+   |
+LL |         take_u32(x.await)
+   |                   ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
index afba889f014fe..df54ac88acee1 100644
--- a/src/test/ui/async-await/issue-61076.stderr
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -53,6 +53,10 @@ LL |         Tuple(_) => {}
    |
    = note: expected opaque type `impl Future`
                    found struct `Tuple`
+help: consider `await`ing on the `Future`
+   |
+LL |     match tuple().await {
+   |                  ^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed
deleted file mode 100644
index e548fda7cb4f5..0000000000000
--- a/src/test/ui/async-await/suggest-missing-await.fixed
+++ /dev/null
@@ -1,30 +0,0 @@
-// edition:2018
-// run-rustfix
-
-fn take_u32(_x: u32) {}
-
-async fn make_u32() -> u32 {
-    22
-}
-
-#[allow(unused)]
-async fn suggest_await_in_async_fn() {
-    let x = make_u32();
-    take_u32(x.await)
-    //~^ ERROR mismatched types [E0308]
-    //~| HELP consider `await`ing on the `Future`
-    //~| SUGGESTION .await
-}
-
-async fn dummy() {}
-
-#[allow(unused)]
-async fn suggest_await_in_async_fn_return() {
-    dummy().await;
-    //~^ ERROR mismatched types [E0308]
-    //~| HELP try adding a semicolon
-    //~| HELP consider `await`ing on the `Future`
-    //~| SUGGESTION .await
-}
-
-fn main() {}
diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs
index 464a9602119e1..d629054911dac 100644
--- a/src/test/ui/async-await/suggest-missing-await.rs
+++ b/src/test/ui/async-await/suggest-missing-await.rs
@@ -1,5 +1,4 @@
 // edition:2018
-// run-rustfix
 
 fn take_u32(_x: u32) {}
 
diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr
index d729420e93019..46615dae7e2ba 100644
--- a/src/test/ui/async-await/suggest-missing-await.stderr
+++ b/src/test/ui/async-await/suggest-missing-await.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/suggest-missing-await.rs:13:14
+  --> $DIR/suggest-missing-await.rs:12:14
    |
 LL | async fn make_u32() -> u32 {
    |                        --- the `Output` of this `async fn`'s found opaque type
@@ -15,7 +15,7 @@ LL |     take_u32(x.await)
    |               ^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/suggest-missing-await.rs:23:5
+  --> $DIR/suggest-missing-await.rs:22:5
    |
 LL | async fn dummy() {}
    |                  - the `Output` of this `async fn`'s found opaque type
@@ -25,14 +25,14 @@ LL |     dummy()
    |
    = note: expected unit type `()`
             found opaque type `impl Future`
-help: try adding a semicolon
-   |
-LL |     dummy();
-   |            ^
 help: consider `await`ing on the `Future`
    |
 LL |     dummy().await
    |            ^^^^^^
+help: try adding a semicolon
+   |
+LL |     dummy();
+   |            ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
index 81e6abf7d7ba4..b8ac030b0bbbe 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.rs
@@ -46,6 +46,7 @@ async fn async_extra_semicolon_different() {
 async fn async_different_futures() {
     let _ = match true { //~ NOTE `match` arms have incompatible types
         true => async_dummy(), //~ NOTE this is found to be
+        //~| HELP consider `await`ing on both `Future`s
         false => async_dummy2(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected opaque type, found a different opaque type
         //~| NOTE expected type `impl Future`
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
index 8f4b860589efd..7a4f74a1994ce 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
@@ -20,14 +20,14 @@ LL | |     };
    |
    = note:     expected type `()`
            found opaque type `impl Future`
-help: consider removing this semicolon and boxing the expression
-   |
-LL |             async_dummy()
-   |                         --
 help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy().await,
    |                               ^^^^^^
+help: consider removing this semicolon and boxing the expression
+   |
+LL |             async_dummy()
+   |                         --
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-prev-arm-needing-semi.rs:39:18
@@ -51,17 +51,17 @@ LL | |     };
    |
    = note:     expected type `()`
            found opaque type `impl Future`
-help: consider removing this semicolon and boxing the expression
-   |
-LL |             async_dummy()
-   |                         --
 help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy2().await,
    |                                ^^^^^^
+help: consider removing this semicolon and boxing the expression
+   |
+LL |             async_dummy()
+   |                         --
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:49:18
+  --> $DIR/match-prev-arm-needing-semi.rs:50:18
    |
 LL |   async fn async_dummy2() {}
    |                           - the `Output` of this `async fn`'s found opaque type
@@ -81,6 +81,11 @@ LL | |     };
    = note:     expected type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
            found opaque type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:17:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
+help: consider `await`ing on both `Future`s
+   |
+LL |         true => async_dummy().await,
+LL |         false => async_dummy2().await,
+   |
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-prev-arm-needing-semi.rs:11:18
diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr
index a7c2b82942f05..d74076cbc9b8e 100644
--- a/src/test/ui/suggestions/opaque-type-error.stderr
+++ b/src/test/ui/suggestions/opaque-type-error.stderr
@@ -16,6 +16,12 @@ LL | |     }.await
    = note:     expected type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
            found opaque type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
    = note: distinct uses of `impl Trait` result in different opaque types
+help: consider `await`ing on both `Future`s
+   |
+LL |         thing_one().await
+LL |     } else {
+LL |         thing_two().await
+   |
 
 error: aborting due to previous error
 

From f5d7443a6bd90b78e61b9c47e5032b5e1be1e49f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 22 Oct 2020 20:02:55 -0700
Subject: [PATCH 14/24] Suggest semicolon removal and boxing when appropriate

---
 .../src/infer/error_reporting/mod.rs          | 35 ++++++++++++++-----
 .../match-prev-arm-needing-semi.stderr        | 23 +++++++-----
 2 files changed, 42 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index fcf21c61d8fd9..f7e4ace8fc5fc 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -688,12 +688,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     let msg = "`match` arms have incompatible types";
                     err.span_label(outer_error_span, msg);
                     if let Some((sp, boxed)) = semi_span {
-                        if matches!(boxed, StatementAsExpression::NeedsBoxing) {
-                            err.span_suggestion_verbose(
+                        if let (StatementAsExpression::NeedsBoxing, [.., prior_arm]) =
+                            (boxed, &prior_arms[..])
+                        {
+                            err.multipart_suggestion(
+                                "consider removing this semicolon and boxing the expressions",
+                                vec![
+                                    (prior_arm.shrink_to_lo(), "Box::new(".to_string()),
+                                    (prior_arm.shrink_to_hi(), ")".to_string()),
+                                    (arm_span.shrink_to_lo(), "Box::new(".to_string()),
+                                    (arm_span.shrink_to_hi(), ")".to_string()),
+                                    (sp, String::new()),
+                                ],
+                                Applicability::HasPlaceholders,
+                            );
+                        } else if matches!(boxed, StatementAsExpression::NeedsBoxing) {
+                            err.span_suggestion_short(
                                 sp,
-                                "consider removing this semicolon and boxing the expression",
+                                "consider removing this semicolon and boxing the expressions",
                                 String::new(),
-                                Applicability::HasPlaceholders,
+                                Applicability::MachineApplicable,
                             );
                         } else {
                             err.span_suggestion_short(
@@ -727,11 +741,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
                 if let Some((sp, boxed)) = semicolon {
                     if matches!(boxed, StatementAsExpression::NeedsBoxing) {
-                        err.span_suggestion_verbose(
-                            sp,
+                        err.multipart_suggestion(
                             "consider removing this semicolon and boxing the expression",
-                            String::new(),
-                            Applicability::HasPlaceholders,
+                            vec![
+                                (then.shrink_to_lo(), "Box::new(".to_string()),
+                                (then.shrink_to_hi(), ")".to_string()),
+                                (else_sp.shrink_to_lo(), "Box::new(".to_string()),
+                                (else_sp.shrink_to_hi(), ")".to_string()),
+                                (sp, String::new()),
+                            ],
+                            Applicability::MachineApplicable,
                         );
                     } else {
                         err.span_suggestion_short(
diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
index 7a4f74a1994ce..e9803a78f94b3 100644
--- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
+++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
@@ -24,10 +24,13 @@ help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy().await,
    |                               ^^^^^^
-help: consider removing this semicolon and boxing the expression
+help: consider removing this semicolon and boxing the expressions
+   |
+LL |             Box::new(async_dummy())
+LL |
+LL |         }
+LL |         false => Box::new(async_dummy()),
    |
-LL |             async_dummy()
-   |                         --
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-prev-arm-needing-semi.rs:39:18
@@ -55,10 +58,13 @@ help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy2().await,
    |                                ^^^^^^
-help: consider removing this semicolon and boxing the expression
+help: consider removing this semicolon and boxing the expressions
+   |
+LL |             Box::new(async_dummy())
+LL |
+LL |         }
+LL |         false => Box::new(async_dummy2()),
    |
-LL |             async_dummy()
-   |                         --
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-prev-arm-needing-semi.rs:50:18
@@ -70,10 +76,10 @@ LL |       let _ = match true {
    |  _____________-
 LL | |         true => async_dummy(),
    | |                 ------------- this is found to be of type `impl Future`
+LL | |
 LL | |         false => async_dummy2(),
    | |                  ^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
-LL | |
-LL | |
+...  |
 LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
@@ -84,6 +90,7 @@ LL | |     };
 help: consider `await`ing on both `Future`s
    |
 LL |         true => async_dummy().await,
+LL |
 LL |         false => async_dummy2().await,
    |
 

From d413bb6f5716261f2740eb67540df1da1469ce12 Mon Sep 17 00:00:00 2001
From: chansuke <chansuke@georepublic.de>
Date: Sat, 18 Jul 2020 21:59:53 +0900
Subject: [PATCH 15/24] `#[deny(unsafe_op_in_unsafe_fn)]` in sys/wasm

---
 library/std/src/sys/wasm/alloc.rs           |  8 +++---
 library/std/src/sys/wasm/condvar_atomics.rs | 11 +++++---
 library/std/src/sys/wasm/mod.rs             |  2 ++
 library/std/src/sys/wasm/mutex_atomics.rs   | 29 +++++++++++++--------
 4 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs
index 32b8b5bdaea7a..e12af19718a7c 100644
--- a/library/std/src/sys/wasm/alloc.rs
+++ b/library/std/src/sys/wasm/alloc.rs
@@ -25,25 +25,25 @@ unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
         let _lock = lock::lock();
-        DLMALLOC.malloc(layout.size(), layout.align())
+        unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
         let _lock = lock::lock();
-        DLMALLOC.calloc(layout.size(), layout.align())
+        unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
         let _lock = lock::lock();
-        DLMALLOC.free(ptr, layout.size(), layout.align())
+        unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
         let _lock = lock::lock();
-        DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
+        unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
     }
 }
 
diff --git a/library/std/src/sys/wasm/condvar_atomics.rs b/library/std/src/sys/wasm/condvar_atomics.rs
index a96bb18e6ef1a..b9133e9fb7dbc 100644
--- a/library/std/src/sys/wasm/condvar_atomics.rs
+++ b/library/std/src/sys/wasm/condvar_atomics.rs
@@ -44,13 +44,18 @@ impl Condvar {
 
     pub unsafe fn notify_one(&self) {
         self.cnt.fetch_add(1, SeqCst);
-        wasm32::memory_atomic_notify(self.ptr(), 1);
+        // SAFETY: ptr() is always valid
+        unsafe {
+            wasm32::memory_atomic_notify(self.ptr(), 1);
+        }
     }
 
     #[inline]
     pub unsafe fn notify_all(&self) {
-        self.cnt.fetch_add(1, SeqCst);
-        wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
+        unsafe {
+            self.cnt.fetch_add(1, SeqCst);
+            wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
+        }
     }
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index 11c6896f050b2..82683c0f624cf 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -14,6 +14,8 @@
 //! compiling for wasm. That way it's a compile time error for something that's
 //! guaranteed to be a runtime error!
 
+#![deny(unsafe_op_in_unsafe_fn)]
+
 pub mod alloc;
 pub mod args;
 #[path = "../unsupported/cmath.rs"]
diff --git a/library/std/src/sys/wasm/mutex_atomics.rs b/library/std/src/sys/wasm/mutex_atomics.rs
index 2970fcf806cbf..11d7f4c389dec 100644
--- a/library/std/src/sys/wasm/mutex_atomics.rs
+++ b/library/std/src/sys/wasm/mutex_atomics.rs
@@ -28,11 +28,14 @@ impl Mutex {
 
     pub unsafe fn lock(&self) {
         while !self.try_lock() {
-            let val = wasm32::memory_atomic_wait32(
-                self.ptr(),
-                1,  // we expect our mutex is locked
-                -1, // wait infinitely
-            );
+            // SAFETY: the caller must uphold the safety contract for `memory_atomic_wait32`.
+            let val = unsafe {
+                wasm32::memory_atomic_wait32(
+                    self.ptr(),
+                    1,  // we expect our mutex is locked
+                    -1, // wait infinitely
+                )
+            };
             // we should have either woke up (0) or got a not-equal due to a
             // race (1). We should never time out (2)
             debug_assert!(val == 0 || val == 1);
@@ -47,7 +50,7 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
+        unsafe { self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() }
     }
 
     #[inline]
@@ -83,7 +86,7 @@ unsafe impl Sync for ReentrantMutex {}
 
 impl ReentrantMutex {
     pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
+        unsafe { ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) } }
     }
 
     pub unsafe fn init(&self) {
@@ -93,19 +96,20 @@ impl ReentrantMutex {
     pub unsafe fn lock(&self) {
         let me = thread::my_id();
         while let Err(owner) = self._try_lock(me) {
-            let val = wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1);
+            // SAFETY: the caller must gurantee that `self.ptr()` and `owner` are valid i32.
+            let val = unsafe { wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1) };
             debug_assert!(val == 0 || val == 1);
         }
     }
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        self._try_lock(thread::my_id()).is_ok()
+        unsafe { self._try_lock(thread::my_id()).is_ok() }
     }
 
     #[inline]
     unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
-        let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
+        let id = id.checked_add(1).unwrap();
         match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
             // we transitioned from unlocked to locked
             Ok(_) => {
@@ -132,7 +136,10 @@ impl ReentrantMutex {
         match *self.recursions.get() {
             0 => {
                 self.owner.swap(0, SeqCst);
-                wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1); // wake up one waiter, if any
+                // SAFETY: the caller must gurantee that `self.ptr()` is valid i32.
+                unsafe {
+                    wasm32::atomic_notify(self.ptr() as *mut i32, 1);
+                } // wake up one waiter, if any
             }
             ref mut n => *n -= 1,
         }

From eed45107da8da6293d9cecc302ad3b9870848b51 Mon Sep 17 00:00:00 2001
From: chansuke <chansuke@georepublic.de>
Date: Wed, 21 Oct 2020 08:15:28 +0900
Subject: [PATCH 16/24] Add some description for (malloc/calloc/free/realloc)

---
 library/std/src/sys/wasm/alloc.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs
index e12af19718a7c..b85f4d50021e3 100644
--- a/library/std/src/sys/wasm/alloc.rs
+++ b/library/std/src/sys/wasm/alloc.rs
@@ -24,24 +24,28 @@ static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // SAFETY:  DLMALLOC.malloc() is guranteed to be safe since lock::lock() aqcuire a globl lock
         let _lock = lock::lock();
         unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        // SAFETY:  DLMALLOC.calloc() is guranteed to be safe since lock::lock() aqcuire a globl lock
         let _lock = lock::lock();
         unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        // SAFETY:  DLMALLOC.free() is guranteed to be safe since lock::lock() aqcuire a globl lock
         let _lock = lock::lock();
         unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        // SAFETY:  DLMALLOC.realloc() is guranteed to be safe since lock::lock() aqcuire a globl lock
         let _lock = lock::lock();
         unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
     }

From de87ae79610925502f45ec07cf24bac51e037ed1 Mon Sep 17 00:00:00 2001
From: chansuke <chansuke@georepublic.de>
Date: Sat, 24 Oct 2020 17:59:58 +0900
Subject: [PATCH 17/24] Add documents for DLMALLOC

---
 library/std/src/sys/wasm/alloc.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs
index b85f4d50021e3..b61a7872265f3 100644
--- a/library/std/src/sys/wasm/alloc.rs
+++ b/library/std/src/sys/wasm/alloc.rs
@@ -24,28 +24,32 @@ static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        // SAFETY:  DLMALLOC.malloc() is guranteed to be safe since lock::lock() aqcuire a globl lock
+        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // Calling malloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        // SAFETY:  DLMALLOC.calloc() is guranteed to be safe since lock::lock() aqcuire a globl lock
+        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // Calling calloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        // SAFETY:  DLMALLOC.free() is guranteed to be safe since lock::lock() aqcuire a globl lock
+        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // Calling free() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        // SAFETY:  DLMALLOC.realloc() is guranteed to be safe since lock::lock() aqcuire a globl lock
+        // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+        // Calling realloc() is safe because preconditions on this function match the trait method preconditions.
         let _lock = lock::lock();
         unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
     }

From d147f78e367386bf63ccb03d453e151e37cfdd81 Mon Sep 17 00:00:00 2001
From: chansuke <chansuke@georepublic.de>
Date: Sat, 24 Oct 2020 18:14:17 +0900
Subject: [PATCH 18/24] Fix unsafe operation of wasm32::memory_atomic_notify

---
 library/std/src/sys/wasm/condvar_atomics.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/library/std/src/sys/wasm/condvar_atomics.rs b/library/std/src/sys/wasm/condvar_atomics.rs
index b9133e9fb7dbc..c2c47910582a0 100644
--- a/library/std/src/sys/wasm/condvar_atomics.rs
+++ b/library/std/src/sys/wasm/condvar_atomics.rs
@@ -52,8 +52,9 @@ impl Condvar {
 
     #[inline]
     pub unsafe fn notify_all(&self) {
+        self.cnt.fetch_add(1, SeqCst);
+        // SAFETY: memory_atomic_notify()is always valid
         unsafe {
-            self.cnt.fetch_add(1, SeqCst);
             wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
         }
     }

From d37b8cf729187e5dcabb3650031eb806d1f79770 Mon Sep 17 00:00:00 2001
From: chansuke <chansuke@georepublic.de>
Date: Sat, 24 Oct 2020 18:22:18 +0900
Subject: [PATCH 19/24] Remove unnecessary unsafe block from condvar_atomics &
 mutex_atomics

---
 library/std/src/sys/wasm/condvar_atomics.rs | 2 +-
 library/std/src/sys/wasm/mutex_atomics.rs   | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/library/std/src/sys/wasm/condvar_atomics.rs b/library/std/src/sys/wasm/condvar_atomics.rs
index c2c47910582a0..0c1c076cc9142 100644
--- a/library/std/src/sys/wasm/condvar_atomics.rs
+++ b/library/std/src/sys/wasm/condvar_atomics.rs
@@ -53,7 +53,7 @@ impl Condvar {
     #[inline]
     pub unsafe fn notify_all(&self) {
         self.cnt.fetch_add(1, SeqCst);
-        // SAFETY: memory_atomic_notify()is always valid
+        // SAFETY: ptr() is always valid
         unsafe {
             wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
         }
diff --git a/library/std/src/sys/wasm/mutex_atomics.rs b/library/std/src/sys/wasm/mutex_atomics.rs
index 11d7f4c389dec..479182ffa44d5 100644
--- a/library/std/src/sys/wasm/mutex_atomics.rs
+++ b/library/std/src/sys/wasm/mutex_atomics.rs
@@ -50,7 +50,7 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        unsafe { self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() }
+        self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
     }
 
     #[inline]
@@ -86,7 +86,7 @@ unsafe impl Sync for ReentrantMutex {}
 
 impl ReentrantMutex {
     pub const unsafe fn uninitialized() -> ReentrantMutex {
-        unsafe { ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) } }
+        ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
     }
 
     pub unsafe fn init(&self) {

From 75bbd80c098c240ffe0f97f50670e4cb66dc59c3 Mon Sep 17 00:00:00 2001
From: Alex Macleod <alex@macleod.io>
Date: Fri, 23 Oct 2020 18:41:07 +0100
Subject: [PATCH 20/24] Add some regression tests

Closes #56229
Closes #59494
Closes #70746
Closes #73229
---
 src/test/ui/issues/issue-56229.rs     | 35 +++++++++++++++++++++++++++
 src/test/ui/issues/issue-59494.rs     | 23 ++++++++++++++++++
 src/test/ui/issues/issue-59494.stderr | 14 +++++++++++
 src/test/ui/issues/issue-70746.rs     | 29 ++++++++++++++++++++++
 src/test/ui/issues/issue-73229.rs     | 33 +++++++++++++++++++++++++
 5 files changed, 134 insertions(+)
 create mode 100644 src/test/ui/issues/issue-56229.rs
 create mode 100644 src/test/ui/issues/issue-59494.rs
 create mode 100644 src/test/ui/issues/issue-59494.stderr
 create mode 100644 src/test/ui/issues/issue-70746.rs
 create mode 100644 src/test/ui/issues/issue-73229.rs

diff --git a/src/test/ui/issues/issue-56229.rs b/src/test/ui/issues/issue-56229.rs
new file mode 100644
index 0000000000000..9e5897b98925a
--- /dev/null
+++ b/src/test/ui/issues/issue-56229.rs
@@ -0,0 +1,35 @@
+// check-pass
+
+trait Mirror {
+    type Other;
+}
+
+#[derive(Debug)]
+struct Even(usize);
+struct Odd;
+
+impl Mirror for Even {
+    type Other = Odd;
+}
+
+impl Mirror for Odd {
+    type Other = Even;
+}
+
+trait Dyn<T: Mirror>: AsRef<<T as Mirror>::Other> {}
+
+impl Dyn<Odd> for Even {}
+
+impl AsRef<Even> for Even {
+    fn as_ref(&self) -> &Even {
+        self
+    }
+}
+
+fn code<T: Mirror>(d: &dyn Dyn<T>) -> &T::Other {
+    d.as_ref()
+}
+
+fn main() {
+    println!("{:?}", code(&Even(22)));
+}
diff --git a/src/test/ui/issues/issue-59494.rs b/src/test/ui/issues/issue-59494.rs
new file mode 100644
index 0000000000000..06b8eb777c035
--- /dev/null
+++ b/src/test/ui/issues/issue-59494.rs
@@ -0,0 +1,23 @@
+fn t7p<A, B, C>(f: impl Fn(B) -> C, g: impl Fn(A) -> B) -> impl Fn(A) -> C {
+    move |a: A| -> C { f(g(a)) }
+}
+
+fn t8n<A, B, C>(f: impl Fn(A) -> B, g: impl Fn(A) -> C) -> impl Fn(A) -> (B, C)
+where
+    A: Copy,
+{
+    move |a: A| -> (B, C) {
+        let b = a;
+        let fa = f(a);
+        let ga = g(b);
+        (fa, ga)
+    }
+}
+
+fn main() {
+    let f = |(_, _)| {};
+    let g = |(a, _)| a;
+    let t7 = |env| |a| |b| t7p(f, g)(((env, a), b));
+    let t8 = t8n(t7, t7p(f, g));
+    //~^ ERROR: expected a `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>
+}
diff --git a/src/test/ui/issues/issue-59494.stderr b/src/test/ui/issues/issue-59494.stderr
new file mode 100644
index 0000000000000..e2ac5d94da108
--- /dev/null
+++ b/src/test/ui/issues/issue-59494.stderr
@@ -0,0 +1,14 @@
+error[E0277]: expected a `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>`
+  --> $DIR/issue-59494.rs:21:22
+   |
+LL | fn t8n<A, B, C>(f: impl Fn(A) -> B, g: impl Fn(A) -> C) -> impl Fn(A) -> (B, C)
+   |                                             ---------- required by this bound in `t8n`
+...
+LL |     let t8 = t8n(t7, t7p(f, g));
+   |                      ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>`
+   |
+   = help: the trait `Fn<(_,)>` is not implemented for `impl Fn<(((_, _), _),)>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-70746.rs b/src/test/ui/issues/issue-70746.rs
new file mode 100644
index 0000000000000..8930c15f57edc
--- /dev/null
+++ b/src/test/ui/issues/issue-70746.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+pub trait Trait1 {
+    type C;
+}
+
+struct T1;
+impl Trait1 for T1 {
+    type C = usize;
+}
+pub trait Callback<T: Trait1>: FnMut(<T as Trait1>::C) {}
+impl<T: Trait1, F: FnMut(<T as Trait1>::C)> Callback<T> for F {}
+
+pub struct State<T: Trait1> {
+    callback: Option<Box<dyn Callback<T>>>,
+}
+impl<T: Trait1> State<T> {
+    fn new() -> Self {
+        Self { callback: None }
+    }
+    fn test_cb(&mut self, d: <T as Trait1>::C) {
+        (self.callback.as_mut().unwrap())(d)
+    }
+}
+
+fn main() {
+    let mut s = State::<T1>::new();
+    s.test_cb(1);
+}
diff --git a/src/test/ui/issues/issue-73229.rs b/src/test/ui/issues/issue-73229.rs
new file mode 100644
index 0000000000000..35346199add92
--- /dev/null
+++ b/src/test/ui/issues/issue-73229.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+fn any<T>() -> T {
+    loop {}
+}
+
+trait Foo {
+    type V;
+}
+
+trait Callback<T: Foo>: Fn(&T, &T::V) {}
+impl<T: Foo, F: Fn(&T, &T::V)> Callback<T> for F {}
+
+struct Bar<T: Foo> {
+    callback: Box<dyn Callback<T>>,
+}
+
+impl<T: Foo> Bar<T> {
+    fn event(&self) {
+        (self.callback)(any(), any());
+    }
+}
+
+struct A;
+struct B;
+impl Foo for A {
+    type V = B;
+}
+
+fn main() {
+    let foo = Bar::<A> { callback: Box::new(|_: &A, _: &B| ()) };
+    foo.event();
+}

From c6ab758e54bd509f75df7a21fd72aa740ac5a4b0 Mon Sep 17 00:00:00 2001
From: Jake Goulding <jake.goulding@gmail.com>
Date: Sat, 24 Oct 2020 09:44:57 -0400
Subject: [PATCH 21/24] Switch from tuple matching to match guards

---
 compiler/rustc_codegen_llvm/src/va_arg.rs | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 5f820f83a9438..0d4aa08a873b4 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -173,26 +173,24 @@ pub(super) fn emit_va_arg(
     // is lacking in some instances, so we should only use it as a fallback.
     let target = &bx.cx.tcx.sess.target;
     let arch = &bx.cx.tcx.sess.target.arch;
-    match (&**arch, target.options.is_like_windows) {
+    match &**arch {
         // Windows x86
-        ("x86", true) => {
+        "x86" if target.options.is_like_windows => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(4).unwrap(), false)
         }
         // Generic x86
-        ("x86", _) => {
-            emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(4).unwrap(), true)
-        }
+        "x86" => emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(4).unwrap(), true),
         // Windows AArch64
-        ("aarch64", true) => {
+        "aarch64" if target.options.is_like_windows => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), false)
         }
         // iOS AArch64
-        ("aarch64", _) if target.target_os == "ios" => {
+        "aarch64" if target.target_os == "ios" => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
         }
-        ("aarch64", _) => emit_aapcs_va_arg(bx, addr, target_ty),
+        "aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
         // Windows x86_64
-        ("x86_64", true) => {
+        "x86_64" if target.options.is_like_windows => {
             let target_ty_size = bx.cx.size_of(target_ty).bytes();
             let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two();
             emit_ptr_va_arg(bx, addr, target_ty, indirect, Align::from_bytes(8).unwrap(), false)

From 7b4c397b73912d3c604667933fb7e64f0c1a366a Mon Sep 17 00:00:00 2001
From: Yuki Okushi <huyuumi.dev@gmail.com>
Date: Fri, 23 Oct 2020 18:00:18 +0900
Subject: [PATCH 22/24] Do not try to report on closures to avoid ICE

---
 .../nice_region_error/static_impl_trait.rs     |  8 ++++++++
 src/test/ui/regions/issue-78262.rs             |  9 +++++++++
 src/test/ui/regions/issue-78262.stderr         | 18 ++++++++++++++++++
 3 files changed, 35 insertions(+)
 create mode 100644 src/test/ui/regions/issue-78262.rs
 create mode 100644 src/test/ui/regions/issue-78262.stderr

diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 441cfeea20a48..e9d5ebad7de03 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -39,6 +39,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             ) if **sub_r == RegionKind::ReStatic => {
                 // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
                 if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
+                    // This may have a closure and it would cause ICE
+                    // through `find_param_with_region` (#78262).
+                    let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+                    let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
+                    if fn_returns.is_empty() {
+                        return None;
+                    }
+
                     let param = self.find_param_with_region(sup_r, sub_r)?;
                     let lifetime = if sup_r.has_name() {
                         format!("lifetime `{}`", sup_r)
diff --git a/src/test/ui/regions/issue-78262.rs b/src/test/ui/regions/issue-78262.rs
new file mode 100644
index 0000000000000..2324152d2c081
--- /dev/null
+++ b/src/test/ui/regions/issue-78262.rs
@@ -0,0 +1,9 @@
+trait TT {}
+
+impl dyn TT {
+    fn func(&self) {}
+}
+
+fn main() {
+    let f = |x: &dyn TT| x.func(); //~ ERROR: mismatched types
+}
diff --git a/src/test/ui/regions/issue-78262.stderr b/src/test/ui/regions/issue-78262.stderr
new file mode 100644
index 0000000000000..580cea00ecd4f
--- /dev/null
+++ b/src/test/ui/regions/issue-78262.stderr
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-78262.rs:8:28
+   |
+LL |     let f = |x: &dyn TT| x.func();
+   |                            ^^^^ lifetime mismatch
+   |
+   = note: expected reference `&(dyn TT + 'static)`
+              found reference `&dyn TT`
+note: the anonymous lifetime #1 defined on the body at 8:13...
+  --> $DIR/issue-78262.rs:8:13
+   |
+LL |     let f = |x: &dyn TT| x.func();
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.

From 4ec396ea5dd7bddfaa667766ab6cd8824c8028da Mon Sep 17 00:00:00 2001
From: Yuki Okushi <huyuumi.dev@gmail.com>
Date: Sun, 25 Oct 2020 11:43:26 +0900
Subject: [PATCH 23/24] Test with NLL explicitly

---
 .../{issue-78262.stderr => issue-78262.default.stderr} |  6 +++---
 src/test/ui/regions/issue-78262.nll.stderr             | 10 ++++++++++
 src/test/ui/regions/issue-78262.rs                     |  7 ++++++-
 3 files changed, 19 insertions(+), 4 deletions(-)
 rename src/test/ui/regions/{issue-78262.stderr => issue-78262.default.stderr} (79%)
 create mode 100644 src/test/ui/regions/issue-78262.nll.stderr

diff --git a/src/test/ui/regions/issue-78262.stderr b/src/test/ui/regions/issue-78262.default.stderr
similarity index 79%
rename from src/test/ui/regions/issue-78262.stderr
rename to src/test/ui/regions/issue-78262.default.stderr
index 580cea00ecd4f..e97b8eca94892 100644
--- a/src/test/ui/regions/issue-78262.stderr
+++ b/src/test/ui/regions/issue-78262.default.stderr
@@ -1,13 +1,13 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-78262.rs:8:28
+  --> $DIR/issue-78262.rs:12:28
    |
 LL |     let f = |x: &dyn TT| x.func();
    |                            ^^^^ lifetime mismatch
    |
    = note: expected reference `&(dyn TT + 'static)`
               found reference `&dyn TT`
-note: the anonymous lifetime #1 defined on the body at 8:13...
-  --> $DIR/issue-78262.rs:8:13
+note: the anonymous lifetime #1 defined on the body at 12:13...
+  --> $DIR/issue-78262.rs:12:13
    |
 LL |     let f = |x: &dyn TT| x.func();
    |             ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/regions/issue-78262.nll.stderr b/src/test/ui/regions/issue-78262.nll.stderr
new file mode 100644
index 0000000000000..4607dbad4220b
--- /dev/null
+++ b/src/test/ui/regions/issue-78262.nll.stderr
@@ -0,0 +1,10 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/issue-78262.rs:12:26
+   |
+LL |     let f = |x: &dyn TT| x.func();
+   |              -           ^^^^^^^^ `x` escapes the closure body here
+   |              |
+   |              `x` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/issue-78262.rs b/src/test/ui/regions/issue-78262.rs
index 2324152d2c081..0bdb0abac307d 100644
--- a/src/test/ui/regions/issue-78262.rs
+++ b/src/test/ui/regions/issue-78262.rs
@@ -1,3 +1,7 @@
+// revisions: nll default
+// ignore-compare-mode-nll
+//[nll]compile-flags: -Z borrowck=mir
+
 trait TT {}
 
 impl dyn TT {
@@ -5,5 +9,6 @@ impl dyn TT {
 }
 
 fn main() {
-    let f = |x: &dyn TT| x.func(); //~ ERROR: mismatched types
+    let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types
+    //[nll]~^ ERROR: borrowed data escapes outside of closure
 }

From 0a91755ff4b6899e1c0675c48b4652e890ce63aa Mon Sep 17 00:00:00 2001
From: Jake Goulding <jake.goulding@gmail.com>
Date: Mon, 19 Oct 2020 21:48:58 -0400
Subject: [PATCH 24/24] Properly define va_arg and va_list for
 aarch64-apple-darwin

From [Apple][]:

> Because of these changes, the type `va_list` is an alias for `char*`,
> and not for the struct type in the generic procedure call standard.

With this change `/x.py test --stage 1 src/test/ui/abi/variadic-ffi`
passes.

Fixes #78092

[Apple]: https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms
---
 compiler/rustc_codegen_llvm/src/va_arg.rs |  4 ++--
 library/core/src/ffi.rs                   | 18 +++++++++++-------
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 0d4aa08a873b4..b6a0516b8bc9c 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -184,8 +184,8 @@ pub(super) fn emit_va_arg(
         "aarch64" if target.options.is_like_windows => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), false)
         }
-        // iOS AArch64
-        "aarch64" if target.target_os == "ios" => {
+        // macOS / iOS AArch64
+        "aarch64" if target.options.is_like_osx => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
         }
         "aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs
index e146a97ae94d1..4b303acfd3bfb 100644
--- a/library/core/src/ffi.rs
+++ b/library/core/src/ffi.rs
@@ -62,7 +62,7 @@ impl fmt::Debug for c_void {
 // The name is WIP, using `VaListImpl` for now.
 #[cfg(any(
     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
-    all(target_arch = "aarch64", target_os = "ios"),
+    all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_arch = "wasm32",
     target_arch = "asmjs",
     windows
@@ -85,7 +85,7 @@ pub struct VaListImpl<'f> {
 
 #[cfg(any(
     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
-    all(target_arch = "aarch64", target_os = "ios"),
+    all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_arch = "wasm32",
     target_arch = "asmjs",
     windows
@@ -107,7 +107,11 @@ impl<'f> fmt::Debug for VaListImpl<'f> {
 ///
 /// [AArch64 Procedure Call Standard]:
 /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
-#[cfg(all(target_arch = "aarch64", not(target_os = "ios"), not(windows)))]
+#[cfg(all(
+    target_arch = "aarch64",
+    not(any(target_os = "macos", target_os = "ios")),
+    not(windows)
+))]
 #[repr(C)]
 #[derive(Debug)]
 #[unstable(
@@ -181,7 +185,7 @@ pub struct VaList<'a, 'f: 'a> {
             not(target_arch = "powerpc"),
             not(target_arch = "x86_64")
         ),
-        all(target_arch = "aarch64", target_os = "ios"),
+        all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
         target_arch = "wasm32",
         target_arch = "asmjs",
         windows
@@ -190,7 +194,7 @@ pub struct VaList<'a, 'f: 'a> {
 
     #[cfg(all(
         any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
-        any(not(target_arch = "aarch64"), not(target_os = "ios")),
+        any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
         not(target_arch = "wasm32"),
         not(target_arch = "asmjs"),
         not(windows)
@@ -202,7 +206,7 @@ pub struct VaList<'a, 'f: 'a> {
 
 #[cfg(any(
     all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "x86_64")),
-    all(target_arch = "aarch64", target_os = "ios"),
+    all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_arch = "wasm32",
     target_arch = "asmjs",
     windows
@@ -223,7 +227,7 @@ impl<'f> VaListImpl<'f> {
 
 #[cfg(all(
     any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
-    any(not(target_arch = "aarch64"), not(target_os = "ios")),
+    any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
     not(target_arch = "wasm32"),
     not(target_arch = "asmjs"),
     not(windows)