about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/alloc/src/collections/btree/node.rs81
-rw-r--r--library/std/src/primitive_docs.rs57
-rw-r--r--src/bootstrap/native.rs2
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile7
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile7
-rw-r--r--src/librustc_ast/util/parser.rs1
-rw-r--r--src/librustc_builtin_macros/format.rs33
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs3
-rw-r--r--src/librustc_codegen_ssa/mir/debuginfo.rs8
-rw-r--r--src/librustc_error_codes/error_codes/E0477.md3
-rw-r--r--src/librustc_middle/mir/mod.rs9
-rw-r--r--src/librustc_middle/ty/query/profiling_support.rs46
-rw-r--r--src/librustc_mir/transform/match_branches.rs93
-rw-r--r--src/librustc_mir/transform/mod.rs2
-rw-r--r--src/librustc_mir_build/build/mod.rs12
-rw-r--r--src/librustc_parse/parser/expr.rs11
-rw-r--r--src/librustc_query_system/query/caches.rs9
-rw-r--r--src/librustc_query_system/query/plumbing.rs10
-rw-r--r--src/librustc_typeck/check/demand.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs8
-rw-r--r--src/test/codegen/naked-functions.rs4
-rw-r--r--src/test/debuginfo/function-arguments-naked.rs42
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit66
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit66
-rw-r--r--src/test/mir-opt/matches_reduce_branches.rs13
-rw-r--r--src/test/ui/issues/issue-75307.rs3
-rw-r--r--src/test/ui/issues/issue-75307.stderr10
-rw-r--r--src/test/ui/parser/expr-as-stmt-2.rs10
-rw-r--r--src/test/ui/parser/expr-as-stmt-2.stderr33
-rw-r--r--src/test/ui/parser/expr-as-stmt.fixed6
-rw-r--r--src/test/ui/parser/expr-as-stmt.rs6
-rw-r--r--src/test/ui/parser/expr-as-stmt.stderr12
-rw-r--r--src/test/ui/unknown-llvm-arg.rs22
-rw-r--r--src/test/ui/unknown-llvm-arg.stderr1
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--triagebot.toml91
36 files changed, 552 insertions, 237 deletions
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index f70869148d5..aa959c667ac 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -821,6 +821,53 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
     }
 }
 
+enum InsertionPlace {
+    Left(usize),
+    Right(usize),
+}
+
+/// Given an edge index where we want to insert into a node filled to capacity,
+/// computes a sensible KV index of a split point and where to perform the insertion.
+/// The goal of the split point is for its key and value to end up in a parent node;
+/// the keys, values and edges to the left of the split point become the left child;
+/// the keys, values and edges to the right of the split point become the right child.
+fn splitpoint(edge_idx: usize) -> (usize, InsertionPlace) {
+    debug_assert!(edge_idx <= CAPACITY);
+    // Rust issue #74834 tries to explain these symmetric rules.
+    let middle_kv_idx;
+    let insertion;
+    if edge_idx <= B - 2 {
+        middle_kv_idx = B - 2;
+        insertion = InsertionPlace::Left(edge_idx);
+    } else if edge_idx == B - 1 {
+        middle_kv_idx = B - 1;
+        insertion = InsertionPlace::Left(edge_idx);
+    } else if edge_idx == B {
+        middle_kv_idx = B - 1;
+        insertion = InsertionPlace::Right(0);
+    } else {
+        middle_kv_idx = B;
+        let new_edge_idx = edge_idx - (B + 1);
+        insertion = InsertionPlace::Right(new_edge_idx);
+    }
+    let mut left_len = middle_kv_idx;
+    let mut right_len = CAPACITY - middle_kv_idx - 1;
+    match insertion {
+        InsertionPlace::Left(edge_idx) => {
+            debug_assert!(edge_idx <= left_len);
+            left_len += 1;
+        }
+        InsertionPlace::Right(edge_idx) => {
+            debug_assert!(edge_idx <= right_len);
+            right_len += 1;
+        }
+    }
+    debug_assert!(left_len >= MIN_LEN);
+    debug_assert!(right_len >= MIN_LEN);
+    debug_assert!(left_len + right_len == CAPACITY);
+    (middle_kv_idx, insertion)
+}
+
 impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::Edge> {
     /// Helps implementations of `insert_fit` for a particular `NodeType`,
     /// by taking care of leaf data.
@@ -863,18 +910,20 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
             let kv = unsafe { Handle::new_kv(self.node, self.idx) };
             (InsertResult::Fit(kv), ptr)
         } else {
-            let middle = unsafe { Handle::new_kv(self.node, B) };
+            let (middle_kv_idx, insertion) = splitpoint(self.idx);
+            let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
             let (mut left, k, v, mut right) = middle.split();
-            let ptr = if self.idx <= B {
-                unsafe { Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val) }
-            } else {
-                unsafe {
+            let ptr = match insertion {
+                InsertionPlace::Left(insert_idx) => unsafe {
+                    Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val)
+                },
+                InsertionPlace::Right(insert_idx) => unsafe {
                     Handle::new_edge(
                         right.node_as_mut().cast_unchecked::<marker::Leaf>(),
-                        self.idx - (B + 1),
+                        insert_idx,
                     )
                     .insert_fit(key, val)
-                }
+                },
             };
             (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), ptr)
         }
