about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-21 03:04:43 +0000
committerbors <bors@rust-lang.org>2022-01-21 03:04:43 +0000
commit523be2e05da322daaecf1ecc8f2c0d625f5f46e3 (patch)
tree95681d8d7471bb843edca4f3e988d4ec176e1b6f
parent777bb86bcdbc568be7cff6eeeaaf81a89b4aa50b (diff)
parentdd164313d52fbe174c05a37b2f90f184d09a2422 (diff)
downloadrust-523be2e05da322daaecf1ecc8f2c0d625f5f46e3.tar.gz
rust-523be2e05da322daaecf1ecc8f2c0d625f5f46e3.zip
Auto merge of #93138 - matthiaskrgr:rollup-m8akifd, r=matthiaskrgr
Rollup of 17 pull requests

Successful merges:

 - #91032 (Introduce drop range tracking to generator interior analysis)
 - #92856 (Exclude "test" from doc_auto_cfg)
 - #92860 (Fix errors on blanket impls by ignoring the children of generated impls)
 - #93038 (Fix star handling in block doc comments)
 - #93061 (Only suggest adding `!` to expressions that can be macro invocation)
 - #93067 (rustdoc mobile: fix scroll offset when jumping to internal id)
 - #93086 (Add tests to ensure that `let_chains` works with `if_let_guard`)
 - #93087 (Fix src/test/run-make/raw-dylib-alt-calling-convention)
 - #93091 (⬆ chalk to 0.76.0)
 - #93094 (src/test/rustdoc-json: Check for `struct_field`s in `variant_tuple_struct.rs`)
 - #93098 (Show a more informative panic message when `DefPathHash` does not exist)
 - #93099 (rustdoc: auto create output directory when "--output-format json")
 - #93102 (Pretty printer algorithm revamp step 3)
 - #93104 (Support --bless for pp-exact pretty printer tests)
 - #93114 (update comment for `ensure_monomorphic_enough`)
 - #93128 (Add script to prevent point releases with same number as existing ones)
 - #93136 (Backport the 1.58.1 release notes to master)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--.github/workflows/ci.yml9
-rw-r--r--Cargo.lock19
-rw-r--r--RELEASES.md15
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs205
-rw-r--r--compiler/rustc_ast_pretty/src/pp/ring.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs6
-rw-r--r--compiler/rustc_hir/src/definitions.rs8
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs4
-rw-r--r--compiler/rustc_middle/src/middle/region.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs7
-rw-r--r--compiler/rustc_passes/src/region.rs11
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs11
-rw-r--r--compiler/rustc_traits/Cargo.toml6
-rw-r--r--compiler/rustc_typeck/Cargo.toml2
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs48
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs269
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs473
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs92
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs77
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs118
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs2
-rw-r--r--src/ci/github-actions/ci.yml4
-rwxr-xr-xsrc/ci/scripts/verify-stable-version-number.sh30
-rw-r--r--src/librustdoc/clean/cfg.rs53
-rw-r--r--src/librustdoc/clean/types.rs5
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css9
-rw-r--r--src/librustdoc/json/mod.rs27
-rw-r--r--src/librustdoc/visit_ast.rs1
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/Makefile7
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/lib.rs7
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/output.txt2
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile.goml6
-rw-r--r--src/test/rustdoc-json/enums/variant_struct.rs4
-rw-r--r--src/test/rustdoc-json/enums/variant_tuple_struct.rs2
-rw-r--r--src/test/rustdoc-json/impls/blanket_with_local.rs14
-rw-r--r--src/test/rustdoc/doc-auto-cfg.rs10
-rw-r--r--src/test/rustdoc/doc-cfg-hide.rs2
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.rs25
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.stderr51
-rw-r--r--src/test/ui/async-await/partial-drop-partial-reinit.rs29
-rw-r--r--src/test/ui/async-await/partial-drop-partial-reinit.stderr27
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs8
-rw-r--r--src/test/ui/async-await/unresolved_type_param.stderr26
-rw-r--r--src/test/ui/generator/drop-control-flow.rs121
-rw-r--r--src/test/ui/generator/drop-yield-twice.rs15
-rw-r--r--src/test/ui/generator/drop-yield-twice.stderr25
-rw-r--r--src/test/ui/generator/issue-57478.rs16
-rw-r--r--src/test/ui/generator/partial-drop.rs40
-rw-r--r--src/test/ui/generator/partial-drop.stderr71
-rw-r--r--src/test/ui/generator/reinit-in-match-guard.rs25
-rw-r--r--src/test/ui/hygiene/rustc-macro-transparency.stderr28
-rw-r--r--src/test/ui/lint/must_not_suspend/dedup.rs2
-rw-r--r--src/test/ui/lint/must_not_suspend/dedup.stderr12
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.fixed11
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.rs7
-rw-r--r--src/test/ui/resolve/resolve-hint-macro.stderr45
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs12
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs16
-rw-r--r--src/tools/compiletest/src/runtest.rs14
62 files changed, 1902 insertions, 316 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fe5dedb6ba4..1f872569ab1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -128,6 +128,9 @@ jobs:
       - name: ensure backported commits are in upstream branches
         run: src/ci/scripts/verify-backported-commits.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
@@ -502,6 +505,9 @@ jobs:
       - name: ensure backported commits are in upstream branches
         run: src/ci/scripts/verify-backported-commits.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
@@ -612,6 +618,9 @@ jobs:
       - name: ensure backported commits are in upstream branches
         run: src/ci/scripts/verify-backported-commits.sh
         if: success() && !env.SKIP_JOB
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        if: success() && !env.SKIP_JOB
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
diff --git a/Cargo.lock b/Cargo.lock
index a7496e61b8b..e0d2abc08fc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -544,9 +544,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54e3b5f9e3425e6b119ff07568d8d006bfa5a8d6f78a9cbc3530b1e962e316c"
+checksum = "58c24b8052ea1e3adbb6f9ab7ba5fcc18b9d12591c042de4c833f709ce81e0e0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -556,9 +556,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-engine"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdc891073396b167163db77123b0a3c00088edc00466cecc5531f33e3e989523"
+checksum = "0eca186b6ea9af798312f4b568fd094c82e7946ac08be5dc5fea22decc6d2ed8"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -569,9 +569,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b79e5a1d04b79311e90c69356a2c62027853906a7e33b3e070b93c055fc3e8a"
+checksum = "f3cad5c3f1edd4b4a2c9bda24ae558ceb4f88336f88f944c2e35d0bfeb13c818"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -580,13 +580,14 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.75.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5d2a1db6605aba70a58820bd80ac422b218913a510f1a40beef9efc5371ea1d"
+checksum = "94533188d3452bc72cbd5618d166f45fc7646b674ad3fe9667d557bc25236dee"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
  "ena",
+ "indexmap",
  "itertools 0.10.1",
  "petgraph",
  "rustc-hash",
@@ -4413,6 +4414,7 @@ dependencies = [
  "rustc_attr",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_graphviz",
  "rustc_hir",
  "rustc_hir_pretty",
  "rustc_index",
@@ -4420,6 +4422,7 @@ dependencies = [
  "rustc_lint",
  "rustc_macros",
  "rustc_middle",
+ "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
diff --git a/RELEASES.md b/RELEASES.md
index 460c78b14d1..f44291c1fa3 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,18 @@
+Version 1.58.1 (2022-01-19)
+===========================
+
+* Fix race condition in `std::fs::remove_dir_all` ([CVE-2022-21658])
+* [Handle captured arguments in the `useless_format` Clippy lint][clippy/8295]
+* [Move `non_send_fields_in_send_ty` Clippy lint to nursery][clippy/8075]
+* [Fix wrong error message displayed when some imports are missing][91254]
+* [Fix rustfmt not formatting generated files from stdin][92912]
+
+[CVE-2022-21658]: https://www.cve.org/CVERecord?id=CVE-2022-21658]
+[91254]: https://github.com/rust-lang/rust/pull/91254
+[92912]: https://github.com/rust-lang/rust/pull/92912
+[clippy/8075]: https://github.com/rust-lang/rust-clippy/pull/8075
+[clippy/8295]: https://github.com/rust-lang/rust-clippy/pull/8295
+
 Version 1.58.0 (2022-01-13)
 ==========================
 
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index bdd70148d85..82c40868d18 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -137,7 +137,7 @@ mod ring;
 use ring::RingBuffer;
 use std::borrow::Cow;
 use std::collections::VecDeque;
-use std::fmt;
+use std::iter;
 
 /// How to break. Described in more detail in the module docs.
 #[derive(Clone, Copy, PartialEq)]
@@ -175,27 +175,10 @@ impl Token {
     }
 }
 
-impl fmt::Display for Token {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Token::String(ref s) => write!(f, "STR({},{})", s, s.len()),
-            Token::Break(_) => f.write_str("BREAK"),
-            Token::Begin(_) => f.write_str("BEGIN"),
-            Token::End => f.write_str("END"),
-        }
-    }
-}
-
 #[derive(Copy, Clone)]