@@ -936,20 +985,20 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
             let kv = unsafe { Handle::new_kv(self.node, self.idx) };
             InsertResult::Fit(kv)
         } else {
-            let middle = unsafe { Handle::new_kv(self.node, B) };
+            let (middle_kv_idx, insertion) = splitpoint(self.idx);
+            let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
             let (mut left, k, v, mut right) = middle.split();
-            if self.idx <= B {
-                unsafe {
-                    Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val, edge);
-                }
-            } else {
-                unsafe {
+            match insertion {
+                InsertionPlace::Left(insert_idx) => unsafe {
+                    Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val, edge);
+                },
+                InsertionPlace::Right(insert_idx) => unsafe {
                     Handle::new_edge(
                         right.node_as_mut().cast_unchecked::<marker::Internal>(),
-                        self.idx - (B + 1),
+                        insert_idx,
                     )
                     .insert_fit(key, val, edge);
-                }
+                },
             }
             InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right })
         }
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 0d2aca6bbc3..bca1732b84d 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -1058,6 +1058,8 @@ mod prim_ref {}
 /// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null
 /// pointers, make your type `Option<fn()>` with your required signature.
 ///
+/// ### Safety
+///
 /// Plain function pointers are obtained by casting either plain functions, or closures that don't
 /// capture an environment:
 ///
@@ -1095,23 +1097,60 @@ mod prim_ref {}
 /// let really_safe_ptr: unsafe fn(usize) -> usize = add_one;
 /// ```
 ///
-/// On top of that, function pointers can vary based on what ABI they use. This is achieved by
-/// adding the `extern` keyword to the type name, followed by the ABI in question. For example,
-/// `fn()` is different from `extern "C" fn()`, which itself is different from `extern "stdcall"
-/// fn()`, and so on for the various ABIs that Rust supports. Non-`extern` functions have an ABI
-/// of `"Rust"`, and `extern` functions without an explicit ABI have an ABI of `"C"`. For more
-/// information, see [the nomicon's section on foreign calling conventions][nomicon-abi].
+/// ### ABI
+///
+/// On top of that, function pointers can vary based on what ABI they use. This
+/// is achieved by adding the `extern` keyword before the type, followed by the
+/// ABI in question. The default ABI is "Rust", i.e., `fn()` is the exact same
+/// type as `extern "Rust" fn()`. A pointer to a function with C ABI would have
+/// type `extern "C" fn()`.
+///
+/// `extern "ABI" { ... }` blocks declare functions with ABI "ABI". The default
+/// here is "C", i.e., functions declared in an `extern {...}` block have "C"
+/// ABI.
+///
+/// For more information and a list of supported ABIs, see [the nomicon's
+/// section on foreign calling conventions][nomicon-abi].
 ///
-/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
+/// ### Variadic functions
 ///
 /// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
-/// to be called with a variable number of arguments. Normal rust functions, even those with an
+/// to be called with a variable number of arguments. Normal Rust functions, even those with an
 /// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on
 /// variadic functions][nomicon-variadic].
 ///
 /// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions
 ///
-/// These markers can be combined, so `unsafe extern "stdcall" fn()` is a valid type.
+/// ### Creating function pointers
+///
+/// When `bar` is the name of a function, then the expression `bar` is *not* a
+/// function pointer. Rather, it denotes a value of an unnameable type that
+/// uniquely identifies the function `bar`. The value is zero-sized because the
+/// type already identifies the function. This has the advantage that "calling"
+/// the value (it implements the `Fn*` traits) does not require dynamic
+/// dispatch.
+///
+/// This zero-sized type *coerces* to a regular function pointer. For example:
+///
+/// ```rust
+/// use std::mem;
+///
+/// fn bar(x: i32) {}
+///
+/// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar`
+/// assert_eq!(mem::size_of_val(&not_bar_ptr), 0);
+///
+/// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer
+/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::<usize>());
+///
+/// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar`
+/// ```
+///
+/// The last line shows that `&bar` is not a function pointer either. Rather, it
+/// is a reference to the function-specific ZST. `&bar` is basically never what you
+/// want when `bar` is a function.
+///
+/// ### Traits
 ///
 /// Function pointers implement the following traits:
 ///
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 48b2cc24d4c..3ab50e114c7 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -178,7 +178,7 @@ impl Step for Llvm {
             .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
             .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
 
-        if !target.contains("netbsd") {
+        if !target.contains("netbsd") && target != "aarch64-apple-darwin" {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
             // FIXME: Enable zlib on NetBSD too
diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
index 6a596b3465f..cb507dced42 100644
--- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
@@ -19,8 +19,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+RUN mkdir -p /config
+RUN echo "[rust]" > /config/nopt-std-config.toml
+RUN echo "optimize = false" >> /config/nopt-std-config.toml
+
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
-ENV SCRIPT python3 ../x.py --stage 2 test
+ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
+  && python3 ../x.py --stage 2 test
 
 # FIXME(#59637) takes too long on CI right now
 ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
index fa769cac9c1..41e83c69e54 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
@@ -18,7 +18,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+RUN mkdir -p /config
+RUN echo "[rust]" > /config/nopt-std-config.toml
+RUN echo "optimize = false" >> /config/nopt-std-config.toml
+
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
   --disable-optimize-tests \
   --set rust.test-compare-mode
-ENV SCRIPT python3 ../x.py --stage 2 test
+ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
+  && python3 ../x.py --stage 2 test
diff --git a/src/librustc_ast/util/parser.rs b/src/librustc_ast/util/parser.rs
index e5bcc571d41..2ee94965756 100644
--- a/src/librustc_ast/util/parser.rs
+++ b/src/librustc_ast/util/parser.rs
@@ -222,7 +222,6 @@ impl AssocOp {
             Greater | // `{ 42 } > 3`
             GreaterEqual | // `{ 42 } >= 3`
             AssignOp(_) | // `{ 42 } +=`
-            LAnd | // `{ 42 } &&foo`
             As | // `{ 42 } as usize`
             // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
             // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs
index 55eab24b8a5..78cead02b7b 100644
--- a/src/librustc_builtin_macros/format.rs
+++ b/src/librustc_builtin_macros/format.rs
@@ -149,7 +149,7 @@ fn parse_args<'a>(
                 return Err(err);
             } else {
                 // ...after that delegate to `expect` to also include the other expected tokens.
-                return Err(p.expect(&token::Comma).err().unwrap());
+                let _ = p.expect(&token::Comma)?;
             }
         }
         first = false;
@@ -359,24 +359,18 @@ impl<'a, 'b> Context<'a, 'b> {
             // for `println!("{7:7$}", 1);`
             refs.sort();
             refs.dedup();
-            let (arg_list, mut sp) = if refs.len() == 1 {
-                let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect();
-                (
-                    format!("argument {}", refs[0]),
-                    if spans.is_empty() {
-                        MultiSpan::from_span(self.fmtsp)
-                    } else {
-                        MultiSpan::from_spans(spans)
-                    },
-                )
+            let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect();
+            let sp = if self.arg_spans.is_empty() || spans.is_empty() {
+                MultiSpan::from_span(self.fmtsp)
+            } else {
+                MultiSpan::from_spans(spans)
+            };
+            let arg_list = if refs.len() == 1 {
+                format!("argument {}", refs[0])
             } else {
-                let pos = MultiSpan::from_spans(spans.into_iter().map(|s| *s.unwrap()).collect());
                 let reg = refs.pop().unwrap();
-                (format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg,), pos)
+                format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg)
             };
-            if self.arg_spans.is_empty() {
-                sp = MultiSpan::from_span(self.fmtsp);
-            }
 
             e = self.ecx.struct_span_err(
                 sp,
@@ -1067,10 +1061,9 @@ pub fn expand_preparsed_format_args(
         let args_unused = errs_len;
 
         let mut diag = {
-            if errs_len == 1 {
-                let (sp, msg) = errs.into_iter().next().unwrap();
-                let mut diag = cx.ecx.struct_span_err(sp, msg);
-                diag.span_label(sp, msg);
+            if let [(sp, msg)] = &errs[..] {
+                let mut diag = cx.ecx.struct_span_err(*sp, *msg);
+                diag.span_label(*sp, *msg);
                 diag
             } else {
                 let mut diag = cx.ecx.struct_span_err(
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index b631c10334c..f0b50459837 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -73,7 +73,8 @@ unsafe fn configure_llvm(sess: &Session) {
                 llvm_c_strs.push(s);
             }
         };
-        add("rustc", true); // fake program name
+        // Set the llvm "program name" to make usage and invalid argument messages more clear.
+        add("rustc -Cllvm-args=\"...\" with", true);
         if sess.time_llvm_passes() {
             add("-time-passes", false);
         }
diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs
index d166a27b5a9..d8a530d98fa 100644
--- a/src/librustc_codegen_ssa/mir/debuginfo.rs
+++ b/src/librustc_codegen_ssa/mir/debuginfo.rs
@@ -1,6 +1,7 @@
 use crate::traits::*;
 use rustc_hir::def_id::CrateNum;
 use rustc_index::vec::IndexVec;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_session::config::DebugInfo;
@@ -216,6 +217,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             LocalRef::Operand(None) => return,
 
             LocalRef::Operand(Some(operand)) => {
+                // Don't spill operands onto the stack in naked functions.
+                // See: https://github.com/rust-lang/rust/issues/42779
+                let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id());
+                if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+                    return;
+                }
+
                 // "Spill" the value onto the stack, for debuginfo,
                 // without forcing non-debuginfo uses of the local
                 // to also load from the stack every single time.
diff --git a/src/librustc_error_codes/error_codes/E0477.md b/src/librustc_error_codes/error_codes/E0477.md
index 794456451ef..9cfefb1de63 100644
--- a/src/librustc_error_codes/error_codes/E0477.md
+++ b/src/librustc_error_codes/error_codes/E0477.md
@@ -37,8 +37,7 @@ fn i_want_static_closure<F>(a: F)
 
 fn print_string(s: Mutex<MyString<'static>>) {
 
-    i_want_static_closure(move || {     // error: this closure has lifetime 'a
-                                        //        rather than 'static
+    i_want_static_closure(move || {     // ok!
         println!("{}", s.lock().unwrap().data);
     });
 }
diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 3b0c480f6d4..98fd68927f1 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -857,9 +857,12 @@ pub struct LocalDecl<'tcx> {
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(LocalDecl<'_>, 56);
 
-/// Extra information about a some locals that's used for diagnostics. (Not
-/// used for non-StaticRef temporaries, the return place, or anonymous function
-/// parameters.)
+/// Extra information about a some locals that's used for diagnostics and for
+/// classifying variables into local variables, statics, etc, which is needed e.g.
+/// for unsafety checking.
+///
+/// Not used for non-StaticRef temporaries, the return place, or anonymous
+/// function parameters.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
 pub enum LocalInfo<'tcx> {
     /// A user-defined local variable or function parameter
diff --git a/src/librustc_middle/ty/query/profiling_support.rs b/src/librustc_middle/ty/query/profiling_support.rs
index 0683dc02011..9b1837356e3 100644
--- a/src/librustc_middle/ty/query/profiling_support.rs
+++ b/src/librustc_middle/ty/query/profiling_support.rs
@@ -1,8 +1,9 @@
 use crate::ty::context::TyCtxt;
+use crate::ty::WithOptConstParam;
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
 use rustc_query_system::query::QueryCache;
 use rustc_query_system::query::QueryState;
@@ -154,6 +155,49 @@ impl SpecIntoSelfProfilingString for DefIndex {
     }
 }
 
+impl SpecIntoSelfProfilingString for LocalDefId {
+    fn spec_to_self_profile_string(
+        &self,
+        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+    ) -> StringId {
+        builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
+    }
+}
+
+impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
+    fn spec_to_self_profile_string(
+        &self,
+        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+    ) -> StringId {
+        // We print `WithOptConstParam` values as tuples to make them shorter
+        // and more readable, without losing information:
+        //
+        // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
+        // becomes "(foo::bar, foo::baz)" and
+        // "WithOptConstParam { did: foo::bar, const_param_did: None }"
+        // becomes "(foo::bar, _)".
+
+        let did = StringComponent::Ref(self.did.to_self_profile_string(builder));
+
+        let const_param_did = if let Some(const_param_did) = self.const_param_did {
+            let const_param_did = builder.def_id_to_string_id(const_param_did);
+            StringComponent::Ref(const_param_did)
+        } else {
+            StringComponent::Value("_")
+        };
+
+        let components = [
+            StringComponent::Value("("),
+            did,
+            StringComponent::Value(", "),
+            const_param_did,
+            StringComponent::Value(")"),
+        ];
+
+        builder.profiler.alloc_string(&components[..])
+    }
+}
+
 impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
 where
     T0: SpecIntoSelfProfilingString,
diff --git a/src/librustc_mir/transform/match_branches.rs b/src/librustc_mir/transform/match_branches.rs
new file mode 100644
index 00000000000..74da6d5e629
--- /dev/null
+++ b/src/librustc_mir/transform/match_branches.rs
@@ -0,0 +1,93 @@
+use crate::transform::{MirPass, MirSource};
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+pub struct MatchBranchSimplification;
+
+// What's the intent of this pass?
+// If one block is found that switches between blocks which both go to the same place
+// AND both of these blocks set a similar const in their ->
+// condense into 1 block based on discriminant AND goto the destination afterwards
+
+impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+        let param_env = tcx.param_env(src.def_id());
+        let bbs = body.basic_blocks_mut();
+        'outer: for bb_idx in bbs.indices() {
+            let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
+                TerminatorKind::SwitchInt {
+                    discr: Operand::Move(ref place),
+                    switch_ty,
+                    ref targets,
+                    ref values,
+                    ..
+                } if targets.len() == 2 && values.len() == 1 => {
+                    (place, values[0], switch_ty, targets[0], targets[1])
+                }
+                // Only optimize switch int statements
+                _ => continue,
+            };
+
+            // Check that destinations are identical, and if not, then don't optimize this block
+            if &bbs[first].terminator().kind != &bbs[second].terminator().kind {
+                continue;
+            }
+
+            // Check that blocks are assignments of consts to the same place or same statement,
+            // and match up 1-1, if not don't optimize this block.
+            let first_stmts = &bbs[first].statements;
+            let scnd_stmts = &bbs[second].statements;
+            if first_stmts.len() != scnd_stmts.len() {
+                continue;
+            }
+            for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) {
+                match (&f.kind, &s.kind) {
+                    // If two statements are exactly the same just ignore them.
+                    (f_s, s_s) if f_s == s_s => (),
+
+                    (
+                        StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
+                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
+                    ) if lhs_f == lhs_s => {
+                        if let Some(f_c) = f_c.literal.try_eval_bool(tcx, param_env) {
+                            // This should also be a bool because it's writing to the same place
+                            let s_c = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
+                            if f_c != s_c {
+                                // have to check this here because f_c & s_c might have
+                                // different spans.
+                                continue;
+                            }
+                        }
+                        continue 'outer;
+                    }
+                    // If there are not exclusively assignments, then ignore this
+                    _ => continue 'outer,
+                }
+            }
+            // Take owenership of items now that we know we can optimize.
+            let discr = discr.clone();
+            let (from, first) = bbs.pick2_mut(bb_idx, first);
+
+            let new_stmts = first.statements.iter().cloned().map(|mut s| {
+                if let StatementKind::Assign(box (_, ref mut rhs)) = s.kind {
+                    if let Rvalue::Use(Operand::Constant(c)) = rhs {
+                        let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+                        let const_cmp = Operand::const_from_scalar(
+                            tcx,
+                            switch_ty,
+                            crate::interpret::Scalar::from_uint(val, size),
+                            rustc_span::DUMMY_SP,
+                        );
+                        if let Some(c) = c.literal.try_eval_bool(tcx, param_env) {
+                            let op = if c { BinOp::Eq } else { BinOp::Ne };
+                            *rhs = Rvalue::BinaryOp(op, Operand::Move(discr), const_cmp);
+                        }
+                    }
+                }
+                s
+            });
+            from.statements.extend(new_stmts);
+            from.terminator_mut().kind = first.terminator().kind.clone();
+        }
+    }
+}
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 3803ee78fd4..4f26f3bb459 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -29,6 +29,7 @@ pub mod generator;
 pub mod inline;
 pub mod instcombine;
 pub mod instrument_coverage;
+pub mod match_branches;
 pub mod no_landing_pads;
 pub mod nrvo;
 pub mod promote_consts;
@@ -440,6 +441,7 @@ fn run_optimization_passes<'tcx>(
         // with async primitives.
         &generator::StateTransform,
         &instcombine::InstCombine,
+        &match_branches::MatchBranchSimplification,
         &const_prop::ConstProp,
         &simplify_branches::SimplifyBranches::new("after-const-prop"),
         &simplify_try::SimplifyArmIdentity,
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index f3f3c3e33a4..215a0c7dfdf 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -10,7 +10,6 @@ use rustc_hir::lang_items;
 use rustc_hir::{GeneratorKind, HirIdMap, Node};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::Subst;
@@ -798,22 +797,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         argument_scope: region::Scope,
         ast_body: &'tcx hir::Expr<'tcx>,
     ) -> BlockAnd<()> {
-        let tcx = self.hir.tcx();
-        let attrs = tcx.codegen_fn_attrs(fn_def_id);
-        let naked = attrs.flags.contains(CodegenFnAttrFlags::NAKED);
-
         // Allocate locals for the function arguments
         for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
             let source_info =
                 SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span));
             let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info));
 