-enum PrintStackBreak {
+enum PrintFrame {
     Fits,
-    Broken(Breaks),
-}
-
-#[derive(Copy, Clone)]
-struct PrintStackElem {
-    offset: isize,
-    pbreak: PrintStackBreak,
+    Broken { offset: isize, breaks: Breaks },
 }
 
 const SIZE_INFINITY: isize = 0xffff;
@@ -220,7 +203,7 @@ pub struct Printer {
     /// advancing.
     scan_stack: VecDeque<usize>,
     /// Stack of blocks-in-progress being flushed by print
-    print_stack: Vec<PrintStackElem>,
+    print_stack: Vec<PrintFrame>,
     /// Buffered indentation to avoid writing trailing whitespace
     pending_indentation: isize,
     /// The token most recently popped from the left boundary of the
@@ -260,8 +243,8 @@ impl Printer {
     }
 
     /// Be very careful with this!
-    pub fn replace_last_token_still_buffered(&mut self, t: Token) {
-        self.buf.last_mut().unwrap().token = t;
+    pub fn replace_last_token_still_buffered(&mut self, token: Token) {
+        self.buf.last_mut().unwrap().token = token;
     }
 
     fn scan_eof(&mut self) {
@@ -271,14 +254,14 @@ impl Printer {
         }
     }
 
-    fn scan_begin(&mut self, b: BeginToken) {
+    fn scan_begin(&mut self, token: BeginToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
             self.buf.clear();
         }
-        let right = self.buf.push(BufEntry { token: Token::Begin(b), size: -self.right_total });
-        self.scan_stack.push_front(right);
+        let right = self.buf.push(BufEntry { token: Token::Begin(token), size: -self.right_total });
+        self.scan_stack.push_back(right);
     }
 
     fn scan_end(&mut self) {
@@ -286,11 +269,11 @@ impl Printer {
             self.print_end();
         } else {
             let right = self.buf.push(BufEntry { token: Token::End, size: -1 });
-            self.scan_stack.push_front(right);
+            self.scan_stack.push_back(right);
         }
     }
 
-    fn scan_break(&mut self, b: BreakToken) {
+    fn scan_break(&mut self, token: BreakToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
@@ -298,17 +281,17 @@ impl Printer {
         } else {
             self.check_stack(0);
         }
-        let right = self.buf.push(BufEntry { token: Token::Break(b), size: -self.right_total });
-        self.scan_stack.push_front(right);
-        self.right_total += b.blank_space;
+        let right = self.buf.push(BufEntry { token: Token::Break(token), size: -self.right_total });
+        self.scan_stack.push_back(right);
+        self.right_total += token.blank_space;
     }
 
-    fn scan_string(&mut self, s: Cow<'static, str>) {
+    fn scan_string(&mut self, string: Cow<'static, str>) {
         if self.scan_stack.is_empty() {
-            self.print_string(&s);
+            self.print_string(&string);
         } else {
-            let len = s.len() as isize;
-            self.buf.push(BufEntry { token: Token::String(s), size: len });
+            let len = string.len() as isize;
+            self.buf.push(BufEntry { token: Token::String(string), size: len });
             self.right_total += len;
             self.check_stream();
         }
@@ -316,8 +299,8 @@ impl Printer {
 
     fn check_stream(&mut self) {
         while self.right_total - self.left_total > self.space {
-            if *self.scan_stack.back().unwrap() == self.buf.index_of_first() {
-                self.scan_stack.pop_back().unwrap();
+            if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
+                self.scan_stack.pop_front().unwrap();
                 self.buf.first_mut().unwrap().size = SIZE_INFINITY;
             }
             self.advance_left();
@@ -328,56 +311,52 @@ impl Printer {
     }
 
     fn advance_left(&mut self) {
-        let mut left_size = self.buf.first().unwrap().size;
-
-        while left_size >= 0 {
-            let left = self.buf.first().unwrap().token.clone();
+        while self.buf.first().unwrap().size >= 0 {
+            let left = self.buf.pop_first().unwrap();
 
-            let len = match left {
-                Token::Break(b) => b.blank_space,
-                Token::String(ref s) => {
-                    let len = s.len() as isize;
-                    assert_eq!(len, left_size);
-                    len
+            match &left.token {
+                Token::String(string) => {
+                    self.left_total += string.len() as isize;
+                    self.print_string(string);
                 }
-                _ => 0,
-            };
-
-            self.print(left, left_size);
+                Token::Break(token) => {
+                    self.left_total += token.blank_space;
+                    self.print_break(*token, left.size);
+                }
+                Token::Begin(token) => self.print_begin(*token, left.size),
+                Token::End => self.print_end(),
+            }
 
-            self.left_total += len;
+            self.last_printed = Some(left.token);
 
-            self.buf.advance_left();
             if self.buf.is_empty() {
                 break;
             }
-
-            left_size = self.buf.first().unwrap().size;
         }
     }
 
-    fn check_stack(&mut self, mut k: usize) {
-        while let Some(&x) = self.scan_stack.front() {
-            let mut entry = &mut self.buf[x];
+    fn check_stack(&mut self, mut depth: usize) {
+        while let Some(&index) = self.scan_stack.back() {
+            let mut entry = &mut self.buf[index];
             match entry.token {
                 Token::Begin(_) => {
-                    if k == 0 {
+                    if depth == 0 {
                         break;
                     }
-                    self.scan_stack.pop_front().unwrap();
+                    self.scan_stack.pop_back().unwrap();
                     entry.size += self.right_total;
-                    k -= 1;
+                    depth -= 1;
                 }
                 Token::End => {
                     // paper says + not =, but that makes no sense.
-                    self.scan_stack.pop_front().unwrap();
+                    self.scan_stack.pop_back().unwrap();
                     entry.size = 1;
-                    k += 1;
+                    depth += 1;
                 }
                 _ => {
-                    self.scan_stack.pop_front().unwrap();
+                    self.scan_stack.pop_back().unwrap();
                     entry.size += self.right_total;
-                    if k == 0 {
+                    if depth == 0 {
                         break;
                     }
                 }
@@ -385,29 +364,19 @@ impl Printer {
         }
     }
 
-    fn print_newline(&mut self, amount: isize) {
-        self.out.push('\n');
-        self.pending_indentation = 0;
-        self.indent(amount);
-    }
-
-    fn indent(&mut self, amount: isize) {
-        self.pending_indentation += amount;
+    fn get_top(&self) -> PrintFrame {
+        *self
+            .print_stack
+            .last()
+            .unwrap_or(&PrintFrame::Broken { offset: 0, breaks: Breaks::Inconsistent })
     }
 
-    fn get_top(&self) -> PrintStackElem {
-        *self.print_stack.last().unwrap_or({
-            &PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
-        })
-    }
-
-    fn print_begin(&mut self, b: BeginToken, l: isize) {
-        if l > self.space {
-            let col = self.margin - self.space + b.offset;
-            self.print_stack
-                .push(PrintStackElem { offset: col, pbreak: PrintStackBreak::Broken(b.breaks) });
+    fn print_begin(&mut self, token: BeginToken, size: isize) {
+        if size > self.space {
+            let col = self.margin - self.space + token.offset;
+            self.print_stack.push(PrintFrame::Broken { offset: col, breaks: token.breaks });
         } else {
-            self.print_stack.push(PrintStackElem { offset: 0, pbreak: PrintStackBreak::Fits });
+            self.print_stack.push(PrintFrame::Fits);
         }
     }
 
@@ -415,34 +384,26 @@ impl Printer {
         self.print_stack.pop().unwrap();
     }
 
-    fn print_break(&mut self, b: BreakToken, l: isize) {
-        let top = self.get_top();
-        match top.pbreak {
-            PrintStackBreak::Fits => {
-                self.space -= b.blank_space;
-                self.indent(b.blank_space);
-            }
-            PrintStackBreak::Broken(Breaks::Consistent) => {
-                self.print_newline(top.offset + b.offset);
-                self.space = self.margin - (top.offset + b.offset);
-            }
-            PrintStackBreak::Broken(Breaks::Inconsistent) => {
-                if l > self.space {
-                    self.print_newline(top.offset + b.offset);
-                    self.space = self.margin - (top.offset + b.offset);
-                } else {
-                    self.indent(b.blank_space);
-                    self.space -= b.blank_space;
+    fn print_break(&mut self, token: BreakToken, size: isize) {
+        let break_offset =
+            match self.get_top() {
+                PrintFrame::Fits => None,
+                PrintFrame::Broken { offset, breaks: Breaks::Consistent } => Some(offset),
+                PrintFrame::Broken { offset, breaks: Breaks::Inconsistent } => {
+                    if size > self.space { Some(offset) } else { None }
                 }
-            }
+            };
+        if let Some(offset) = break_offset {
+            self.out.push('\n');
+            self.pending_indentation = offset + token.offset;
+            self.space = self.margin - (offset + token.offset);
+        } else {
+            self.pending_indentation += token.blank_space;
+            self.space -= token.blank_space;
         }
     }
 
-    fn print_string(&mut self, s: &str) {
-        let len = s.len() as isize;
-        // assert!(len <= space);
-        self.space -= len;
-
+    fn print_string(&mut self, string: &str) {
         // Write the pending indent. A more concise way of doing this would be:
         //
         //   write!(self.out, "{: >n$}", "", n = self.pending_indentation as usize)?;
@@ -450,30 +411,18 @@ impl Printer {
         // But that is significantly slower. This code is sufficiently hot, and indents can get
         // sufficiently large, that the difference is significant on some workloads.
         self.out.reserve(self.pending_indentation as usize);
-        self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
+        self.out.extend(iter::repeat(' ').take(self.pending_indentation as usize));
         self.pending_indentation = 0;
-        self.out.push_str(s);
-    }
 
-    fn print(&mut self, token: Token, l: isize) {
-        match &token {
-            Token::Begin(b) => self.print_begin(*b, l),
-            Token::End => self.print_end(),
-            Token::Break(b) => self.print_break(*b, l),
-            Token::String(s) => {
-                let len = s.len() as isize;
-                assert_eq!(len, l);
-                self.print_string(s);
-            }
-        }
-        self.last_printed = Some(token);
+        self.out.push_str(string);
+        self.space -= string.len() as isize;
     }
 
     // Convenience functions to talk to the printer.
 
     /// "raw box"
-    pub fn rbox(&mut self, indent: usize, b: Breaks) {
-        self.scan_begin(BeginToken { offset: indent as isize, breaks: b })
+    pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
+        self.scan_begin(BeginToken { offset: indent as isize, breaks })
     }
 
     /// Inconsistent breaking box
@@ -500,8 +449,8 @@ impl Printer {
     }
 
     pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
-        let s = wrd.into();
-        self.scan_string(s)
+        let string = wrd.into();
+        self.scan_string(string)
     }
 
     fn spaces(&mut self, n: usize) {
diff --git a/compiler/rustc_ast_pretty/src/pp/ring.rs b/compiler/rustc_ast_pretty/src/pp/ring.rs
index d20142eb591..8187394fe30 100644
--- a/compiler/rustc_ast_pretty/src/pp/ring.rs
+++ b/compiler/rustc_ast_pretty/src/pp/ring.rs
@@ -32,11 +32,6 @@ impl<T> RingBuffer<T> {
         index
     }
 
-    pub fn advance_left(&mut self) {
-        self.data.pop_front().unwrap();
-        self.offset += 1;
-    }
-
     pub fn clear(&mut self) {
         self.data.clear();
     }
@@ -53,6 +48,12 @@ impl<T> RingBuffer<T> {
         self.data.front_mut()
     }
 
+    pub fn pop_first(&mut self) -> Option<T> {
+        let first = self.data.pop_front()?;
+        self.offset += 1;
+        Some(first)
+    }
+
     pub fn last(&self) -> Option<&T> {
         self.data.back()
     }
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 3dde34a6410..6a3378a3896 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -3,7 +3,11 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use std::convert::TryInto;
 use std::ops::ControlFlow;
 
-/// Returns `true` if a used generic parameter requires substitution.
+/// Checks whether a type contains generic parameters which require substitution.
+///
+/// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization
+/// types may be "concrete enough" even though they still contain generic parameters in
+/// case these parameters are unused.
 crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
 where
     T: TypeFoldable<'tcx>,
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index d813c887eee..e839f7fc777 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -449,13 +449,17 @@ impl Definitions {
     }
 
     #[inline(always)]
-    pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> LocalDefId {
+    pub fn local_def_path_hash_to_def_id(
+        &self,
+        hash: DefPathHash,
+        err: &mut dyn FnMut() -> !,
+    ) -> LocalDefId {
         debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
         self.table
             .def_path_hash_to_index
             .get(&hash)
             .map(|local_def_index| LocalDefId { local_def_index })
-            .unwrap()
+            .unwrap_or_else(|| err())
     }
 
     pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 30664784ed8..b1334410237 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -29,7 +29,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.75.0"
+chalk-ir = "0.76.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_session = { path = "../rustc_session" }
 rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 5c7cdbe4c2b..d20be0a34d2 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -266,7 +266,9 @@ impl DepNodeExt for DepNode {
     /// has been removed.
     fn extract_def_id<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
         if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
-            Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())))
+            Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
+                panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
+            }))
         } else {
             None
         }
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 39ca41c92ff..75dd223d014 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -308,7 +308,7 @@ pub struct ScopeTree {
     /// The reason is that semantically, until the `box` expression returns,
     /// the values are still owned by their containing expressions. So
     /// we'll see that `&x`.
-    pub yield_in_scope: FxHashMap<Scope, YieldData>,
+    pub yield_in_scope: FxHashMap<Scope, Vec<YieldData>>,
 
     /// The number of visit_expr and visit_pat calls done in the body.
     /// Used to sanity check visit_expr/visit_pat call count when
@@ -423,8 +423,8 @@ impl ScopeTree {
 
     /// Checks whether the given scope contains a `yield`. If so,
     /// returns `Some(YieldData)`. If not, returns `None`.
-    pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
-        self.yield_in_scope.get(&scope).cloned()
+    pub fn yield_in_scope(&self, scope: Scope) -> Option<&Vec<YieldData>> {
+        self.yield_in_scope.get(&scope)
     }
 
     /// Gives the number of expressions visited in a body.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 8d591d67812..a7d7ee5efc8 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1322,7 +1322,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
     /// session, if it still exists. This is used during incremental compilation to
     /// turn a deserialized `DefPathHash` into its current `DefId`.
-    pub fn def_path_hash_to_def_id(self, hash: DefPathHash) -> DefId {
+    pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() -> !) -> DefId {
         debug!("def_path_hash_to_def_id({:?})", hash);
 
         let stable_crate_id = hash.stable_crate_id();
@@ -1330,7 +1330,10 @@ impl<'tcx> TyCtxt<'tcx> {
         // If this is a DefPathHash from the local crate, we can look up the
         // DefId in the tcx's `Definitions`.
         if stable_crate_id == self.sess.local_stable_crate_id() {
-            self.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash).to_def_id()
+            self.untracked_resolutions
+                .definitions
+                .local_def_path_hash_to_def_id(hash, err)
+                .to_def_id()
         } else {
             // If this is a DefPathHash from an upstream crate, let the CrateStore map
             // it to a DefId.
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index db699a56645..fdf93e58932 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -366,7 +366,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             let target_scopes = visitor.fixup_scopes.drain(start_point..);
 
             for scope in target_scopes {
-                let mut yield_data = visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap();
+                let mut yield_data =
+                    visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap();
                 let count = yield_data.expr_and_pat_count;
                 let span = yield_data.span;
 
@@ -429,7 +430,13 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
             };
             let data =
                 YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source };
-            visitor.scope_tree.yield_in_scope.insert(scope, data);
+            match visitor.scope_tree.yield_in_scope.get_mut(&scope) {
+                Some(yields) => yields.push(data),
+                None => {
+                    visitor.scope_tree.yield_in_scope.insert(scope, vec![data]);
+                }
+            }
+
             if visitor.pessimistic_yield {
                 debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope);
                 visitor.fixup_scopes.push(scope);
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 6a88e123537..5f6d9b050b2 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -761,7 +761,9 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        Ok(d.tcx().def_path_hash_to_def_id(def_path_hash))
+        Ok(d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || {
+            panic!("Failed to convert DefPathHash {:?}", def_path_hash)
+        }))
     }
 }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ccaaa2eaf46..2c678e71ae1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2517,6 +2517,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 self.visit_expr(elem);
                 self.resolve_anon_const(ct, IsRepeatExpr::Yes);
             }
+            ExprKind::Index(ref elem, ref idx) => {
+                self.resolve_expr(elem, Some(expr));
+                self.visit_expr(idx);
+            }
             _ => {
                 visit::walk_expr(self, expr);
             }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 4cd1b34bedc..7b4fe6f0e07 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -970,7 +970,13 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         };
 
         match (res, source) {
-            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+            (
+                Res::Def(DefKind::Macro(MacroKind::Bang), _),
+                PathSource::Expr(Some(Expr {
+                    kind: ExprKind::Index(..) | ExprKind::Call(..), ..
+                }))
+                | PathSource::Struct,
+            ) => {
                 err.span_label(span, fallback_label);
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
@@ -982,6 +988,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     err.note("if you want the `try` keyword, you need Rust 2018 or later");
                 }
             }
+            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+                err.span_label(span, fallback_label);
+            }
             (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
                 err.span_label(span, "type aliases cannot be used as traits");
                 if self.r.session.is_nightly_build() {
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index f22751dc740..25f228c7890 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.75.0"
-chalk-engine = "0.75.0"
-chalk-solve = "0.75.0"
+chalk-ir = "0.76.0"
+chalk-engine = "0.76.0"
+chalk-solve = "0.76.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index 7e570e151c5..57930a28a35 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -15,6 +15,7 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_target = { path = "../rustc_target" }
@@ -27,3 +28,4 @@ rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
 rustc_lint = { path = "../rustc_lint" }
+rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index fb6e11dbfb7..56b6dd9a284 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -3,6 +3,7 @@
 //! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
 //! types computed here.
 
+use self::drop_ranges::DropRanges;
 use super::FnCtxt;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::pluralize;
@@ -19,6 +20,8 @@ use rustc_span::Span;
 use smallvec::SmallVec;
 use tracing::debug;
 
+mod drop_ranges;
+
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
@@ -34,6 +37,7 @@ struct InteriorVisitor<'a, 'tcx> {
     guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
     guard_bindings_set: HirIdSet,
     linted_values: HirIdSet,
+    drop_ranges: DropRanges,
 }
 
 impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
@@ -48,9 +52,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
     ) {
         use rustc_span::DUMMY_SP;
 
+        let ty = self.fcx.resolve_vars_if_possible(ty);
+
         debug!(
-            "generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
-            ty, scope, expr, source_span
+            "attempting to record type ty={:?}; hir_id={:?}; scope={:?}; expr={:?}; source_span={:?}; expr_count={:?}",
+            ty, hir_id, scope, expr, source_span, self.expr_count,
         );
 
         let live_across_yield = scope
@@ -63,21 +69,27 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                     //
                     // See the mega-comment at `yield_in_scope` for a proof.
 
-                    debug!(
-                        "comparing counts yield: {} self: {}, source_span = {:?}",
-                        yield_data.expr_and_pat_count, self.expr_count, source_span
-                    );
+                    yield_data
+                        .iter()
+                        .find(|yield_data| {
+                            debug!(
+                                "comparing counts yield: {} self: {}, source_span = {:?}",
+                                yield_data.expr_and_pat_count, self.expr_count, source_span
+                            );
+
+                            if self.drop_ranges.is_dropped_at(hir_id, yield_data.expr_and_pat_count)
+                            {
+                                debug!("value is dropped at yield point; not recording");
+                                return false;
+                            }
 
-                    // If it is a borrowing happening in the guard,
-                    // it needs to be recorded regardless because they
-                    // do live across this yield point.
-                    if guard_borrowing_from_pattern
-                        || yield_data.expr_and_pat_count >= self.expr_count
-                    {
-                        Some(yield_data)
-                    } else {
-                        None
-                    }
+                            // If it is a borrowing happening in the guard,
+                            // it needs to be recorded regardless because they
+                            // do live across this yield point.
+                            guard_borrowing_from_pattern
+                                || yield_data.expr_and_pat_count >= self.expr_count
+                        })
+                        .cloned()
                 })
             })
             .unwrap_or_else(|| {
@@ -85,7 +97,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
             });
 
         if let Some(yield_data) = live_across_yield {
-            let ty = self.fcx.resolve_vars_if_possible(ty);
             debug!(
                 "type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
                 expr, scope, ty, self.expr_count, yield_data.span
@@ -154,7 +165,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                 self.expr_count,
                 expr.map(|e| e.span)
             );
-            let ty = self.fcx.resolve_vars_if_possible(ty);
             if let Some((unresolved_type, unresolved_type_span)) =
                 self.fcx.unresolved_type_vars(&ty)
             {
@@ -186,6 +196,7 @@ pub fn resolve_interior<'a, 'tcx>(
         guard_bindings: <_>::default(),
         guard_bindings_set: <_>::default(),
         linted_values: <_>::default(),
+        drop_ranges: drop_ranges::compute_drop_ranges(fcx, def_id, body),
     };
     intravisit::walk_body(&mut visitor, body);
 
@@ -313,6 +324,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         let mut guard_borrowing_from_pattern = false;
+
         match &expr.kind {
             ExprKind::Call(callee, args) => match &callee.kind {
                 ExprKind::Path(qpath) => {
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
new file mode 100644
index 00000000000..21a8d7b5634
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
@@ -0,0 +1,269 @@
+//! Drop range analysis finds the portions of the tree where a value is guaranteed to be dropped
+//! (i.e. moved, uninitialized, etc.). This is used to exclude the types of those values from the
+//! generator type. See `InteriorVisitor::record` for where the results of this analysis are used.
+//!
+//! There are three phases to this analysis:
+//! 1. Use `ExprUseVisitor` to identify the interesting values that are consumed and borrowed.
+//! 2. Use `DropRangeVisitor` to find where the interesting values are dropped or reinitialized,
+//!    and also build a control flow graph.
+//! 3. Use `DropRanges::propagate_to_fixpoint` to flow the dropped/reinitialized information through
+//!    the CFG and find the exact points where we know a value is definitely dropped.
+//!
+//! The end result is a data structure that maps the post-order index of each node in the HIR tree
+//! to a set of values that are known to be dropped at that location.
+
+use self::cfg_build::build_control_flow_graph;
+use self::record_consumed_borrow::find_consumed_and_borrowed;
+use crate::check::FnCtxt;
+use hir::def_id::DefId;
+use hir::{Body, HirId, HirIdMap, Node};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::hir::map::Map;
+use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
+use rustc_middle::ty;
+use std::collections::BTreeMap;
+use std::fmt::Debug;
+
+mod cfg_build;
+mod cfg_propagate;
+mod cfg_visualize;
+mod record_consumed_borrow;
+
+pub fn compute_drop_ranges<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    def_id: DefId,
+    body: &'tcx Body<'tcx>,
+) -> DropRanges {
+    let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
+
+    let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
+    let mut drop_ranges = build_control_flow_graph(
+        fcx.tcx.hir(),
+        fcx.tcx,
+        &fcx.typeck_results.borrow(),
+        consumed_borrowed_places,
+        body,
+        num_exprs,
+    );
+
+    drop_ranges.propagate_to_fixpoint();
+
+    DropRanges { tracked_value_map: drop_ranges.tracked_value_map, nodes: drop_ranges.nodes }
+}
+
+/// Applies `f` to consumable node in the HIR subtree pointed to by `place`.
+///
+/// This includes the place itself, and if the place is a reference to a local
+/// variable then `f` is also called on the HIR node for that variable as well.
+///
+/// For example, if `place` points to `foo()`, then `f` is called once for the
+/// result of `foo`. On the other hand, if `place` points to `x` then `f` will
+/// be called both on the `ExprKind::Path` node that represents the expression
+/// as well as the HirId of the local `x` itself.
+fn for_each_consumable<'tcx>(hir: Map<'tcx>, place: TrackedValue, mut f: impl FnMut(TrackedValue)) {
+    f(place);
+    let node = hir.find(place.hir_id());
+    if let Some(Node::Expr(expr)) = node {
+        match expr.kind {
+            hir::ExprKind::Path(hir::QPath::Resolved(
+                _,
+                hir::Path { res: hir::def::Res::Local(hir_id), .. },
+            )) => {
+                f(TrackedValue::Variable(*hir_id));
+            }
+            _ => (),
+        }
+    }
+}
+
+rustc_index::newtype_index! {
+    pub struct PostOrderId {
+        DEBUG_FORMAT = "id({})",
+    }
+}
+
+rustc_index::newtype_index! {
+    pub struct TrackedValueIndex {
+        DEBUG_FORMAT = "hidx({})",
+    }
+}
+
+/// Identifies a value whose drop state we need to track.
+#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
+enum TrackedValue {
+    /// Represents a named variable, such as a let binding, parameter, or upvar.
+    ///
+    /// The HirId points to the variable's definition site.
+    Variable(HirId),
+    /// A value produced as a result of an expression.
+    ///
+    /// The HirId points to the expression that returns this value.
+    Temporary(HirId),
+}
+
+impl TrackedValue {
+    fn hir_id(&self) -> HirId {
+        match self {
+            TrackedValue::Variable(hir_id) | TrackedValue::Temporary(hir_id) => *hir_id,
+        }
+    }
+}
+
+/// Represents a reason why we might not be able to convert a HirId or Place
+/// into a tracked value.
+#[derive(Debug)]
+enum TrackedValueConversionError {
+    /// Place projects are not currently supported.
+    ///
+    /// The reasoning around these is kind of subtle, so we choose to be more
+    /// conservative around these for now. There is not reason in theory we
+    /// cannot support these, we just have not implemented it yet.
+    PlaceProjectionsNotSupported,
+}
+
+impl TryFrom<&PlaceWithHirId<'_>> for TrackedValue {
+    type Error = TrackedValueConversionError;
+
+    fn try_from(place_with_id: &PlaceWithHirId<'_>) -> Result<Self, Self::Error> {
+        if !place_with_id.place.projections.is_empty() {
+            debug!(
+                "TrackedValue from PlaceWithHirId: {:?} has projections, which are not supported.",
+                place_with_id
+            );
+            return Err(TrackedValueConversionError::PlaceProjectionsNotSupported);
+        }
+
+        match place_with_id.place.base {
+            PlaceBase::Rvalue | PlaceBase::StaticItem => {
+                Ok(TrackedValue::Temporary(place_with_id.hir_id))
+            }
+            PlaceBase::Local(hir_id)
+            | PlaceBase::Upvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id }, .. }) => {
+                Ok(TrackedValue::Variable(hir_id))
+            }
+        }
+    }
+}
+
+pub struct DropRanges {
+    tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+    nodes: IndexVec<PostOrderId, NodeInfo>,
+}
+
+impl DropRanges {
+    pub fn is_dropped_at(&self, hir_id: HirId, location: usize) -> bool {
+        self.tracked_value_map
+            .get(&TrackedValue::Temporary(hir_id))
+            .or(self.tracked_value_map.get(&TrackedValue::Variable(hir_id)))
+            .cloned()
+            .map_or(false, |tracked_value_id| {
+                self.expect_node(location.into()).drop_state.contains(tracked_value_id)
+            })
+    }
+
+    /// Returns a reference to the NodeInfo for a node, panicking if it does not exist
+    fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
+        &self.nodes[id]
+    }
+}
+
+/// Tracks information needed to compute drop ranges.
+struct DropRangesBuilder {
+    /// The core of DropRangesBuilder is a set of nodes, which each represent
+    /// one expression. We primarily refer to them by their index in a
+    /// post-order traversal of the HIR tree,  since this is what
+    /// generator_interior uses to talk about yield positions.
+    ///
+    /// This IndexVec keeps the relevant details for each node. See the
+    /// NodeInfo struct for more details, but this information includes things
+    /// such as the set of control-flow successors, which variables are dropped
+    /// or reinitialized, and whether each variable has been inferred to be
+    /// known-dropped or potentially reintiialized at each point.
+    nodes: IndexVec<PostOrderId, NodeInfo>,
+    /// We refer to values whose drop state we are tracking by the HirId of
+    /// where they are defined. Within a NodeInfo, however, we store the
+    /// drop-state in a bit vector indexed by a HirIdIndex
+    /// (see NodeInfo::drop_state). The hir_id_map field stores the mapping
+    /// from HirIds to the HirIdIndex that is used to represent that value in
+    /// bitvector.
+    tracked_value_map: FxHashMap<TrackedValue, TrackedValueIndex>,
+
+    /// When building the control flow graph, we don't always know the
+    /// post-order index of the target node at the point we encounter it.
+    /// For example, this happens with break and continue. In those cases,
+    /// we store a pair of the PostOrderId of the source and the HirId
+    /// of the target. Once we have gathered all of these edges, we make a
+    /// pass over the set of deferred edges (see process_deferred_edges in
+    /// cfg_build.rs), look up the PostOrderId for the target (since now the
+    /// post-order index for all nodes is known), and add missing control flow
+    /// edges.
+    deferred_edges: Vec<(PostOrderId, HirId)>,
+    /// This maps HirIds of expressions to their post-order index. It is
+    /// used in process_deferred_edges to correctly add back-edges.
+    post_order_map: HirIdMap<PostOrderId>,
+}
+
+impl Debug for DropRangesBuilder {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("DropRanges")
+            .field("hir_id_map", &self.tracked_value_map)
+            .field("post_order_maps", &self.post_order_map)
+            .field("nodes", &self.nodes.iter_enumerated().collect::<BTreeMap<_, _>>())
+            .finish()
+    }
+}
+
+/// DropRanges keeps track of what values are definitely dropped at each point in the code.
+///
+/// Values of interest are defined by the hir_id of their place. Locations in code are identified
+/// by their index in the post-order traversal. At its core, DropRanges maps
+/// (hir_id, post_order_id) -> bool, where a true value indicates that the value is definitely
+/// dropped at the point of the node identified by post_order_id.
+impl DropRangesBuilder {
+    /// Returns the number of values (hir_ids) that are tracked
+    fn num_values(&self) -> usize {
+        self.tracked_value_map.len()
+    }
+
+    fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo {
+        let size = self.num_values();
+        self.nodes.ensure_contains_elem(id, || NodeInfo::new(size));
+        &mut self.nodes[id]
+    }
+
+    fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
+        trace!("adding control edge from {:?} to {:?}", from, to);
+        self.node_mut(from.into()).successors.push(to.into());
+    }
+}
+
+#[derive(Debug)]
+struct NodeInfo {
+    /// IDs of nodes that can follow this one in the control flow
+    ///
+    /// If the vec is empty, then control proceeds to the next node.
+    successors: Vec<PostOrderId>,
+
+    /// List of hir_ids that are dropped by this node.
+    drops: Vec<TrackedValueIndex>,
+
+    /// List of hir_ids that are reinitialized by this node.
+    reinits: Vec<TrackedValueIndex>,
+
+    /// Set of values that are definitely dropped at this point.
+    drop_state: BitSet<TrackedValueIndex>,
+}
+
+impl NodeInfo {
+    fn new(num_values: usize) -> Self {
+        Self {
+            successors: vec![],
+            drops: vec![],
+            reinits: vec![],
+            drop_state: BitSet::new_filled(num_values),
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
new file mode 100644
index 00000000000..fc957b89990
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -0,0 +1,473 @@
+use super::{
+    for_each_consumable, record_consumed_borrow::ConsumedAndBorrowedPlaces, DropRangesBuilder,
+    NodeInfo, PostOrderId, TrackedValue, TrackedValueIndex,
+};
+use hir::{
+    intravisit::{self, Visitor},
+    Body, Expr, ExprKind, Guard, HirId,
+};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_index::vec::IndexVec;
+use rustc_middle::{
+    hir::map::Map,
+    ty::{TyCtxt, TypeckResults},
+};
+use std::mem::swap;
+
+/// Traverses the body to find the control flow graph and locations for the
+/// relevant places are dropped or reinitialized.
+///
+/// The resulting structure still needs to be iterated to a fixed point, which
+/// can be done with propagate_to_fixpoint in cfg_propagate.
+pub(super) fn build_control_flow_graph<'tcx>(
+    hir: Map<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    typeck_results: &TypeckResults<'tcx>,
+    consumed_borrowed_places: ConsumedAndBorrowedPlaces,
+    body: &'tcx Body<'tcx>,
+    num_exprs: usize,
+) -> DropRangesBuilder {
+    let mut drop_range_visitor =
+        DropRangeVisitor::new(hir, tcx, typeck_results, consumed_borrowed_places, num_exprs);
+    intravisit::walk_body(&mut drop_range_visitor, body);
+
+    drop_range_visitor.drop_ranges.process_deferred_edges();
+
+    drop_range_visitor.drop_ranges
+}
+
+/// This struct is used to gather the information for `DropRanges` to determine the regions of the
+/// HIR tree for which a value is dropped.
+///
+/// We are interested in points where a variables is dropped or initialized, and the control flow
+/// of the code. We identify locations in code by their post-order traversal index, so it is
+/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
+///
+/// We make several simplifying assumptions, with the goal of being more conservative than
+/// necessary rather than less conservative (since being less conservative is unsound, but more
+/// conservative is still safe). These assumptions are:
+///
+/// 1. Moving a variable `a` counts as a move of the whole variable.
+/// 2. Moving a partial path like `a.b.c` is ignored.
+/// 3. Reinitializing through a field (e.g. `a.b.c = 5`) counds as a reinitialization of all of
+///    `a`.
+///
+/// Some examples:
+///
+/// Rule 1:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a);
+/// // `a` is not considered initialized.
+/// ```
+///
+/// Rule 2:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a.0);
+/// drop(a.1);
+/// // `a` is still considered initialized.
+/// ```
+///
+/// Rule 3:
+/// ```rust
+/// let mut a = (vec![0], vec![0]);
+/// drop(a);
+/// a.1 = vec![1];
+/// // all of `a` is considered initialized
+/// ```
+
+struct DropRangeVisitor<'a, 'tcx> {
+    hir: Map<'tcx>,
+    places: ConsumedAndBorrowedPlaces,
+    drop_ranges: DropRangesBuilder,
+    expr_index: PostOrderId,
+    tcx: TyCtxt<'tcx>,
+    typeck_results: &'a TypeckResults<'tcx>,
+}
+
+impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
+    fn new(
+        hir: Map<'tcx>,
+        tcx: TyCtxt<'tcx>,
+        typeck_results: &'a TypeckResults<'tcx>,
+        places: ConsumedAndBorrowedPlaces,
+        num_exprs: usize,
+    ) -> Self {
+        debug!("consumed_places: {:?}", places.consumed);
+        let drop_ranges = DropRangesBuilder::new(
+            places.consumed.iter().flat_map(|(_, places)| places.iter().cloned()),
+            hir,
+            num_exprs,
+        );
+        Self { hir, places, drop_ranges, expr_index: PostOrderId::from_u32(0), typeck_results, tcx }
+    }
+
+    fn record_drop(&mut self, value: TrackedValue) {
+        if self.places.borrowed.contains(&value) {
+            debug!("not marking {:?} as dropped because it is borrowed at some point", value);
+        } else {
+            debug!("marking {:?} as dropped at {:?}", value, self.expr_index);
+            let count = self.expr_index;
+            self.drop_ranges.drop_at(value, count);
+        }
+    }
+
+    /// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
+    /// expressions. This method consumes a little deeper into the expression when needed.
+    fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
+        debug!("consuming expr {:?}, count={:?}", expr.hir_id, self.expr_index);
+        let places = self
+            .places
+            .consumed
+            .get(&expr.hir_id)
+            .map_or(vec![], |places| places.iter().cloned().collect());
+        for place in places {
+            for_each_consumable(self.hir, place, |value| self.record_drop(value));
+        }
+    }
+
+    /// Marks an expression as being reinitialized.
+    ///
+    /// Note that we always approximated on the side of things being more
+    /// initialized than they actually are, as opposed to less. In cases such
+    /// as `x.y = ...`, we would consider all of `x` as being initialized
+    /// instead of just the `y` field.
+    ///
+    /// This is because it is always safe to consider something initialized
+    /// even when it is not, but the other way around will cause problems.
+    ///
+    /// In the future, we will hopefully tighten up these rules to be more
+    /// precise.
+    fn reinit_expr(&mut self, expr: &hir::Expr<'_>) {
+        // Walk the expression to find the base. For example, in an expression
+        // like `*a[i].x`, we want to find the `a` and mark that as
+        // reinitialized.
+        match expr.kind {
+            ExprKind::Path(hir::QPath::Resolved(
+                _,
+                hir::Path { res: hir::def::Res::Local(hir_id), .. },
+            )) => {
+                // This is the base case, where we have found an actual named variable.
+
+                let location = self.expr_index;
+                debug!("reinitializing {:?} at {:?}", hir_id, location);
+                self.drop_ranges.reinit_at(TrackedValue::Variable(*hir_id), location);
+            }
+
+            ExprKind::Field(base, _) => self.reinit_expr(base),
+
+            // Most expressions do not refer to something where we need to track
+            // reinitializations.
+            //
+            // Some of these may be interesting in the future
+            ExprKind::Path(..)
+            | ExprKind::Box(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Array(..)
+            | ExprKind::Call(..)
+            | ExprKind::MethodCall(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Binary(..)
+            | ExprKind::Unary(..)
+            | ExprKind::Lit(..)
+            | ExprKind::Cast(..)
+            | ExprKind::Type(..)
+            | ExprKind::DropTemps(..)
+            | ExprKind::Let(..)
+            | ExprKind::If(..)
+            | ExprKind::Loop(..)
+            | ExprKind::Match(..)
+            | ExprKind::Closure(..)
+            | ExprKind::Block(..)
+            | ExprKind::Assign(..)
+            | ExprKind::AssignOp(..)
+            | ExprKind::Index(..)
+            | ExprKind::AddrOf(..)
+            | ExprKind::Break(..)
+            | ExprKind::Continue(..)
+            | ExprKind::Ret(..)
+            | ExprKind::InlineAsm(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Yield(..)
+            | ExprKind::Err => (),
+        }
+    }
+
+    /// For an expression with an uninhabited return type (e.g. a function that returns !),
+    /// this adds a self edge to to the CFG to model the fact that the function does not
+    /// return.
+    fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
+        let ty = self.typeck_results.expr_ty(expr);
+        let ty = self.tcx.erase_regions(ty);
+        let m = self.tcx.parent_module(expr.hir_id).to_def_id();
+        let param_env = self.tcx.param_env(m.expect_local());
+        if self.tcx.is_ty_uninhabited_from(m, ty, param_env) {
+            // This function will not return. We model this fact as an infinite loop.
+            self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let mut reinit = None;
+        match expr.kind {
+            ExprKind::Assign(lhs, rhs, _) => {
+                self.visit_expr(lhs);
+                self.visit_expr(rhs);
+
+                reinit = Some(lhs);
+            }
+
+            ExprKind::If(test, if_true, if_false) => {
+                self.visit_expr(test);
+
+                let fork = self.expr_index;
+
+                self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
+                self.visit_expr(if_true);
+                let true_end = self.expr_index;
+
+                self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
+                if let Some(if_false) = if_false {
+                    self.visit_expr(if_false);
+                }
+
+                self.drop_ranges.add_control_edge(true_end, self.expr_index + 1);
+            }
+            ExprKind::Match(scrutinee, arms, ..) => {
+                // We walk through the match expression almost like a chain of if expressions.
+                // Here's a diagram to follow along with:
+                //
+                //           ┌─┐
+                //     match │A│ {
+                //       ┌───┴─┘
+                //       │
+                //      ┌▼┌───►┌─┐   ┌─┐
+                //      │B│ if │C│ =>│D│,
+                //      └─┘    ├─┴──►└─┴──────┐
+                //          ┌──┘              │
+                //       ┌──┘                 │
+                //       │                    │
+                //      ┌▼┌───►┌─┐   ┌─┐      │
+                //      │E│ if │F│ =>│G│,     │
+                //      └─┘    ├─┴──►└─┴┐     │
+                //             │        │     │
+                //     }       ▼        ▼     │
+                //     ┌─┐◄───────────────────┘
+                //     │H│
+                //     └─┘
+                //
+                // The order we want is that the scrutinee (A) flows into the first pattern (B),
+                // which flows into the guard (C). Then the guard either flows into the arm body
+                // (D) or into the start of the next arm (E). Finally, the body flows to the end
+                // of the match block (H).
+                //
+                // The subsequent arms follow the same ordering. First we go to the pattern, then
+                // the guard (if present, otherwise it flows straight into the body), then into
+                // the body and then to the end of the match expression.
+                //
+                // The comments below show which edge is being added.
+                self.visit_expr(scrutinee);
+
+                let (guard_exit, arm_end_ids) = arms.iter().fold(
+                    (self.expr_index, vec![]),
+                    |(incoming_edge, mut arm_end_ids), hir::Arm { pat, body, guard, .. }| {
+                        // A -> B, or C -> E
+                        self.drop_ranges.add_control_edge(incoming_edge, self.expr_index + 1);
+                        self.visit_pat(pat);
+                        // B -> C and E -> F are added implicitly due to the traversal order.
+                        match guard {
+                            Some(Guard::If(expr)) => self.visit_expr(expr),
+                            Some(Guard::IfLet(pat, expr)) => {
+                                self.visit_pat(pat);
+                                self.visit_expr(expr);
+                            }
+                            None => (),
+                        }
+                        // Likewise, C -> D and F -> G are added implicitly.
+
+                        // Save C, F, so we can add the other outgoing edge.
+                        let to_next_arm = self.expr_index;
+
+                        // The default edge does not get added since we also have an explicit edge,
+                        // so we also need to add an edge to the next node as well.
+                        //
+                        // This adds C -> D, F -> G
+                        self.drop_ranges.add_control_edge(self.expr_index, self.expr_index + 1);
+                        self.visit_expr(body);
+
+                        // Save the end of the body so we can add the exit edge once we know where
+                        // the exit is.
+                        arm_end_ids.push(self.expr_index);
+
+                        // Pass C to the next iteration, as well as vec![D]
+                        //
+                        // On the last round through, we pass F and vec![D, G] so that we can
+                        // add all the exit edges.
+                        (to_next_arm, arm_end_ids)
+                    },
+                );
+                // F -> H
+                self.drop_ranges.add_control_edge(guard_exit, self.expr_index + 1);
+
+                arm_end_ids.into_iter().for_each(|arm_end| {
+                    // D -> H, G -> H
+                    self.drop_ranges.add_control_edge(arm_end, self.expr_index + 1)
+                });
+            }
+
+            ExprKind::Loop(body, ..) => {
+                let loop_begin = self.expr_index + 1;
+                if body.stmts.is_empty() && body.expr.is_none() {
+                    // For empty loops we won't have updated self.expr_index after visiting the
+                    // body, meaning we'd get an edge from expr_index to expr_index + 1, but
+                    // instead we want an edge from expr_index + 1 to expr_index + 1.
+                    self.drop_ranges.add_control_edge(loop_begin, loop_begin);
+                } else {
+                    self.visit_block(body);
+                    self.drop_ranges.add_control_edge(self.expr_index, loop_begin);
+                }
+            }
+            ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..)
+            | ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => {
+                self.drop_ranges.add_control_edge_hir_id(self.expr_index, target);
+            }
+
+            ExprKind::Call(f, args) => {
+                self.visit_expr(f);
+                for arg in args {
+                    self.visit_expr(arg);
+                }
+
+                self.handle_uninhabited_return(expr);
+            }
+            ExprKind::MethodCall(_, _, exprs, _) => {
+                for expr in exprs {
+                    self.visit_expr(expr);
+                }
+
+                self.handle_uninhabited_return(expr);
+            }
+
+            ExprKind::AddrOf(..)
+            | ExprKind::Array(..)
+            | ExprKind::AssignOp(..)
+            | ExprKind::Binary(..)
+            | ExprKind::Block(..)
+            | ExprKind::Box(..)
+            | ExprKind::Break(..)
+            | ExprKind::Cast(..)
+            | ExprKind::Closure(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Continue(..)
+            | ExprKind::DropTemps(..)
+            | ExprKind::Err
+            | ExprKind::Field(..)
+            | ExprKind::Index(..)
+            | ExprKind::InlineAsm(..)
+            | ExprKind::Let(..)
+            | ExprKind::Lit(..)
+            | ExprKind::Path(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Type(..)
+            | ExprKind::Unary(..)
+            | ExprKind::Yield(..) => intravisit::walk_expr(self, expr),
+        }
+
+        self.expr_index = self.expr_index + 1;
+        self.drop_ranges.add_node_mapping(expr.hir_id, self.expr_index);
+        self.consume_expr(expr);
+        if let Some(expr) = reinit {
+            self.reinit_expr(expr);
+        }
+    }
+
+    fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
+        intravisit::walk_pat(self, pat);
+
+        // Increment expr_count here to match what InteriorVisitor expects.
+        self.expr_index = self.expr_index + 1;
+    }
+}
+
+impl DropRangesBuilder {
+    fn new(
+        tracked_values: impl Iterator<Item = TrackedValue>,
+        hir: Map<'_>,
+        num_exprs: usize,
+    ) -> Self {
+        let mut tracked_value_map = FxHashMap::<_, TrackedValueIndex>::default();
+        let mut next = <_>::from(0u32);
+        for value in tracked_values {
+            for_each_consumable(hir, value, |value| {
+                if !tracked_value_map.contains_key(&value) {
+                    tracked_value_map.insert(value, next);
+                    next = next + 1;
+                }
+            });
+        }
+        debug!("hir_id_map: {:?}", tracked_value_map);
+        let num_values = tracked_value_map.len();
+        Self {
+            tracked_value_map,
+            nodes: IndexVec::from_fn_n(|_| NodeInfo::new(num_values), num_exprs + 1),
+            deferred_edges: <_>::default(),
+            post_order_map: <_>::default(),
+        }
+    }
+
+    fn tracked_value_index(&self, tracked_value: TrackedValue) -> TrackedValueIndex {
+        *self.tracked_value_map.get(&tracked_value).unwrap()
+    }
+
+    /// Adds an entry in the mapping from HirIds to PostOrderIds
+    ///
+    /// Needed so that `add_control_edge_hir_id` can work.
+    fn add_node_mapping(&mut self, node_hir_id: HirId, post_order_id: PostOrderId) {
+        self.post_order_map.insert(node_hir_id, post_order_id);
+    }
+
+    /// Like add_control_edge, but uses a hir_id as the target.
+    ///
+    /// This can be used for branches where we do not know the PostOrderId of the target yet,
+    /// such as when handling `break` or `continue`.
+    fn add_control_edge_hir_id(&mut self, from: PostOrderId, to: HirId) {
+        self.deferred_edges.push((from, to));
+    }
+
+    fn drop_at(&mut self, value: TrackedValue, location: PostOrderId) {
+        let value = self.tracked_value_index(value);
+        self.node_mut(location.into()).drops.push(value);
+    }
+
+    fn reinit_at(&mut self, value: TrackedValue, location: PostOrderId) {
+        let value = match self.tracked_value_map.get(&value) {
+            Some(value) => *value,
+            // If there's no value, this is never consumed and therefore is never dropped. We can
+            // ignore this.
+            None => return,
+        };
+        self.node_mut(location.into()).reinits.push(value);
+    }
+
+    /// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.
+    ///
+    /// Should be called after visiting the HIR but before solving the control flow, otherwise some
+    /// edges will be missed.
+    fn process_deferred_edges(&mut self) {
+        let mut edges = vec![];
+        swap(&mut edges, &mut self.deferred_edges);
+        edges.into_iter().for_each(|(from, to)| {
+            let to = *self.post_order_map.get(&to).expect("Expression ID not found");
+            trace!("Adding deferred edge from {:?} to {:?}", from, to);
+            self.add_control_edge(from, to)
+        });
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
new file mode 100644
index 00000000000..139d17d2e1c
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
@@ -0,0 +1,92 @@
+use super::{DropRangesBuilder, PostOrderId};
+use rustc_index::{bit_set::BitSet, vec::IndexVec};
+use std::collections::BTreeMap;
+
+impl DropRangesBuilder {
+    pub fn propagate_to_fixpoint(&mut self) {
+        trace!("before fixpoint: {:#?}", self);
+        let preds = self.compute_predecessors();
+
+        trace!("predecessors: {:#?}", preds.iter_enumerated().collect::<BTreeMap<_, _>>());
+
+        let mut new_state = BitSet::new_empty(self.num_values());
+        let mut changed_nodes = BitSet::new_empty(self.nodes.len());
+        let mut unchanged_mask = BitSet::new_filled(self.nodes.len());
+        changed_nodes.insert(0u32.into());
+
+        let mut propagate = || {
+            let mut changed = false;
+            unchanged_mask.insert_all();
+            for id in self.nodes.indices() {
+                trace!("processing {:?}, changed_nodes: {:?}", id, changed_nodes);
+                // Check if any predecessor has changed, and if not then short-circuit.
+                //
+                // We handle the start node specially, since it doesn't have any predecessors,
+                // but we need to start somewhere.
+                if match id.index() {
+                    0 => !changed_nodes.contains(id),
+                    _ => !preds[id].iter().any(|pred| changed_nodes.contains(*pred)),
+                } {
+                    trace!("short-circuiting because none of {:?} have changed", preds[id]);
+                    unchanged_mask.remove(id);
+                    continue;
+                }
+
+                if id.index() == 0 {
+                    new_state.clear();
+                } else {
+                    // If we are not the start node and we have no predecessors, treat
+                    // everything as dropped because there's no way to get here anyway.
+                    new_state.insert_all();
+                };
+
+                for pred in &preds[id] {
+                    new_state.intersect(&self.nodes[*pred].drop_state);
+                }
+
+                for drop in &self.nodes[id].drops {
+                    new_state.insert(*drop);
+                }
+
+                for reinit in &self.nodes[id].reinits {
+                    new_state.remove(*reinit);
+                }
+
+                if self.nodes[id].drop_state.intersect(&new_state) {
+                    changed_nodes.insert(id);
+                    changed = true;
+                } else {
+                    unchanged_mask.remove(id);
+                }
+            }
+
+            changed_nodes.intersect(&unchanged_mask);
+            changed
+        };
+
+        while propagate() {
+            trace!("drop_state changed, re-running propagation");
+        }
+
+        trace!("after fixpoint: {:#?}", self);
+    }
+
+    fn compute_predecessors(&self) -> IndexVec<PostOrderId, Vec<PostOrderId>> {
+        let mut preds = IndexVec::from_fn_n(|_| vec![], self.nodes.len());
+        for (id, node) in self.nodes.iter_enumerated() {
+            // If the node has no explicit successors, we assume that control
+            // will from this node into the next one.
+            //
+            // If there are successors listed, then we assume that all
+            // possible successors are given and we do not include the default.
+            if node.successors.len() == 0 && id.index() != self.nodes.len() - 1 {
+                preds[id + 1].push(id);
+            } else {
+                for succ in &node.successors {
+                    preds[*succ].push(id);
+                }
+            }
+        }
+        preds
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
new file mode 100644
index 00000000000..20aad7aedf7
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
@@ -0,0 +1,77 @@
+//! Implementation of GraphWalk for DropRanges so we can visualize the control
+//! flow graph when needed for debugging.
+
+use rustc_graphviz as dot;
+
+use super::{DropRangesBuilder, PostOrderId};
+
+/// Writes the CFG for DropRangesBuilder to a .dot file for visualization.
+///
+/// It is not normally called, but is kept around to easily add debugging
+/// code when needed.
+#[allow(dead_code)]
+pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) {
+    dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap();
+}
+
+impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
+    type Node = PostOrderId;
+
+    type Edge = (PostOrderId, PostOrderId);
+
+    fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
+        self.nodes.iter_enumerated().map(|(i, _)| i).collect()
+    }
+
+    fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
+        self.nodes
+            .iter_enumerated()
+            .flat_map(|(i, node)| {
+                if node.successors.len() == 0 {
+                    vec![(i, i + 1)]
+                } else {
+                    node.successors.iter().map(move |&s| (i, s)).collect()
+                }
+            })
+            .collect()
+    }
+
+    fn source(&'a self, edge: &Self::Edge) -> Self::Node {
+        edge.0
+    }
+
+    fn target(&'a self, edge: &Self::Edge) -> Self::Node {
+        edge.1
+    }
+}
+
+impl<'a> dot::Labeller<'a> for DropRangesBuilder {
+    type Node = PostOrderId;
+
+    type Edge = (PostOrderId, PostOrderId);
+
+    fn graph_id(&'a self) -> dot::Id<'a> {
+        dot::Id::new("drop_ranges").unwrap()
+    }
+
+    fn node_id(&'a self, n: &Self::Node) -> dot::Id<'a> {
+        dot::Id::new(format!("id{}", n.index())).unwrap()
+    }
+
+    fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
+        dot::LabelText::LabelStr(
+            format!(
+                "{:?}, local_id: {}",
+                n,
+                self.post_order_map
+                    .iter()
+                    .find(|(_hir_id, &post_order_id)| post_order_id == *n)
+                    .map_or("<unknown>".into(), |(hir_id, _)| format!(
+                        "{}",
+                        hir_id.local_id.index()
+                    ))
+            )
+            .into(),
+        )
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
new file mode 100644
index 00000000000..059a135a6fb
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -0,0 +1,118 @@
+use super::TrackedValue;
+use crate::{
+    check::FnCtxt,
+    expr_use_visitor::{self, ExprUseVisitor},
+};
+use hir::{def_id::DefId, Body, HirId, HirIdMap};
+use rustc_data_structures::stable_set::FxHashSet;
+use rustc_hir as hir;
+use rustc_middle::hir::map::Map;
+
+pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    def_id: DefId,
+    body: &'tcx Body<'tcx>,
+) -> ConsumedAndBorrowedPlaces {
+    let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx.hir());
+    expr_use_visitor.consume_body(fcx, def_id, body);
+    expr_use_visitor.places
+}
+
+pub(super) struct ConsumedAndBorrowedPlaces {
+    /// Records the variables/expressions that are dropped by a given expression.
+    ///
+    /// The key is the hir-id of the expression, and the value is a set or hir-ids for variables
+    /// or values that are consumed by that expression.
+    ///
+    /// Note that this set excludes "partial drops" -- for example, a statement like `drop(x.y)` is
+    /// not considered a drop of `x`, although it would be a drop of `x.y`.
+    pub(super) consumed: HirIdMap<FxHashSet<TrackedValue>>,
+    /// A set of hir-ids of values or variables that are borrowed at some point within the body.
+    pub(super) borrowed: FxHashSet<TrackedValue>,
+}
+
+/// Works with ExprUseVisitor to find interesting values for the drop range analysis.
+///
+/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
+/// record the parent expression, which is the point where the drop actually takes place.
+struct ExprUseDelegate<'tcx> {
+    hir: Map<'tcx>,
+    places: ConsumedAndBorrowedPlaces,
+}
+
+impl<'tcx> ExprUseDelegate<'tcx> {
+    fn new(hir: Map<'tcx>) -> Self {
+        Self {
+            hir,
+            places: ConsumedAndBorrowedPlaces {
+                consumed: <_>::default(),
+                borrowed: <_>::default(),
+            },
+        }
+    }
+
+    fn consume_body(&mut self, fcx: &'_ FnCtxt<'_, 'tcx>, def_id: DefId, body: &'tcx Body<'tcx>) {
+        // Run ExprUseVisitor to find where values are consumed.
+        ExprUseVisitor::new(
+            self,
+            &fcx.infcx,
+            def_id.expect_local(),
+            fcx.param_env,
+            &fcx.typeck_results.borrow(),
+        )
+        .consume_body(body);
+    }
+
+    fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) {
+        if !self.places.consumed.contains_key(&consumer) {
+            self.places.consumed.insert(consumer, <_>::default());
+        }
+        self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
+    }
+}
+
+impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
+    fn consume(
+        &mut self,
+        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        diag_expr_id: HirId,
+    ) {
+        let parent = match self.hir.find_parent_node(place_with_id.hir_id) {
+            Some(parent) => parent,
+            None => place_with_id.hir_id,
+        };
+        debug!(
+            "consume {:?}; diag_expr_id={:?}, using parent {:?}",
+            place_with_id, diag_expr_id, parent
+        );
+        place_with_id
+            .try_into()
+            .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
+    }
+
+    fn borrow(
+        &mut self,
+        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        _diag_expr_id: HirId,
+        _bk: rustc_middle::ty::BorrowKind,
+    ) {
+        place_with_id
+            .try_into()
+            .map_or(false, |tracked_value| self.places.borrowed.insert(tracked_value));
+    }
+
+    fn mutate(
+        &mut self,
+        _assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        _diag_expr_id: HirId,
+    ) {
+    }
+
+    fn fake_read(
+        &mut self,
+        _place: expr_use_visitor::Place<'tcx>,
+        _cause: rustc_middle::mir::FakeReadCause,
+        _diag_expr_id: HirId,
+    ) {
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index f50f3c39c88..ec88bdf4a37 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let item_def_id = self.tcx.hir().local_def_id(item_id);
 
         // This attribute causes us to dump some writeback information
-        // in the form of errors, which is uSymbol for unit tests.
+        // in the form of errors, which is used for unit tests.
         let rustc_dump_user_substs =
             self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_dump_user_substs);
 
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index a70cdc4b519..cc282fc2f0e 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -206,6 +206,10 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/verify-backported-commits.sh
         <<: *step
 
+      - name: ensure the stable version number is correct
+        run: src/ci/scripts/verify-stable-version-number.sh
+        <<: *step
+
       - name: run the build
         run: src/ci/scripts/run-build-from-ci.sh
         env:
diff --git a/src/ci/scripts/verify-stable-version-number.sh b/src/ci/scripts/verify-stable-version-number.sh
new file mode 100755
index 00000000000..82eb3833ccf
--- /dev/null
+++ b/src/ci/scripts/verify-stable-version-number.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# On the stable channel, check whether we're trying to build artifacts with the
+# same version number of a release that's already been published, and fail the
+# build if that's the case.
+#
+# It's a mistake whenever that happens: the release process won't start if it
+# detects a duplicate version number, and the artifacts would have to be
+# rebuilt anyway.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+if [[ "$(cat src/ci/channel)" != "stable" ]]; then
+    echo "This script only works on the stable channel. Skipping the check."
+    exit 0
+fi
+
+version="$(cat src/version)"
+url="https://static.rust-lang.org/dist/channel-rust-${version}.toml"
+
+if curl --silent --fail "${url}" >/dev/null; then
+    echo "The version number ${version} matches an existing release."
+    echo
+    echo "If you're trying to prepare a point release, remember to change the"
+    echo "version number in the src/version file."
+    exit 1
+else
+    echo "The version number ${version} does not match any released version!"
+    exit 0
+fi
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index dfee2b702c1..b72d2624177 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -8,6 +8,7 @@ use std::mem;
 use std::ops;
 
 use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::Features;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{sym, Symbol};
@@ -43,23 +44,22 @@ crate struct InvalidCfgError {
 
 impl Cfg {
     /// Parses a `NestedMetaItem` into a `Cfg`.
-    fn parse_nested(nested_cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
+    fn parse_nested(
+        nested_cfg: &NestedMetaItem,
+        exclude: &FxHashSet<Cfg>,
+    ) -> Result<Option<Cfg>, InvalidCfgError> {
         match nested_cfg {
-            NestedMetaItem::MetaItem(ref cfg) => Cfg::parse(cfg),
+            NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
             NestedMetaItem::Literal(ref lit) => {
                 Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
             }
         }
     }
 
-    /// Parses a `MetaItem` into a `Cfg`.
-    ///
-    /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or
-    /// `target_os = "redox"`.
-    ///
-    /// If the content is not properly formatted, it will return an error indicating what and where
-    /// the error is.
-    crate fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
+    crate fn parse_without(
+        cfg: &MetaItem,
+        exclude: &FxHashSet<Cfg>,
+    ) -> Result<Option<Cfg>, InvalidCfgError> {
         let name = match cfg.ident() {
             Some(ident) => ident.name,
             None => {
@@ -70,9 +70,15 @@ impl Cfg {
             }
         };
         match cfg.kind {
-            MetaItemKind::Word => Ok(Cfg::Cfg(name, None)),
+            MetaItemKind::Word => {
+                let cfg = Cfg::Cfg(name, None);
+                if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) }
+            }
             MetaItemKind::NameValue(ref lit) => match lit.kind {
-                LitKind::Str(value, _) => Ok(Cfg::Cfg(name, Some(value))),
+                LitKind::Str(value, _) => {
+                    let cfg = Cfg::Cfg(name, Some(value));
+                    if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) }
+                }
                 _ => Err(InvalidCfgError {
                     // FIXME: if the main #[cfg] syntax decided to support non-string literals,
                     // this should be changed as well.
@@ -81,23 +87,40 @@ impl Cfg {
                 }),
             },
             MetaItemKind::List(ref items) => {
-                let mut sub_cfgs = items.iter().map(Cfg::parse_nested);
-                match name {
+                let sub_cfgs =
+                    items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose());
+                let ret = match name {
                     sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)),
                     sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)),
                     sym::not => {
+                        let mut sub_cfgs = sub_cfgs.collect::<Vec<_>>();
                         if sub_cfgs.len() == 1 {
-                            Ok(!sub_cfgs.next().unwrap()?)
+                            Ok(!sub_cfgs.pop().unwrap()?)
                         } else {
                             Err(InvalidCfgError { msg: "expected 1 cfg-pattern", span: cfg.span })
                         }
                     }
                     _ => Err(InvalidCfgError { msg: "invalid predicate", span: cfg.span }),
+                };
+                match ret {
+                    Ok(c) => Ok(Some(c)),
+                    Err(e) => Err(e),
                 }
             }
         }
     }
 
+    /// Parses a `MetaItem` into a `Cfg`.
+    ///
+    /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or
+    /// `target_os = "redox"`.
+    ///
+    /// If the content is not properly formatted, it will return an error indicating what and where
+    /// the error is.
+    crate fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
+        Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
+    }
+
     /// Checks whether the given configuration can be matched in the current session.
     ///
     /// Equivalent to `attr::cfg_matches`.
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 920dd202ee9..993503005d7 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -831,8 +831,9 @@ impl AttributesExt for [ast::Attribute] {
                 self.iter()
                     .filter(|attr| attr.has_name(sym::cfg))
                     .filter_map(|attr| single(attr.meta_item_list()?))
-                    .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
-                    .filter(|cfg| !hidden_cfg.contains(cfg))
+                    .filter_map(|attr| {
+                        Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()
+                    })
                     .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
             } else {
                 Cfg::True
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index d0244351b59..bdd8aa430b2 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1731,12 +1731,19 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 }
 
 @media (max-width: 700px) {
+	/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
+	   or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured
+	   by the topbar. Anything with an `id` gets scroll-margin-top equal to .mobile-topbar's size.
+	*/
+	*[id] {
+		scroll-margin-top: 45px;
+	}
+
 	.rustdoc {
 		padding-top: 0px;
 		/* Sidebar should overlay main content, rather than pushing main content to the right.
 		   Turn off `display: flex` on the body element. */
 		display: block;
-		scroll-margin-top: 45px;
 	}
 
 	main {
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 81fbfd9fdbd..8f484766d9a 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -7,7 +7,7 @@
 mod conversions;
 
 use std::cell::RefCell;
-use std::fs::File;
+use std::fs::{create_dir_all, File};
 use std::path::PathBuf;
 use std::rc::Rc;
 
@@ -18,13 +18,14 @@ use rustc_session::Session;
 
 use rustdoc_json_types as types;
 
-use crate::clean;
 use crate::clean::types::{ExternalCrate, ExternalLocation};
 use crate::config::RenderOptions;
+use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
 use crate::json::conversions::{from_item_id, IntoWithTcx};
+use crate::{clean, try_err};
 
 #[derive(Clone)]
 crate struct JsonRenderer<'tcx> {
@@ -171,8 +172,21 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     /// the hashmap because certain items (traits and types) need to have their mappings for trait
     /// implementations filled out before they're inserted.
     fn item(&mut self, item: clean::Item) -> Result<(), Error> {
+        let local_blanket_impl = match item.def_id {
+            clean::ItemId::Blanket { impl_id, .. } => impl_id.is_local(),
+            clean::ItemId::Auto { .. }
+            | clean::ItemId::DefId(_)
+            | clean::ItemId::Primitive(_, _) => false,
+        };
+
         // Flatten items that recursively store other items
-        item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
+        // FIXME(CraftSpider): We skip children of local blanket implementations, as we'll have
+        //     already seen the actual generic impl, and the generated ones don't need documenting.
+        //     This is necessary due to the visibility, return type, and self arg of the generated
+        //     impls not quite matching, and will no longer be necessary when the mismatch is fixed.
+        if !local_blanket_impl {
+            item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
+        }
 
         let id = item.def_id;
         if let Some(mut new_item) = self.convert_item(item) {
@@ -256,10 +270,13 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .collect(),
             format_version: types::FORMAT_VERSION,
         };
-        let mut p = self.out_path.clone();
+        let out_dir = self.out_path.clone();
+        try_err!(create_dir_all(&out_dir), out_dir);
+
+        let mut p = out_dir;
         p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
         p.set_extension("json");
-        let file = File::create(&p).map_err(|error| Error { error: error.to_string(), file: p })?;
+        let file = try_err!(File::create(&p), p);
         serde_json::ser::to_writer(&file, &output).unwrap();
         Ok(())
     }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 90cb5d586c2..2cbb3324a5e 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -141,6 +141,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     })
                     .collect::<Vec<_>>()
             })
+            .chain([Cfg::Cfg(sym::test, None)].into_iter())
             .collect();
 
         self.cx.cache.exact_paths = self.exact_paths;
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
index 0f874333fa0..4af8b43ea84 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
@@ -1,12 +1,17 @@
 # Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.
 
-# only-i686-pc-windows-msvc
+# only-x86
+# only-windows
 
 -include ../../run-make-fulldeps/tools.mk
 
 all:
 	$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
+ifdef IS_MSVC
 	$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll
+else
+	$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
+endif
 	$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
 	$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
index ba0f1418aba..165792b0490 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
@@ -62,9 +62,12 @@ pub fn library_function() {
         fastcall_fn_2(16, 3.5);
         fastcall_fn_3(3.5);
         fastcall_fn_4(1, 2, 3.0);
-        fastcall_fn_5(S { x: 1, y: 2 }, 16);
+        // FIXME: 91167
+        // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
+        // on i686-pc-windows-gnu; commenting these out until the indicated issue is fixed.
+        //fastcall_fn_5(S { x: 1, y: 2 }, 16);
         fastcall_fn_6(Some(&S { x: 10, y: 12 }));
-        fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
+        //fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
         fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
         fastcall_fn_9(1, 3.0);
     }
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/output.txt b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
index be598a22027..348bad63ed0 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/output.txt
@@ -11,8 +11,6 @@ fastcall_fn_1(14)
 fastcall_fn_2(16, 3.5)
 fastcall_fn_3(3.5)
 fastcall_fn_4(1, 2, 3.0)
-fastcall_fn_5(S { x: 1, y: 2 }, 16)
 fastcall_fn_6(S { x: 10, y: 12 })
-fastcall_fn_7(S2 { x: 15, y: 16 }, 3)
 fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
 fastcall_fn_9(1, 3.0)
diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml
index 547eb3fd1b3..680822b6ecb 100644
--- a/src/test/rustdoc-gui/sidebar-mobile.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile.goml
@@ -29,3 +29,9 @@ assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 
 // Check that the topbar is visible
 assert-property: (".mobile-topbar", {"clientHeight": "45"})
+
+// Check that clicking an element from the sidebar scrolls to the right place
+// so the target is not obscured by the topbar.
+click: ".sidebar-menu-toggle"
+click: ".sidebar-links a"
+assert-position: ("#method\.must_use", {"y": 45})
diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs
index 246e6a09007..fcd92887c0b 100644
--- a/src/test/rustdoc-json/enums/variant_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_struct.rs
@@ -2,8 +2,8 @@
 // @has - "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
 pub enum EnumStruct {
     // @has - "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
-    // @has - "$.index[*][?(@.name=='x')]"
-    // @has - "$.index[*][?(@.name=='y')]"
+    // @has - "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+    // @has - "$.index[*][?(@.name=='y')].kind" \"struct_field\"
     VariantS {
         x: u32,
         y: String,
diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
index d948dc552cd..ac3e72e2905 100644
--- a/src/test/rustdoc-json/enums/variant_tuple_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
@@ -2,5 +2,7 @@
 // @has - "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
 pub enum EnumTupleStruct {
     // @has - "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
+    // @has - "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+    // @has - "$.index[*][?(@.name=='1')].kind" \"struct_field\"
     VariantA(u32, String),
 }
diff --git a/src/test/rustdoc-json/impls/blanket_with_local.rs b/src/test/rustdoc-json/impls/blanket_with_local.rs
new file mode 100644
index 00000000000..963ea2fe5ae
--- /dev/null
+++ b/src/test/rustdoc-json/impls/blanket_with_local.rs
@@ -0,0 +1,14 @@
+// Test for the ICE in rust/83718
+// A blanket impl plus a local type together shouldn't result in mismatched ID issues
+
+// @has blanket_with_local.json "$.index[*][?(@.name=='Load')]"
+pub trait Load {
+    fn load() {}
+}
+
+impl<P> Load for P {
+    fn load() {}
+}
+
+// @has - "$.index[*][?(@.name=='Wrapper')]"
+pub struct Wrapper {}
diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs
index fcdd8354569..57dd0529535 100644
--- a/src/test/rustdoc/doc-auto-cfg.rs
+++ b/src/test/rustdoc/doc-auto-cfg.rs
@@ -3,6 +3,12 @@
 #![crate_name = "foo"]
 
 // @has foo/fn.foo.html
-// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test'
-#[cfg(not(test))]
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-doctest'
+#[cfg(not(doctest))]
 pub fn foo() {}
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc'
+// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'test'
+#[cfg(any(test, doc))]
+pub fn bar() {}
diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs
index 424fa6d6a91..636957fe998 100644
--- a/src/test/rustdoc/doc-cfg-hide.rs
+++ b/src/test/rustdoc/doc-cfg-hide.rs
@@ -26,7 +26,7 @@ pub struct Hyperdulia;
 
 // @has 'oud/struct.Oystercatcher.html'
 // @count   - '//*[@class="stab portability"]' 1
-// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher'
+// @matches - '//*[@class="stab portability"]' 'crate feature oystercatcher only'
 // compile-flags:--cfg feature="oystercatcher"
 #[cfg(all(feature = "solecism", feature = "oystercatcher"))]
 pub struct Oystercatcher;
diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
index 845941200fc..c5453b67ef5 100644
--- a/src/test/ui/async-await/async-fn-nonsend.rs
+++ b/src/test/ui/async-await/async-fn-nonsend.rs
@@ -18,7 +18,7 @@ async fn fut() {}
 async fn fut_arg<T>(_: T) {}
 
 async fn local_dropped_before_await() {
-    // FIXME: it'd be nice for this to be allowed in a `Send` `async fn`
+    // this is okay now because of the drop
     let x = non_send();
     drop(x);
     fut().await;
@@ -35,21 +35,40 @@ async fn non_send_temporary_in_match() {
     }
 }
 
+fn get_formatter() -> std::fmt::Formatter<'static> {
+    panic!()
+}
+
 async fn non_sync_with_method_call() {
-    // FIXME: it'd be nice for this to work.
+    let f: &mut std::fmt::Formatter = &mut get_formatter();
+    // It would by nice for this to work.
+    if non_sync().fmt(f).unwrap() == () {
+        fut().await;
+    }
+}
+
+async fn non_sync_with_method_call_panic() {
     let f: &mut std::fmt::Formatter = panic!();
     if non_sync().fmt(f).unwrap() == () {
         fut().await;
     }
 }
 
+async fn non_sync_with_method_call_infinite_loop() {
+    let f: &mut std::fmt::Formatter = loop {};
+    if non_sync().fmt(f).unwrap() == () {
+        fut().await;
+    }
+}
+
 fn assert_send(_: impl Send) {}
 
 pub fn pass_assert() {
     assert_send(local_dropped_before_await());
-    //~^ ERROR future cannot be sent between threads safely
     assert_send(non_send_temporary_in_match());
     //~^ ERROR future cannot be sent between threads safely
     assert_send(non_sync_with_method_call());
     //~^ ERROR future cannot be sent between threads safely
+    assert_send(non_sync_with_method_call_panic());
+    assert_send(non_sync_with_method_call_infinite_loop());
 }
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index bff28208573..40ad46b4862 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -1,28 +1,5 @@
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:49:17
-   |
-LL |     assert_send(local_dropped_before_await());
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
-   |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
-note: future is not `Send` as this value is used across an await
-  --> $DIR/async-fn-nonsend.rs:24:10
-   |
-LL |     let x = non_send();
-   |         - has type `impl Debug` which is not `Send`
-LL |     drop(x);
-LL |     fut().await;
-   |          ^^^^^^ await occurs here, with `x` maybe used later
-LL | }
-   | - `x` is later dropped here
-note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:46:24
-   |
-LL | fn assert_send(_: impl Send) {}
-   |                        ^^^^ required by this bound in `assert_send`
-
-error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:51:17
+  --> $DIR/async-fn-nonsend.rs:68:17
    |
 LL |     assert_send(non_send_temporary_in_match());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
@@ -32,41 +9,41 @@ note: future is not `Send` as this value is used across an await
   --> $DIR/async-fn-nonsend.rs:33:25
    |
 LL |     match Some(non_send()) {
-   |                ---------- has type `impl Debug` which is not `Send`
+   |           ---------------- has type `Option<impl Debug>` which is not `Send`
 LL |         Some(_) => fut().await,
-   |                         ^^^^^^ await occurs here, with `non_send()` maybe used later
+   |                         ^^^^^^ await occurs here, with `Some(non_send())` maybe used later
 ...
 LL | }
-   | - `non_send()` is later dropped here
+   | - `Some(non_send())` is later dropped here
 note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:46:24
+  --> $DIR/async-fn-nonsend.rs:64:24
    |
 LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
 
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:53:17
+  --> $DIR/async-fn-nonsend.rs:70:17
    |
 LL |     assert_send(non_sync_with_method_call());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
    = help: the trait `Send` is not implemented for `dyn std::fmt::Write`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/async-fn-nonsend.rs:42:14
+  --> $DIR/async-fn-nonsend.rs:46:14
    |
-LL |     let f: &mut std::fmt::Formatter = panic!();
-   |         - has type `&mut Formatter<'_>` which is not `Send`
-LL |     if non_sync().fmt(f).unwrap() == () {
+LL |     let f: &mut std::fmt::Formatter = &mut get_formatter();
+   |                                            --------------- has type `Formatter<'_>` which is not `Send`
+...
 LL |         fut().await;
-   |              ^^^^^^ await occurs here, with `f` maybe used later
+   |              ^^^^^^ await occurs here, with `get_formatter()` maybe used later
 LL |     }
 LL | }
-   | - `f` is later dropped here
+   | - `get_formatter()` is later dropped here
 note: required by a bound in `assert_send`
-  --> $DIR/async-fn-nonsend.rs:46:24
+  --> $DIR/async-fn-nonsend.rs:64:24
    |
 LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.rs b/src/test/ui/async-await/partial-drop-partial-reinit.rs
new file mode 100644
index 00000000000..73f0ca8153c
--- /dev/null
+++ b/src/test/ui/async-await/partial-drop-partial-reinit.rs
@@ -0,0 +1,29 @@
+// edition:2021
+#![feature(negative_impls)]
+#![allow(unused)]
+
+fn main() {
+    gimme_send(foo());
+    //~^ ERROR cannot be sent between threads safely
+}
+
+fn gimme_send<T: Send>(t: T) {
+    drop(t);
+}
+
+struct NotSend {}
+
+impl Drop for NotSend {
+    fn drop(&mut self) {}
+}
+
+impl !Send for NotSend {}
+
+async fn foo() {
+    let mut x = (NotSend {},);
+    drop(x.0);
+    x.0 = NotSend {};
+    bar().await;
+}
+
+async fn bar() {}
diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr
new file mode 100644
index 00000000000..2097642eb24
--- /dev/null
+++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr
@@ -0,0 +1,27 @@
+error[E0277]: `NotSend` cannot be sent between threads safely
+  --> $DIR/partial-drop-partial-reinit.rs:6:16
+   |
+LL |     gimme_send(foo());
+   |     ---------- ^^^^^ `NotSend` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+...
+LL | async fn foo() {
+   |                - within this `impl Future<Output = ()>`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
+   = note: required because it appears within the type `(NotSend,)`
+   = note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}`
+   = note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]`
+   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>`
+   = note: required because it appears within the type `impl Future<Output = [async output]>`
+   = note: required because it appears within the type `impl Future<Output = ()>`
+note: required by a bound in `gimme_send`
+  --> $DIR/partial-drop-partial-reinit.rs:10:18
+   |
+LL | fn gimme_send<T: Send>(t: T) {
+   |                  ^^^^ required by this bound in `gimme_send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index 85d868c2703..d313691b388 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -10,20 +10,12 @@ async fn foo() {
     //~^ ERROR type inside `async fn` body must be known in this context
     //~| ERROR type inside `async fn` body must be known in this context
     //~| ERROR type inside `async fn` body must be known in this context
-    //~| ERROR type inside `async fn` body must be known in this context
-    //~| ERROR type inside `async fn` body must be known in this context
-    //~| NOTE cannot infer type for type parameter `T`
-    //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE the type is part of the `async fn` body because of this `await`
-    //~| NOTE in this expansion of desugaring of `await`
-    //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index 8c0ecb8785d..d19a3226ef9 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -34,30 +34,6 @@ note: the type is part of the `async fn` body because of this `await`
 LL |     bar().await;
    |          ^^^^^^
 
-error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/unresolved_type_param.rs:9:5
-   |
-LL |     bar().await;
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
-   |
-note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/unresolved_type_param.rs:9:10
-   |
-LL |     bar().await;
-   |          ^^^^^^
-
-error[E0698]: type inside `async fn` body must be known in this context
-  --> $DIR/unresolved_type_param.rs:9:5
-   |
-LL |     bar().await;
-   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
-   |
-note: the type is part of the `async fn` body because of this `await`
-  --> $DIR/unresolved_type_param.rs:9:10
-   |
-LL |     bar().await;
-   |          ^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0698`.
diff --git a/src/test/ui/generator/drop-control-flow.rs b/src/test/ui/generator/drop-control-flow.rs
new file mode 100644
index 00000000000..6319a29f5b7
--- /dev/null
+++ b/src/test/ui/generator/drop-control-flow.rs
@@ -0,0 +1,121 @@
+// build-pass
+
+// A test to ensure generators capture values that were conditionally dropped,
+// and also that values that are dropped along all paths to a yield do not get
+// included in the generator type.
+
+#![feature(generators, negative_impls)]
+#![allow(unused_assignments, dead_code)]
+
+struct Ptr;
+impl<'a> Drop for Ptr {
+    fn drop(&mut self) {}
+}
+
+struct NonSend;
+impl !Send for NonSend {}
+
+fn assert_send<T: Send>(_: T) {}
+
+// This test case is reduced from src/test/ui/drop/dynamic-drop-async.rs
+fn one_armed_if(arg: bool) {
+    let _ = || {
+        let arr = [Ptr];
+        if arg {
+            drop(arr);
+        }
+        yield;
+    };
+}
+
+fn two_armed_if(arg: bool) {
+    assert_send(|| {
+        let arr = [Ptr];
+        if arg {
+            drop(arr);
+        } else {
+            drop(arr);
+        }
+        yield;
+    })
+}
+
+fn if_let(arg: Option<i32>) {
+    let _ = || {
+        let arr = [Ptr];
+        if let Some(_) = arg {
+            drop(arr);
+        }
+        yield;
+    };
+}
+
+fn init_in_if(arg: bool) {
+    assert_send(|| {
+        let mut x = NonSend;
+        drop(x);
+        if arg {
+            x = NonSend;
+        } else {
+            yield;
+        }
+    })
+}
+
+fn init_in_match_arm(arg: Option<i32>) {
+    assert_send(|| {
+        let mut x = NonSend;
+        drop(x);
+        match arg {
+            Some(_) => x = NonSend,
+            None => yield,
+        }
+    })
+}
+
+fn reinit() {
+    let _ = || {
+        let mut arr = [Ptr];
+        drop(arr);
+        arr = [Ptr];
+        yield;
+    };
+}
+
+fn loop_uninit() {
+    let _ = || {
+        let mut arr = [Ptr];
+        let mut count = 0;
+        drop(arr);
+        while count < 3 {
+            yield;
+            arr = [Ptr];
+            count += 1;
+        }
+    };
+}
+
+fn nested_loop() {
+    let _ = || {
+        let mut arr = [Ptr];
+        let mut count = 0;
+        drop(arr);
+        while count < 3 {
+            for _ in 0..3 {
+                yield;
+            }
+            arr = [Ptr];
+            count += 1;
+        }
+    };
+}
+
+fn main() {
+    one_armed_if(true);
+    if_let(Some(41));
+    init_in_if(true);
+    init_in_match_arm(Some(41));
+    reinit();
+    loop_uninit();
+    nested_loop();
+}
diff --git a/src/test/ui/generator/drop-yield-twice.rs b/src/test/ui/generator/drop-yield-twice.rs
new file mode 100644
index 00000000000..f484cbb8d67
--- /dev/null
+++ b/src/test/ui/generator/drop-yield-twice.rs
@@ -0,0 +1,15 @@
+#![feature(negative_impls, generators)]
+
+struct Foo(i32);
+impl !Send for Foo {}
+
+fn main() {
+    assert_send(|| { //~ ERROR generator cannot be sent between threads safely
+        let guard = Foo(42);
+        yield;
+        drop(guard);
+        yield;
+    })
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/drop-yield-twice.stderr b/src/test/ui/generator/drop-yield-twice.stderr
new file mode 100644
index 00000000000..f821f2f4005
--- /dev/null
+++ b/src/test/ui/generator/drop-yield-twice.stderr
@@ -0,0 +1,25 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/drop-yield-twice.rs:7:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/drop-yield-twice.rs:7:17: 12:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/drop-yield-twice.rs:9:9
+   |
+LL |         let guard = Foo(42);
+   |             ----- has type `Foo` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+...
+LL |     })
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/drop-yield-twice.rs:15:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/issue-57478.rs b/src/test/ui/generator/issue-57478.rs
new file mode 100644
index 00000000000..39710febdb9
--- /dev/null
+++ b/src/test/ui/generator/issue-57478.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(negative_impls, generators)]
+
+struct Foo;
+impl !Send for Foo {}
+
+fn main() {
+    assert_send(|| {
+        let guard = Foo;
+        drop(guard);
+        yield;
+    })
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/partial-drop.rs b/src/test/ui/generator/partial-drop.rs
new file mode 100644
index 00000000000..36f6e78cb3b
--- /dev/null
+++ b/src/test/ui/generator/partial-drop.rs
@@ -0,0 +1,40 @@
+#![feature(negative_impls, generators)]
+
+struct Foo;
+impl !Send for Foo {}
+
+struct Bar {
+    foo: Foo,
+    x: i32,
+}
+
+fn main() {
+    assert_send(|| {
+        //~^ ERROR generator cannot be sent between threads safely
+        // FIXME: it would be nice to make this work.
+        let guard = Bar { foo: Foo, x: 42 };
+        drop(guard.foo);
+        yield;
+    });
+
+    assert_send(|| {
+        //~^ ERROR generator cannot be sent between threads safely
+        // FIXME: it would be nice to make this work.
+        let guard = Bar { foo: Foo, x: 42 };
+        drop(guard);
+        guard.foo = Foo;
+        guard.x = 23;
+        yield;
+    });
+
+    assert_send(|| {
+        //~^ ERROR generator cannot be sent between threads safely
+        // FIXME: it would be nice to make this work.
+        let guard = Bar { foo: Foo, x: 42 };
+        let Bar { foo, x } = guard;
+        drop(foo);
+        yield;
+    });
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/partial-drop.stderr b/src/test/ui/generator/partial-drop.stderr
new file mode 100644
index 00000000000..9a1b0734d8c
--- /dev/null
+++ b/src/test/ui/generator/partial-drop.stderr
@@ -0,0 +1,71 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:12:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:12:17: 18:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:17:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+LL |         drop(guard.foo);
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:20:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:20:17: 28:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:27:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+...
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/partial-drop.rs:30:5
+   |
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/partial-drop.rs:30:17: 37:6]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/partial-drop.rs:36:9
+   |
+LL |         let guard = Bar { foo: Foo, x: 42 };
+   |             ----- has type `Bar` which is not `Send`
+...
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `guard` maybe used later
+LL |     });
+   |     - `guard` is later dropped here
+note: required by a bound in `assert_send`
+  --> $DIR/partial-drop.rs:40:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/generator/reinit-in-match-guard.rs b/src/test/ui/generator/reinit-in-match-guard.rs
new file mode 100644
index 00000000000..260b341a525
--- /dev/null
+++ b/src/test/ui/generator/reinit-in-match-guard.rs
@@ -0,0 +1,25 @@
+// build-pass
+
+#![feature(generators)]
+
+#![allow(unused_assignments, dead_code)]
+
+fn main() {
+    let _ = || {
+        let mut x = vec![22_usize];
+        std::mem::drop(x);
+        match y() {
+            true if {
+                x = vec![];
+                false
+            } => {}
+            _ => {
+                yield;
+            }
+        }
+    };
+}
+
+fn y() -> bool {
+    true
+}
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.stderr b/src/test/ui/hygiene/rustc-macro-transparency.stderr
index e4c1c8ad293..17d05dd0963 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.stderr
+++ b/src/test/ui/hygiene/rustc-macro-transparency.stderr
@@ -11,16 +11,10 @@ LL |     struct SemiTransparent;
    |     ----------------------- similarly named unit struct `SemiTransparent` defined here
 ...
 LL |     semitransparent;
-   |     ^^^^^^^^^^^^^^^ not a value
-   |
-help: use `!` to invoke the macro
-   |
-LL |     semitransparent!;
-   |                    +
-help: a unit struct with a similar name exists
-   |
-LL |     SemiTransparent;
-   |     ~~~~~~~~~~~~~~~
+   |     ^^^^^^^^^^^^^^^
+   |     |
+   |     not a value
+   |     help: a unit struct with a similar name exists: `SemiTransparent`
 
 error[E0423]: expected value, found macro `opaque`
   --> $DIR/rustc-macro-transparency.rs:30:5
@@ -29,16 +23,10 @@ LL |     struct Opaque;
    |     -------------- similarly named unit struct `Opaque` defined here
 ...
 LL |     opaque;
-   |     ^^^^^^ not a value
-   |
-help: use `!` to invoke the macro
-   |
-LL |     opaque!;
-   |           +
-help: a unit struct with a similar name exists
-   |
-LL |     Opaque;
-   |     ~~~~~~
+   |     ^^^^^^
+   |     |
+   |     not a value
+   |     help: a unit struct with a similar name exists (notice the capitalization): `Opaque`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/lint/must_not_suspend/dedup.rs b/src/test/ui/lint/must_not_suspend/dedup.rs
index 040fff5a5a5..81a08579bb7 100644
--- a/src/test/ui/lint/must_not_suspend/dedup.rs
+++ b/src/test/ui/lint/must_not_suspend/dedup.rs
@@ -13,7 +13,7 @@ async fn wheeee<T>(t: T) {
 }
 
 async fn yes() {
-    wheeee(No {}).await; //~ ERROR `No` held across
+    wheeee(&No {}).await; //~ ERROR `No` held across
 }
 
 fn main() {
diff --git a/src/test/ui/lint/must_not_suspend/dedup.stderr b/src/test/ui/lint/must_not_suspend/dedup.stderr
index bc1b611299a..13fa3ae3008 100644
--- a/src/test/ui/lint/must_not_suspend/dedup.stderr
+++ b/src/test/ui/lint/must_not_suspend/dedup.stderr
@@ -1,8 +1,8 @@
 error: `No` held across a suspend point, but should not be
-  --> $DIR/dedup.rs:16:12
+  --> $DIR/dedup.rs:16:13
    |
-LL |     wheeee(No {}).await;
-   |            ^^^^^ ------ the value is held across this suspend point
+LL |     wheeee(&No {}).await;
+   |             ^^^^^ ------ the value is held across this suspend point
    |
 note: the lint level is defined here
   --> $DIR/dedup.rs:3:9
@@ -10,10 +10,10 @@ note: the lint level is defined here
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/dedup.rs:16:12
+  --> $DIR/dedup.rs:16:13
    |
-LL |     wheeee(No {}).await;
-   |            ^^^^^
+LL |     wheeee(&No {}).await;
+   |             ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/resolve-hint-macro.fixed b/src/test/ui/resolve/resolve-hint-macro.fixed
new file mode 100644
index 00000000000..54e01608498
--- /dev/null
+++ b/src/test/ui/resolve/resolve-hint-macro.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+fn main() {
+    assert_eq!(1, 1);
+    //~^ ERROR expected function, found macro `assert_eq`
+    assert_eq! { 1, 1 };
+    //~^ ERROR expected struct, variant or union type, found macro `assert_eq`
+    //~| ERROR expected identifier, found `1`
+    //~| ERROR expected identifier, found `1`
+    assert![true];
+    //~^ ERROR expected value, found macro `assert`
+}
diff --git a/src/test/ui/resolve/resolve-hint-macro.rs b/src/test/ui/resolve/resolve-hint-macro.rs
index 5532c8b90e3..f16e8c07553 100644
--- a/src/test/ui/resolve/resolve-hint-macro.rs
+++ b/src/test/ui/resolve/resolve-hint-macro.rs
@@ -1,4 +1,11 @@
+// run-rustfix
 fn main() {
     assert_eq(1, 1);
     //~^ ERROR expected function, found macro `assert_eq`
+    assert_eq { 1, 1 };
+    //~^ ERROR expected struct, variant or union type, found macro `assert_eq`
+    //~| ERROR expected identifier, found `1`
+    //~| ERROR expected identifier, found `1`
+    assert[true];
+    //~^ ERROR expected value, found macro `assert`
 }
diff --git a/src/test/ui/resolve/resolve-hint-macro.stderr b/src/test/ui/resolve/resolve-hint-macro.stderr
index 78d77678083..bc69ddd8ffe 100644
--- a/src/test/ui/resolve/resolve-hint-macro.stderr
+++ b/src/test/ui/resolve/resolve-hint-macro.stderr
@@ -1,5 +1,21 @@
+error: expected identifier, found `1`
+  --> $DIR/resolve-hint-macro.rs:5:17
+   |
+LL |     assert_eq { 1, 1 };
+   |     ---------   ^ expected identifier
+   |     |
+   |     while parsing this struct
+
+error: expected identifier, found `1`
+  --> $DIR/resolve-hint-macro.rs:5:20
+   |
+LL |     assert_eq { 1, 1 };
+   |     ---------      ^ expected identifier
+   |     |
+   |     while parsing this struct
+
 error[E0423]: expected function, found macro `assert_eq`
-  --> $DIR/resolve-hint-macro.rs:2:5
+  --> $DIR/resolve-hint-macro.rs:3:5
    |
 LL |     assert_eq(1, 1);
    |     ^^^^^^^^^ not a function
@@ -9,6 +25,29 @@ help: use `!` to invoke the macro
 LL |     assert_eq!(1, 1);
    |              +
 
-error: aborting due to previous error
+error[E0574]: expected struct, variant or union type, found macro `assert_eq`
+  --> $DIR/resolve-hint-macro.rs:5:5
+   |
+LL |     assert_eq { 1, 1 };
+   |     ^^^^^^^^^ not a struct, variant or union type
+   |
+help: use `!` to invoke the macro
+   |
+LL |     assert_eq! { 1, 1 };
+   |              +
+
+error[E0423]: expected value, found macro `assert`
+  --> $DIR/resolve-hint-macro.rs:9:5
+   |
+LL |     assert[true];
+   |     ^^^^^^ not a value
+   |
+help: use `!` to invoke the macro
+   |
+LL |     assert![true];
+   |           +
+
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0423`.
+Some errors have detailed explanations: E0423, E0574.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
index 5915cb9df26..945c665e35d 100644
--- a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(let_chains)]
+#![feature(if_let_guard, let_chains)]
 
 use std::ops::Range;
 
@@ -16,6 +16,16 @@ fn main() {
         && let None = local_start {
     }
 
+    match opt {
+        Some(ref first) if let second = first && let _third = second => {},
+        _ => {}
+    }
+    match opt {
+        Some(ref first) if let Range { start: local_start, end: _ } = first
+            && let None = local_start => {},
+        _ => {}
+    }
+
     while let first = &opt && let Some(ref second) = first && let None = second.start {
     }
     while let Some(ref first) = opt && let second = first && let _third = second {
diff --git a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
index 0856a105206..e061174f667 100644
--- a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(let_chains)]
+#![feature(if_let_guard, let_chains)]
 
 fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
     if let Some(first) = opt
@@ -15,6 +15,17 @@ fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
     }
 }
 
+fn check_let_guard(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    match opt {
+        Some(first) if let Some(second) = first && let Some(third) = second && third == value => {
+            true
+        }
+        _ => {
+            false
+        }
+    }
+}
+
 fn check_while_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
     while let Some(first) = opt
         && let Some(second) = first
@@ -30,6 +41,9 @@ fn main() {
     assert_eq!(check_if_let(Some(Some(Some(1))), 1), true);
     assert_eq!(check_if_let(Some(Some(Some(1))), 9), false);
 
+    assert_eq!(check_let_guard(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_let_guard(Some(Some(Some(1))), 9), false);
+
     assert_eq!(check_while_let(Some(Some(Some(1))), 1), true);
     assert_eq!(check_while_let(Some(Some(Some(1))), 9), false);
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index f039ba59d23..22785013085 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -500,7 +500,19 @@ impl<'test> TestCx<'test> {
             expected = expected.replace(&cr, "");
         }
 
-        self.compare_source(&expected, &actual);
+        if !self.config.bless {
+            self.compare_source(&expected, &actual);
+        } else if expected != actual {
+            let filepath_buf;
+            let filepath = match &self.props.pp_exact {
+                Some(file) => {
+                    filepath_buf = self.testpaths.file.parent().unwrap().join(file);
+                    &filepath_buf
+                }
+                None => &self.testpaths.file,
+            };
+            fs::write(filepath, &actual).unwrap();
+        }
 
         // If we're only making sure that the output matches then just stop here
         if self.props.pretty_compare_only {