-            // Emit function argument debuginfo only for non-naked functions.
-            // See: https://github.com/rust-lang/rust/issues/42779
-            if naked {
-                continue;
-            }
-
             // If this is a simple binding pattern, give debuginfo a nice name.
             if let Some(arg) = arg_opt {
                 if let Some(ident) = arg.pat.simple_ident() {
@@ -826,6 +815,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
+        let tcx = self.hir.tcx();
         let tcx_hir = tcx.hir();
         let hir_typeck_results = self.hir.typeck_results();
 
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 9b99eb2e0bd..8e2bee26468 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -318,11 +318,18 @@ impl<'a> Parser<'a> {
             // want to keep their span info to improve diagnostics in these cases in a later stage.
             (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
             (true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
-            (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475)
             (true, Some(AssocOp::Add)) // `{ 42 } + 42
             // If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
             // `if x { a } else { b } && if y { c } else { d }`
-            if !self.look_ahead(1, |t| t.is_reserved_ident()) => {
+            if !self.look_ahead(1, |t| t.is_used_keyword()) => {
+                // These cases are ambiguous and can't be identified in the parser alone.
+                let sp = self.sess.source_map().start_point(self.token.span);
+                self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
+                false
+            }
+            (true, Some(AssocOp::LAnd)) => {
+                // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
+                // above due to #74233.
                 // These cases are ambiguous and can't be identified in the parser alone.
                 let sp = self.sess.source_map().start_point(self.token.span);
                 self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
diff --git a/src/librustc_query_system/query/caches.rs b/src/librustc_query_system/query/caches.rs
index f0beec0a177..1839e1af45e 100644
--- a/src/librustc_query_system/query/caches.rs
+++ b/src/librustc_query_system/query/caches.rs
@@ -43,9 +43,8 @@ pub trait QueryCache: QueryStorage {
         OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R,
         OnMiss: FnOnce(Self::Key, QueryLookup<'_, CTX, Self::Key, Self::Sharded>) -> R;
 
-    fn complete<CTX: QueryContext>(
+    fn complete(
         &self,
-        tcx: CTX,
         lock_sharded_storage: &mut Self::Sharded,
         key: Self::Key,
         value: Self::Value,
@@ -112,9 +111,8 @@ impl<K: Eq + Hash, V: Clone> QueryCache for DefaultCache<K, V> {
     }
 
     #[inline]
-    fn complete<CTX: QueryContext>(
+    fn complete(
         &self,
-        _: CTX,
         lock_sharded_storage: &mut Self::Sharded,
         key: K,
         value: V,
@@ -195,9 +193,8 @@ impl<'tcx, K: Eq + Hash, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V> {
     }
 
     #[inline]
-    fn complete<CTX: QueryContext>(
+    fn complete(
         &self,
-        _: CTX,
         lock_sharded_storage: &mut Self::Sharded,
         key: K,
         value: V,
diff --git a/src/librustc_query_system/query/plumbing.rs b/src/librustc_query_system/query/plumbing.rs
index cc7d0a15703..ae042cc8081 100644
--- a/src/librustc_query_system/query/plumbing.rs
+++ b/src/librustc_query_system/query/plumbing.rs
@@ -264,7 +264,7 @@ where
     /// Completes the query by updating the query cache with the `result`,
     /// signals the waiter and forgets the JobOwner, so it won't poison the query
     #[inline(always)]
-    fn complete(self, tcx: CTX, result: C::Value, dep_node_index: DepNodeIndex) -> C::Stored {
+    fn complete(self, result: C::Value, dep_node_index: DepNodeIndex) -> C::Stored {
         // We can move out of `self` here because we `mem::forget` it below
         let key = unsafe { ptr::read(&self.key) };
         let state = self.state;
@@ -278,7 +278,7 @@ where
                 QueryResult::Started(job) => job,
                 QueryResult::Poisoned => panic!(),
             };
-            let result = state.cache.complete(tcx, &mut lock.cache, key, result, dep_node_index);
+            let result = state.cache.complete(&mut lock.cache, key, result, dep_node_index);
             (job, result)
         };
 
@@ -432,7 +432,7 @@ where
             tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
         }
 
-        return job.complete(tcx, result, dep_node_index);
+        return job.complete(result, dep_node_index);
     }
 
     let dep_node = query.to_dep_node(tcx, &key);
@@ -458,7 +458,7 @@ where
             })
         });
         if let Some((result, dep_node_index)) = loaded {
-            return job.complete(tcx, result, dep_node_index);
+            return job.complete(result, dep_node_index);
         }
     }
 
@@ -609,7 +609,7 @@ where
         }
     }
 
-    let result = job.complete(tcx, result, dep_node_index);
+    let result = job.complete(result, dep_node_index);
 
     (result, dep_node_index)
 }
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 258c5b77df2..4ea76a4a9e2 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
         self.suggest_missing_await(err, expr, expected, expr_ty);
+        self.suggest_missing_parentheses(err, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
     }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a40b6860f77..6957b6b2a05 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5401,6 +5401,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) {
+        let sp = self.tcx.sess.source_map().start_point(expr.span);
+        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
+        }
+    }
+
     fn note_need_for_fn_pointer(
         &self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs
index 758c6c4da92..493c1b9f0ba 100644
--- a/src/test/codegen/naked-functions.rs
+++ b/src/test/codegen/naked-functions.rs
@@ -18,7 +18,7 @@ pub fn naked_empty() {
 // CHECK-NEXT: define void @naked_with_args(i{{[0-9]+( %0)?}})
 pub fn naked_with_args(a: isize) {
     // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: %_1 = alloca i{{[0-9]+}}
+    // CHECK-NEXT: %a = alloca i{{[0-9]+}}
     &a; // keep variable in an alloca
     // CHECK: ret void
 }
@@ -39,7 +39,7 @@ pub fn naked_with_return() -> isize {
 #[naked]
 pub fn naked_with_args_and_return(a: isize) -> isize {
     // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: %_1 = alloca i{{[0-9]+}}
+    // CHECK-NEXT: %a = alloca i{{[0-9]+}}
     &a; // keep variable in an alloca
     // CHECK: ret i{{[0-9]+}} %{{[0-9]+}}
     a
diff --git a/src/test/debuginfo/function-arguments-naked.rs b/src/test/debuginfo/function-arguments-naked.rs
deleted file mode 100644
index 5f3a1eb44e4..00000000000
--- a/src/test/debuginfo/function-arguments-naked.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-// min-lldb-version: 310
-
-// We have to ignore android because of this issue:
-// https://github.com/rust-lang/rust/issues/74847
-// ignore-android
-//
-// We need to use inline assembly, so just use one platform
-// only-x86_64
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:run
-
-// gdb-command:info args
-// gdb-check:No arguments.
-// gdb-command:continue
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:frame variable
-// lldbg-check:(unsigned long) = 111 (unsigned long) = 222
-// lldbr-check:(unsigned long) = 111 (unsigned long) = 222
-// lldb-command:continue
-
-
-#![feature(asm)]
-#![feature(naked_functions)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-fn main() {
-    naked(111, 222);
-}
-
-#[naked]
-extern "C" fn naked(x: usize, y: usize) {
-    unsafe { asm!("ret"); } // #break
-}
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit
new file mode 100644
index 00000000000..df94c897e92
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit
@@ -0,0 +1,66 @@
+- // MIR for `foo` before MatchBranchSimplification
++ // MIR for `foo` after MatchBranchSimplification
+  
+  fn foo(_1: std::option::Option<()>) -> () {
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
++         _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x00000000))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) }
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+      }
+  
+      bb1: {
+          _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb2: {
+          _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb3: {
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb4: {
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb5: {
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit
new file mode 100644
index 00000000000..06849b4a5d9
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit
@@ -0,0 +1,66 @@
+- // MIR for `foo` before MatchBranchSimplification
++ // MIR for `foo` after MatchBranchSimplification
+  
+  fn foo(_1: std::option::Option<()>) -> () {
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25
+      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
++         _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
++                                          // ty::Const
++                                          // + ty: isize
++                                          // + val: Value(Scalar(0x0000000000000000))
++                                          // mir::Constant
++                                          // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1
++                                          // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) }
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26
+      }
+  
+      bb1: {
+          _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb2: {
+          _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      }
+  
+      bb3: {
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb4: {
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6
+      }
+  
+      bb5: {
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs
new file mode 100644
index 00000000000..91b6bfc836b
--- /dev/null
+++ b/src/test/mir-opt/matches_reduce_branches.rs
@@ -0,0 +1,13 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
+
+fn foo(bar: Option<()>) {
+    if matches!(bar, None) {
+      ()
+    }
+}
+
+fn main() {
+  let _ = foo(None);
+  let _ = foo(Some(()));
+}
diff --git a/src/test/ui/issues/issue-75307.rs b/src/test/ui/issues/issue-75307.rs
new file mode 100644
index 00000000000..2fe112a3b95
--- /dev/null
+++ b/src/test/ui/issues/issue-75307.rs
@@ -0,0 +1,3 @@
+fn main() {
+    format!(r"{}{}{}", named_arg=1); //~ ERROR invalid reference to positional arguments 1 and 2
+}
diff --git a/src/test/ui/issues/issue-75307.stderr b/src/test/ui/issues/issue-75307.stderr
new file mode 100644
index 00000000000..4a5d997e00d
--- /dev/null
+++ b/src/test/ui/issues/issue-75307.stderr
@@ -0,0 +1,10 @@
+error: invalid reference to positional arguments 1 and 2 (there is 1 argument)
+  --> $DIR/issue-75307.rs:2:13
+   |
+LL |     format!(r"{}{}{}", named_arg=1);
+   |             ^^^^^^^^^
+   |
+   = note: positional arguments are zero-based
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/expr-as-stmt-2.rs b/src/test/ui/parser/expr-as-stmt-2.rs
new file mode 100644
index 00000000000..3a18bdc3b73
--- /dev/null
+++ b/src/test/ui/parser/expr-as-stmt-2.rs
@@ -0,0 +1,10 @@
+// This is not autofixable because we give extra suggestions to end the first expression with `;`.
+fn foo(a: Option<u32>, b: Option<u32>) -> bool {
+    if let Some(x) = a { true } else { false }
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    && //~ ERROR mismatched types
+    if let Some(y) = a { true } else { false }
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/expr-as-stmt-2.stderr b/src/test/ui/parser/expr-as-stmt-2.stderr
new file mode 100644
index 00000000000..ee07c367633
--- /dev/null
+++ b/src/test/ui/parser/expr-as-stmt-2.stderr
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:3:26
+   |
+LL |     if let Some(x) = a { true } else { false }
+   |     ---------------------^^^^------------------ help: consider using a semicolon here
+   |     |                    |
+   |     |                    expected `()`, found `bool`
+   |     expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:3:40
+   |
+LL |     if let Some(x) = a { true } else { false }
+   |     -----------------------------------^^^^^--- help: consider using a semicolon here
+   |     |                                  |
+   |     |                                  expected `()`, found `bool`
+   |     expected this to be `()`
+
+error[E0308]: mismatched types
+  --> $DIR/expr-as-stmt-2.rs:6:5
+   |
+LL |   fn foo(a: Option<u32>, b: Option<u32>) -> bool {
+   |                                             ---- expected `bool` because of return type
+LL |       if let Some(x) = a { true } else { false }
+   |       ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
+...
+LL | /     &&
+LL | |     if let Some(y) = a { true } else { false }
+   | |______________________________________________^ expected `bool`, found `&&bool`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/expr-as-stmt.fixed b/src/test/ui/parser/expr-as-stmt.fixed
index 1ce6f9c2503..02816ef2791 100644
--- a/src/test/ui/parser/expr-as-stmt.fixed
+++ b/src/test/ui/parser/expr-as-stmt.fixed
@@ -25,12 +25,6 @@ fn baz() -> i32 {
     //~^ ERROR mismatched types
 }
 
-fn qux(a: Option<u32>, b: Option<u32>) -> bool {
-    (if let Some(x) = a { true } else { false })
-    && //~ ERROR expected expression
-    if let Some(y) = a { true } else { false }
-}
-
 fn moo(x: u32) -> bool {
     (match x {
         _ => 1,
diff --git a/src/test/ui/parser/expr-as-stmt.rs b/src/test/ui/parser/expr-as-stmt.rs
index b526c17488e..93baa8278f8 100644
--- a/src/test/ui/parser/expr-as-stmt.rs
+++ b/src/test/ui/parser/expr-as-stmt.rs
@@ -25,12 +25,6 @@ fn baz() -> i32 {
     //~^ ERROR mismatched types
 }
 
-fn qux(a: Option<u32>, b: Option<u32>) -> bool {
-    if let Some(x) = a { true } else { false }
-    && //~ ERROR expected expression
-    if let Some(y) = a { true } else { false }
-}
-
 fn moo(x: u32) -> bool {
     match x {
         _ => 1,
diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr
index 4d93e130901..324aed0ad7c 100644
--- a/src/test/ui/parser/expr-as-stmt.stderr
+++ b/src/test/ui/parser/expr-as-stmt.stderr
@@ -22,16 +22,8 @@ LL |     { 42 } + foo;
    |     |
    |     help: parentheses are required to parse this as an expression: `({ 42 })`
 
-error: expected expression, found `&&`
-  --> $DIR/expr-as-stmt.rs:30:5
-   |
-LL |     if let Some(x) = a { true } else { false }
-   |     ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })`
-LL |     &&
-   |     ^^ expected expression
-
 error: expected expression, found `>`
-  --> $DIR/expr-as-stmt.rs:37:7
+  --> $DIR/expr-as-stmt.rs:31:7
    |
 LL |     } > 0
    |       ^ expected expression
@@ -75,7 +67,7 @@ LL |     { 3 } * 3
    |     |
    |     help: parentheses are required to parse this as an expression: `({ 3 })`
 
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0308, E0614.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/unknown-llvm-arg.rs b/src/test/ui/unknown-llvm-arg.rs
new file mode 100644
index 00000000000..289bae24f81
--- /dev/null
+++ b/src/test/ui/unknown-llvm-arg.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Cllvm-args=-not-a-real-llvm-arg
+// normalize-stderr-test "--help" -> "-help"
+// normalize-stderr-test "\n(\n|.)*" -> ""
+
+// I'm seeing "--help" locally, but "-help" in CI, so I'm normalizing it to just "-help".
+
+// Note that the rustc-supplied "program name", given when invoking LLVM, is used by LLVM to
+// generate user-facing error messages and a usage (--help) messages. If the program name is
+// `rustc`, the usage message in response to `--llvm-args="--help"` starts with:
+// ```
+//   USAGE: rustc [options]
+// ```
+// followed by the list of options not to `rustc` but to `llvm`.
+//
+// On the other hand, if the program name is set to `rustc -Cllvm-args="..." with`, the usage
+// message is more clear:
+// ```
+//   USAGE: rustc -Cllvm-args="..." with [options]
+// ```
+// This test captures the effect of the current program name setting on LLVM command line
+// error messages.
+fn main() {}
diff --git a/src/test/ui/unknown-llvm-arg.stderr b/src/test/ui/unknown-llvm-arg.stderr
new file mode 100644
index 00000000000..e1d3cfea28f
--- /dev/null
+++ b/src/test/ui/unknown-llvm-arg.stderr
@@ -0,0 +1 @@
+rustc -Cllvm-args="..." with: Unknown command line argument '-not-a-real-llvm-arg'.  Try: 'rustc -Cllvm-args="..." with -help'
\ No newline at end of file
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 5dede95a858..0a71361c992 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -447,6 +447,7 @@ impl Builder {
         let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets);
         package("rustc", HOSTS);
         package("rustc-dev", HOSTS);
+        package("rustc-docs", HOSTS);
         package("cargo", HOSTS);
         package("rust-mingw", MINGW);
         package("rust-std", TARGETS);
diff --git a/triagebot.toml b/triagebot.toml
index 8fe89095ae9..707e381b06e 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -99,94 +99,3 @@ message_on_add = """\
 - Needs `I-nominated`?
 """
 message_on_remove = "Issue #{number}'s prioritization request has been removed."
-
-[notify-zulip."I-nominated"]
-required_labels = ["T-compiler"]
-zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "I-nominated #{number} {title}"
-message_on_add = """\
-@*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.
-
-# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-i-nominated-issues)
-- Already discussed?
-- Worth the meeting time?
-- Add agenda entry:
-  - Why nominated?
-  - Assignee?
-  - Issue? PR? What's the status?
-  - Summary and important details?
-"""
-message_on_remove = "#{number}'s nomination has been removed."
-
-[notify-zulip."beta-nominated"]
-zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "Backport #{number} {title}"
-message_on_add = """\
-@*WG-prioritization/alerts* PR #{number} has been requested for beta backport.
-
-# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
-Prepare agenda entry:
-- Why nominated?
-- Author, assignee?
-- Important details?
-"""
-message_on_remove = "PR #{number}'s beta backport request has been removed."
-
-[notify-zulip."stable-nominated"]
-zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "Backport #{number} {title}"
-message_on_add = """\
-@*WG-prioritization/alerts* PR #{number} has been requested for stable backport.
-
-# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
-Prepare agenda entry:
-- Why nominated?
-- Author, assignee?
-- Important details?
-"""
-message_on_remove = "PR #{number}'s stable backport request has been removed."
-
-[notify-zulip."S-waiting-on-team"]
-required_labels = ["T-compiler"]
-zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "S-waiting-on-team #{number} {title}"
-message_on_add = """\
-@*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`.
-
-# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-prs-waiting-on-team)
-- Prepare agenda entry:
-  - What is it waiting for?
-  - Important details?
-- Could be resolved quickly? Tag `I-nominated`.
-"""
-message_on_remove = "PR #{number}'s is no longer waiting on `T-compiler`."
-
-[notify-zulip."P-critical"]
-zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "P-critical #{number} {title}"
-message_on_add = """\
-@*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`.
-
-# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
-- Notify people/groups?
-- Assign if possible?
-- Add to agenda:
-  - Assignee?
-  - Summary and important details?
-- Other actions to move forward?
-"""
-
-[notify-zulip."P-high"]
-required_labels = ["regression-from-stable-to-[bn]*"] # only nightly and beta regressions
-zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
-topic = "P-high regression #{number} {title}"
-message_on_add = """\
-@*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression.
-
-# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
-Is issue assigned? If not:
-- Try to find an assignee?
-- Otherwise add to agenda:
-  - Mark as unassigned.
-  - Summary and important details?
-"""