about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-03-26 11:03:12 +0000
committerbors <bors@rust-lang.org>2025-03-26 11:03:12 +0000
commitf1bc669636023c8643602431791c7f26e5a6edef (patch)
tree033f8e552ddabe2b4916b542a428d2e1f1995c4a
parent65899c06f117ddac9c8399479ddcdc122c92fddf (diff)
parent46a40be2d2e301d9db4f09f098a922c62feb7f04 (diff)
downloadrust-f1bc669636023c8643602431791c7f26e5a6edef.tar.gz
rust-f1bc669636023c8643602431791c7f26e5a6edef.zip
Auto merge of #138974 - Zalathar:rollup-568cpmy, r=Zalathar
Rollup of 7 pull requests

Successful merges:

 - #138483 (Target modifiers fix for bool flags without value)
 - #138818 (Don't produce debug information for compiler-introduced-vars when desugaring assignments.)
 - #138898 (Mostly parser: Eliminate code that's been dead / semi-dead since the removal of type ascription syntax)
 - #138930 (Add bootstrap step diff to CI job analysis)
 - #138954 (Ensure `define_opaque` attrs are accounted for in HIR hash)
 - #138959 (Revert "Make MatchPairTree::place non-optional")
 - #138967 (Fix typo in error message)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast/src/ast.rs8
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs2
-rw-r--r--compiler/rustc_ast/src/visit.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/autodiff.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs1
-rw-r--r--compiler/rustc_expand/src/build.rs1
-rw-r--r--compiler/rustc_metadata/messages.ftl17
-rw-r--r--compiler/rustc_metadata/src/creader.rs69
-rw-r--r--compiler/rustc_metadata/src/errors.rs36
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/context.rs3
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/match_pair.rs3
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs70
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/test.rs9
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/util.rs8
-rw-r--r--compiler/rustc_parse/messages.ftl4
-rw-r--r--compiler/rustc_parse/src/errors.rs18
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs57
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs16
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs19
-rw-r--r--compiler/rustc_resolve/src/late.rs13
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs14
-rw-r--r--compiler/rustc_session/src/options.rs52
-rw-r--r--library/std/src/sys/net/connection/xous/tcpstream.rs2
-rw-r--r--src/build_helper/src/metrics.rs61
-rw-r--r--src/ci/citool/Cargo.lock7
-rw-r--r--src/ci/citool/Cargo.toml1
-rw-r--r--src/ci/citool/src/analysis.rs114
-rw-r--r--src/ci/citool/src/main.rs46
-rw-r--r--src/tools/rustfmt/src/closures.rs1
-rw-r--r--src/tools/rustfmt/src/macros.rs1
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--tests/codegen/assign-desugar-debuginfo.rs18
-rw-r--r--tests/incremental/define-opaques.rs19
-rw-r--r--tests/ui-fulldeps/pprust-expr-roundtrip.rs1
-rw-r--r--tests/ui/closures/upvar-or-pattern-issue-138958.rs11
-rw-r--r--tests/ui/parser/issues/issue-111692.rs32
-rw-r--r--tests/ui/parser/issues/issue-111692.stderr46
-rw-r--r--tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs13
-rw-r--r--tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr13
-rw-r--r--tests/ui/parser/struct-literal-in-for.rs17
-rw-r--r--tests/ui/parser/struct-literal-in-for.stderr31
-rw-r--r--tests/ui/parser/struct-literal-in-if.rs22
-rw-r--r--tests/ui/parser/struct-literal-in-if.stderr34
-rw-r--r--tests/ui/parser/struct-literal-in-match-discriminant.rs13
-rw-r--r--tests/ui/parser/struct-literal-in-match-discriminant.stderr18
-rw-r--r--tests/ui/parser/struct-literal-in-while.rs22
-rw-r--r--tests/ui/parser/struct-literal-in-while.stderr34
-rw-r--r--tests/ui/parser/struct-literal-restrictions-in-lamda.rs17
-rw-r--r--tests/ui/parser/struct-literal-restrictions-in-lamda.stderr37
-rw-r--r--tests/ui/parser/struct-literal-variant-in-if.rs25
-rw-r--r--tests/ui/parser/struct-literal-variant-in-if.stderr76
-rw-r--r--tests/ui/parser/struct-literals-in-invalid-places.rs92
-rw-r--r--tests/ui/parser/struct-literals-in-invalid-places.stderr234
-rw-r--r--tests/ui/parser/type-ascription-in-pattern.rs9
-rw-r--r--tests/ui/parser/type-ascription-in-pattern.stderr80
-rw-r--r--tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs7
-rw-r--r--tests/ui/target_modifiers/defaults_check.error.stderr4
-rw-r--r--tests/ui/target_modifiers/no_value_bool.error.stderr13
-rw-r--r--tests/ui/target_modifiers/no_value_bool.error_explicit.stderr13
-rw-r--r--tests/ui/target_modifiers/no_value_bool.rs22
63 files changed, 896 insertions, 745 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fd27be21326..064f05ef1f3 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -545,14 +545,6 @@ pub struct Block {
     pub rules: BlockCheckMode,
     pub span: Span,
     pub tokens: Option<LazyAttrTokenStream>,
-    /// The following *isn't* a parse error, but will cause multiple errors in following stages.
-    /// ```compile_fail
-    /// let x = {
-    ///     foo: var
-    /// };
-    /// ```
-    /// #34255
-    pub could_be_bare_literal: bool,
 }
 
 /// A match pattern.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 474d38fceef..274fe312f7f 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1222,7 +1222,7 @@ fn walk_mt<T: MutVisitor>(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) {
 }
 
 pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
-    let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut();
+    let Block { id, stmts, rules: _, span, tokens } = block.deref_mut();
     vis.visit_id(id);
     stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
     visit_lazy_tts(vis, tokens);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index dcf1d00910a..2716601ca4f 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -1067,7 +1067,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef)
 }
 
 pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::Result {
-    let Block { stmts, id: _, rules: _, span: _, tokens: _, could_be_bare_literal: _ } = block;
+    let Block { stmts, id: _, rules: _, span: _, tokens: _ } = block;
     walk_list!(visitor, visit_stmt, stmts);
     V::Result::output()
 }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index c9f27d38dfc..ced9064fd9f 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -623,7 +623,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // Don't hash unless necessary, because it's expensive.
         let (opt_hash_including_bodies, attrs_hash) =
-            self.tcx.hash_owner_nodes(node, &bodies, &attrs);
+            self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
         let num_nodes = self.item_local_id_counter.as_usize();
         let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
         let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 5cd653c7945..be11711757e 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -395,7 +395,6 @@ mod llvm_enzyme {
             tokens: None,
             rules: unsf,
             span,
-            could_be_bare_literal: false,
         };
         let unsf_expr = ecx.expr_block(P(unsf_block));
         let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path));
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index c112589b131..50e7b989ed8 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -110,7 +110,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
         rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
         span,
         tokens: None,
-        could_be_bare_literal: false,
     }))
 }
 
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 2c9b5f40d0d..89a750bb39f 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -286,7 +286,6 @@ impl<'a> ExtCtxt<'a> {
             rules: BlockCheckMode::Default,
             span,
             tokens: None,
-            could_be_bare_literal: false,
         })
     }
 
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 20f66fae5c0..9adbcabcf45 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -118,12 +118,23 @@ metadata_incompatible_rustc =
 
 metadata_incompatible_target_modifiers =
     mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
-    .note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}`
+    .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}`
     .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
-
 metadata_incompatible_target_modifiers_help_allow = if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error
-metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$flag_extern_value}` in this crate or `{$flag_name_prefixed}={$flag_local_value}` in `{$extern_crate}`
+metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$extern_value}` in this crate or `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}`
+
+metadata_incompatible_target_modifiers_help_fix_l_missed = set `{$flag_name_prefixed}={$extern_value}` in this crate or unset `{$flag_name_prefixed}` in `{$extern_crate}`
 
+metadata_incompatible_target_modifiers_help_fix_r_missed = unset `{$flag_name_prefixed}` in this crate or set `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}`
+
+metadata_incompatible_target_modifiers_l_missed =
+    mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
+    .note = unset `{$flag_name_prefixed}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}`
+    .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+metadata_incompatible_target_modifiers_r_missed =
+    mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
+    .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}`
+    .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
 metadata_incompatible_wasm_link =
     `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 12503ffd1a6..b7f13e0afdc 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -358,30 +358,58 @@ impl CStore {
     ) {
         let span = krate.spans.inner_span.shrink_to_lo();
         let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
-        let name = tcx.crate_name(LOCAL_CRATE);
+        let local_crate = tcx.crate_name(LOCAL_CRATE);
         let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
         let report_diff = |prefix: &String,
                            opt_name: &String,
-                           flag_local_value: &String,
-                           flag_extern_value: &String| {
+                           flag_local_value: Option<&String>,
+                           flag_extern_value: Option<&String>| {
             if allowed_flag_mismatches.contains(&opt_name) {
                 return;
             }
-            tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
-                span,
-                extern_crate: data.name(),
-                local_crate: name,
-                flag_name: opt_name.clone(),
-                flag_name_prefixed: format!("-{}{}", prefix, opt_name),
-                flag_local_value: flag_local_value.to_string(),
-                flag_extern_value: flag_extern_value.to_string(),
-            });
+            let extern_crate = data.name();
+            let flag_name = opt_name.clone();
+            let flag_name_prefixed = format!("-{}{}", prefix, opt_name);
+
+            match (flag_local_value, flag_extern_value) {
+                (Some(local_value), Some(extern_value)) => {
+                    tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
+                        span,
+                        extern_crate,
+                        local_crate,
+                        flag_name,
+                        flag_name_prefixed,
+                        local_value: local_value.to_string(),
+                        extern_value: extern_value.to_string(),
+                    })
+                }
+                (None, Some(extern_value)) => {
+                    tcx.dcx().emit_err(errors::IncompatibleTargetModifiersLMissed {
+                        span,
+                        extern_crate,
+                        local_crate,
+                        flag_name,
+                        flag_name_prefixed,
+                        extern_value: extern_value.to_string(),
+                    })
+                }
+                (Some(local_value), None) => {
+                    tcx.dcx().emit_err(errors::IncompatibleTargetModifiersRMissed {
+                        span,
+                        extern_crate,
+                        local_crate,
+                        flag_name,
+                        flag_name_prefixed,
+                        local_value: local_value.to_string(),
+                    })
+                }
+                (None, None) => panic!("Incorrect target modifiers report_diff(None, None)"),
+            };
         };
         let mut it1 = mods.iter().map(tmod_extender);
         let mut it2 = dep_mods.iter().map(tmod_extender);
         let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
         let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
-        let no_val = "*".to_string();
         loop {
             left_name_val = left_name_val.or_else(|| it1.next());
             right_name_val = right_name_val.or_else(|| it2.next());
@@ -389,26 +417,31 @@ impl CStore {
                 (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
                     cmp::Ordering::Equal => {
                         if l.0.tech_value != r.0.tech_value {
-                            report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name);
+                            report_diff(
+                                &l.0.prefix,
+                                &l.0.name,
+                                Some(&l.1.value_name),
+                                Some(&r.1.value_name),
+                            );
                         }
                         left_name_val = None;
                         right_name_val = None;
                     }
                     cmp::Ordering::Greater => {
-                        report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
+                        report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
                         right_name_val = None;
                     }
                     cmp::Ordering::Less => {
-                        report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
+                        report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
                         left_name_val = None;
                     }
                 },
                 (Some(l), None) => {
-                    report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
+                    report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
                     left_name_val = None;
                 }
                 (None, Some(r)) => {
-                    report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
+                    report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
                     right_name_val = None;
                 }
                 (None, None) => break,
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 2ad6389c0b4..0c54628598c 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -759,8 +759,40 @@ pub struct IncompatibleTargetModifiers {
     pub local_crate: Symbol,
     pub flag_name: String,
     pub flag_name_prefixed: String,
-    pub flag_local_value: String,
-    pub flag_extern_value: String,
+    pub local_value: String,
+    pub extern_value: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_target_modifiers_l_missed)]
+#[help]
+#[note]
+#[help(metadata_incompatible_target_modifiers_help_fix_l_missed)]
+#[help(metadata_incompatible_target_modifiers_help_allow)]
+pub struct IncompatibleTargetModifiersLMissed {
+    #[primary_span]
+    pub span: Span,
+    pub extern_crate: Symbol,
+    pub local_crate: Symbol,
+    pub flag_name: String,
+    pub flag_name_prefixed: String,
+    pub extern_value: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_target_modifiers_r_missed)]
+#[help]
+#[note]
+#[help(metadata_incompatible_target_modifiers_help_fix_r_missed)]
+#[help(metadata_incompatible_target_modifiers_help_allow)]
+pub struct IncompatibleTargetModifiersRMissed {
+    #[primary_span]
+    pub span: Span,
+    pub extern_crate: Symbol,
+    pub local_crate: Symbol,
+    pub flag_name: String,
+    pub flag_name_prefixed: String,
+    pub local_value: String,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 68b9a4f56b9..347bc5ea312 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -14,7 +14,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::*;
 use rustc_macros::{Decodable, Encodable, HashStable};
-use rustc_span::{ErrorGuaranteed, ExpnId};
+use rustc_span::{ErrorGuaranteed, ExpnId, Span};
 
 use crate::query::Providers;
 use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
@@ -157,6 +157,7 @@ impl<'tcx> TyCtxt<'tcx> {
         node: OwnerNode<'_>,
         bodies: &SortedMap<ItemLocalId, &Body<'_>>,
         attrs: &SortedMap<ItemLocalId, &[Attribute]>,
+        define_opaque: Option<&[(Span, LocalDefId)]>,
     ) -> (Option<Fingerprint>, Option<Fingerprint>) {
         if self.needs_crate_hash() {
             self.with_stable_hashing_context(|mut hcx| {
@@ -168,6 +169,10 @@ impl<'tcx> TyCtxt<'tcx> {
 
                 let mut stable_hasher = StableHasher::new();
                 attrs.hash_stable(&mut hcx, &mut stable_hasher);
+
+                // Hash the defined opaque types, which are not present in the attrs.
+                define_opaque.hash_stable(&mut hcx, &mut stable_hasher);
+
                 let h2 = stable_hasher.finish();
                 (Some(h1), Some(h2))
             })
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f54dd2b0040..834d1f2a4a8 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1288,7 +1288,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
         let bodies = Default::default();
         let attrs = hir::AttributeMap::EMPTY;
 
-        let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map);
+        let (opt_hash_including_bodies, _) =
+            self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, attrs.define_opaque);
         let node = node.into();
         self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes {
             opt_hash_including_bodies,
diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
index f2ce0c46dd3..29d400a957b 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -115,7 +115,6 @@ impl<'tcx> MatchPairTree<'tcx> {
             place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
         }
 
-        // Place can be none if the pattern refers to a non-captured place in a closure.
         let place = place_builder.try_to_place(cx);
         let mut subpairs = Vec::new();
         let test_case = match pattern.kind {
@@ -321,7 +320,7 @@ impl<'tcx> MatchPairTree<'tcx> {
         if let Some(test_case) = test_case {
             // This pattern is refutable, so push a new match-pair node.
             match_pairs.push(MatchPairTree {
-                place: place.expect("refutable patterns should always have a place to inspect"),
+                place,
                 test_case,
                 subpairs,
                 pattern_ty: pattern.ty,
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index 710538ef4b8..3acf2a6a2a6 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -13,13 +13,13 @@ use std::sync::Arc;
 use rustc_abi::VariantIdx;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_hir::{BindingMode, ByRef};
+use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node};
 use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::mir::{self, *};
 use rustc_middle::thir::{self, *};
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
-use rustc_span::{BytePos, Pos, Span, Symbol};
+use rustc_span::{BytePos, Pos, Span, Symbol, sym};
 use tracing::{debug, instrument};
 
 use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard};
@@ -1279,7 +1279,13 @@ impl<'tcx> TestCase<'tcx> {
 #[derive(Debug, Clone)]
 pub(crate) struct MatchPairTree<'tcx> {
     /// This place...
-    place: Place<'tcx>,
+    ///
+    /// ---
+    /// This can be `None` if it referred to a non-captured place in a closure.
+    ///
+    /// Invariant: Can only be `None` when `test_case` is `Or`.
+    /// Therefore this must be `Some(_)` after or-pattern expansion.
+    place: Option<Place<'tcx>>,
 
     /// ... must pass this test...
     test_case: TestCase<'tcx>,
@@ -2099,9 +2105,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // Extract the match-pair from the highest priority candidate
         let match_pair = &candidates[0].match_pairs[0];
         let test = self.pick_test_for_match_pair(match_pair);
+        // Unwrap is ok after simplification.
+        let match_place = match_pair.place.unwrap();
         debug!(?test, ?match_pair);
 
-        (match_pair.place, test)
+        (match_place, test)
     }
 
     /// Given a test, we partition the input candidates into several buckets.
@@ -2796,13 +2804,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             )))),
         };
         let for_arm_body = self.local_decls.push(local);
-        self.var_debug_info.push(VarDebugInfo {
-            name,
-            source_info: debug_source_info,
-            value: VarDebugInfoContents::Place(for_arm_body.into()),
-            composite: None,
-            argument_index: None,
-        });
+        if self.should_emit_debug_info_for_binding(name, var_id) {
+            self.var_debug_info.push(VarDebugInfo {
+                name,
+                source_info: debug_source_info,
+                value: VarDebugInfoContents::Place(for_arm_body.into()),
+                composite: None,
+                argument_index: None,
+            });
+        }
         let locals = if has_guard.0 {
             let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
                 // This variable isn't mutated but has a name, so has to be
@@ -2815,13 +2825,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     BindingForm::RefForGuard,
                 ))),
             });
-            self.var_debug_info.push(VarDebugInfo {
-                name,
-                source_info: debug_source_info,
-                value: VarDebugInfoContents::Place(ref_for_guard.into()),
-                composite: None,
-                argument_index: None,
-            });
+            if self.should_emit_debug_info_for_binding(name, var_id) {
+                self.var_debug_info.push(VarDebugInfo {
+                    name,
+                    source_info: debug_source_info,
+                    value: VarDebugInfoContents::Place(ref_for_guard.into()),
+                    composite: None,
+                    argument_index: None,
+                });
+            }
             LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
         } else {
             LocalsForNode::One(for_arm_body)
@@ -2829,4 +2841,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         debug!(?locals);
         self.var_indices.insert(var_id, locals);
     }
+
+    /// Some bindings are introduced when producing HIR from the AST and don't
+    /// actually exist in the source. Skip producing debug info for those when
+    /// we can recognize them.
+    fn should_emit_debug_info_for_binding(&self, name: Symbol, var_id: LocalVarId) -> bool {
+        // For now we only recognize the output of desugaring assigns.
+        if name != sym::lhs {
+            return true;
+        }
+
+        let tcx = self.tcx;
+        for (_, node) in tcx.hir_parent_iter(var_id.0) {
+            // FIXME(khuey) at what point is it safe to bail on the iterator?
+            // Can we stop at the first non-Pat node?
+            if matches!(node, Node::LetStmt(&LetStmt { source: LocalSource::AssignDesugar(_), .. }))
+            {
+                return false;
+            }
+        }
+
+        true
+    }
 }
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index 7ef9e48326f..d1f9d4c34fe 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -470,8 +470,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // than one, but it'd be very unusual to have two sides that
         // both require tests; you'd expect one side to be simplified
         // away.)
-        let (match_pair_index, match_pair) =
-            candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == test_place)?;
+        let (match_pair_index, match_pair) = candidate
+            .match_pairs
+            .iter()
+            .enumerate()
+            .find(|&(_, mp)| mp.place == Some(test_place))?;
 
         // If true, the match pair is completely entailed by its corresponding test
         // branch, so it can be removed. If false, the match pair is _compatible_
@@ -514,7 +517,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     candidate
                         .match_pairs
                         .iter()
-                        .any(|mp| mp.place == test_place && is_covering_range(&mp.test_case))
+                        .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case))
                 };
                 if sorted_candidates
                     .get(&TestBranch::Failure)
diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs
index ed3b652e4ef..589e350a03f 100644
--- a/compiler/rustc_mir_build/src/builder/matches/util.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/util.rs
@@ -173,10 +173,14 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
             // }
             // ```
             // Hence we fake borrow using a deep borrow.
-            self.fake_borrow(match_pair.place, FakeBorrowKind::Deep);
+            if let Some(place) = match_pair.place {
+                self.fake_borrow(place, FakeBorrowKind::Deep);
+            }
         } else {
             // Insert a Shallow borrow of any place that is switched on.
-            self.fake_borrow(match_pair.place, FakeBorrowKind::Shallow);
+            if let Some(place) = match_pair.place {
+                self.fake_borrow(place, FakeBorrowKind::Shallow);
+            }
 
             for subpair in &match_pair.subpairs {
                 self.visit_match_pair(subpair);
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 6d4308cda1a..3253222b8f2 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -757,10 +757,6 @@ parse_struct_literal_body_without_path =
     struct literal body without path
     .suggestion = you might have forgotten to add the struct literal inside the block
 
-parse_struct_literal_needing_parens =
-    invalid struct literal
-    .suggestion = you might need to surround the struct literal with parentheses
-
 parse_struct_literal_not_allowed_here = struct literals are not allowed here
     .suggestion = surround the struct literal with parentheses
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index e090d9cf760..f813c3380fc 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1273,24 +1273,6 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_struct_literal_needing_parens)]
-pub(crate) struct StructLiteralNeedingParens {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub sugg: StructLiteralNeedingParensSugg,
-}
-
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
-pub(crate) struct StructLiteralNeedingParensSugg {
-    #[suggestion_part(code = "(")]
-    pub before: Span,
-    #[suggestion_part(code = ")")]
-    pub after: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(parse_unmatched_angle_brackets)]
 pub(crate) struct UnmatchedAngleBrackets {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index c1cca1186af..ef044fe9d63 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -40,9 +40,8 @@ use crate::errors::{
     HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
     IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
     QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
-    StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
-    SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
-    UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
+    StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
+    TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
     UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
 };
 use crate::parser::attr::InnerAttrPolicy;
@@ -949,7 +948,6 @@ impl<'a> Parser<'a> {
         lo: Span,
         s: BlockCheckMode,
         maybe_struct_name: token::Token,
-        can_be_struct_literal: bool,
     ) -> Option<PResult<'a, P<Block>>> {
         if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
             // We might be having a struct literal where people forgot to include the path:
@@ -975,47 +973,23 @@ impl<'a> Parser<'a> {
                     // fn foo() -> Foo { Path {
                     //     field: value,
                     // } }
-                    let guar = err.delay_as_bug();
+                    err.cancel();
                     self.restore_snapshot(snapshot);
-                    let mut tail = self.mk_block(
+                    let guar = self.dcx().emit_err(StructLiteralBodyWithoutPath {
+                        span: expr.span,
+                        sugg: StructLiteralBodyWithoutPathSugg {
+                            before: expr.span.shrink_to_lo(),
+                            after: expr.span.shrink_to_hi(),
+                        },
+                    });
+                    Ok(self.mk_block(
                         thin_vec![self.mk_stmt_err(expr.span, guar)],
                         s,
                         lo.to(self.prev_token.span),
-                    );
-                    tail.could_be_bare_literal = true;
-                    if maybe_struct_name.is_ident() && can_be_struct_literal {
-                        // Account for `if Example { a: one(), }.is_pos() {}`.
-                        // expand `before` so that we take care of module path such as:
-                        // `foo::Bar { ... } `
-                        // we expect to suggest `(foo::Bar { ... })` instead of `foo::(Bar { ... })`
-                        let sm = self.psess.source_map();
-                        let before = maybe_struct_name.span.shrink_to_lo();
-                        if let Ok(extend_before) = sm.span_extend_prev_while(before, |t| {
-                            t.is_alphanumeric() || t == ':' || t == '_'
-                        }) {
-                            Err(self.dcx().create_err(StructLiteralNeedingParens {
-                                span: maybe_struct_name.span.to(expr.span),
-                                sugg: StructLiteralNeedingParensSugg {
-                                    before: extend_before.shrink_to_lo(),
-                                    after: expr.span.shrink_to_hi(),
-                                },
-                            }))
-                        } else {
-                            return None;
-                        }
-                    } else {
-                        self.dcx().emit_err(StructLiteralBodyWithoutPath {
-                            span: expr.span,
-                            sugg: StructLiteralBodyWithoutPathSugg {
-                                before: expr.span.shrink_to_lo(),
-                                after: expr.span.shrink_to_hi(),
-                            },
-                        });
-                        Ok(tail)
-                    }
+                    ))
                 }
                 (Err(err), Ok(tail)) => {
-                    // We have a block tail that contains a somehow valid type ascription expr.
+                    // We have a block tail that contains a somehow valid expr.
                     err.cancel();
                     Ok(tail)
                 }
@@ -1025,10 +999,7 @@ impl<'a> Parser<'a> {
                     self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
                     Err(err)
                 }
-                (Ok(_), Ok(mut tail)) => {
-                    tail.could_be_bare_literal = true;
-                    Ok(tail)
-                }
+                (Ok(_), Ok(tail)) => Ok(tail),
             });
         }
         None
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index c48f91643e8..92e83577f1b 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2296,7 +2296,7 @@ impl<'a> Parser<'a> {
             });
         }
 
-        let (attrs, blk) = self.parse_block_common(lo, blk_mode, true, None)?;
+        let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
         Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
     }
 
@@ -3474,19 +3474,9 @@ impl<'a> Parser<'a> {
     }
 
     fn is_certainly_not_a_block(&self) -> bool {
+        // `{ ident, ` and `{ ident: ` cannot start a block.
         self.look_ahead(1, |t| t.is_ident())
-            && (
-                // `{ ident, ` cannot start a block.
-                self.look_ahead(2, |t| t == &token::Comma)
-                    || self.look_ahead(2, |t| t == &token::Colon)
-                        && (
-                            // `{ ident: token, ` cannot start a block.
-                            self.look_ahead(4, |t| t == &token::Comma)
-                                // `{ ident: ` cannot start a block unless it's a type ascription
-                                // `ident: Type`.
-                                || self.look_ahead(3, |t| !t.can_begin_type())
-                        )
-            )
+            && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
     }
 
     fn maybe_parse_struct_expr(
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c32a79f6909..aad18578375 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2538,7 +2538,7 @@ impl<'a> Parser<'a> {
             *sig_hi = self.prev_token.span;
             (AttrVec::new(), None)
         } else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() {
-            self.parse_block_common(self.token.span, BlockCheckMode::Default, false, None)
+            self.parse_block_common(self.token.span, BlockCheckMode::Default, None)
                 .map(|(attrs, body)| (attrs, Some(body)))?
         } else if self.token == token::Eq {
             // Recover `fn foo() = $expr;`.
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 0fe247078d5..97cd4d2117f 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -668,7 +668,7 @@ impl<'a> Parser<'a> {
         &mut self,
         loop_header: Option<Span>,
     ) -> PResult<'a, (AttrVec, P<Block>)> {
-        self.parse_block_common(self.token.span, BlockCheckMode::Default, true, loop_header)
+        self.parse_block_common(self.token.span, BlockCheckMode::Default, loop_header)
     }
 
     /// Parses a block. Inner attributes are allowed, block labels are not.
@@ -679,7 +679,6 @@ impl<'a> Parser<'a> {
         &mut self,
         lo: Span,
         blk_mode: BlockCheckMode,
-        can_be_struct_literal: bool,
         loop_header: Option<Span>,
     ) -> PResult<'a, (AttrVec, P<Block>)> {
         maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block));
@@ -691,12 +690,7 @@ impl<'a> Parser<'a> {
         }
 
         let attrs = self.parse_inner_attributes()?;
-        let tail = match self.maybe_suggest_struct_literal(
-            lo,
-            blk_mode,
-            maybe_ident,
-            can_be_struct_literal,
-        ) {
+        let tail = match self.maybe_suggest_struct_literal(lo, blk_mode, maybe_ident) {
             Some(tail) => tail?,
             None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?,
         };
@@ -1043,14 +1037,7 @@ impl<'a> Parser<'a> {
         rules: BlockCheckMode,
         span: Span,
     ) -> P<Block> {
-        P(Block {
-            stmts,
-            id: DUMMY_NODE_ID,
-            rules,
-            span,
-            tokens: None,
-            could_be_bare_literal: false,
-        })
+        P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None })
     }
 
     pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 11d07407aa1..6bc644e9e11 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -675,11 +675,6 @@ struct DiagMetadata<'ast> {
     /// they are used (in a `break` or `continue` statement)
     unused_labels: FxIndexMap<NodeId, Span>,
 
-    /// Only used for better errors on `let x = { foo: bar };`.
-    /// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only
-    /// needed for cases where this parses as a correct type ascription.
-    current_block_could_be_bare_struct_literal: Option<Span>,
-
     /// Only used for better errors on `let <pat>: <expr, not type>;`.
     current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
 
@@ -4661,13 +4656,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             self.ribs[ValueNS].push(Rib::new(RibKind::Normal));
         }
 
-        let prev = self.diag_metadata.current_block_could_be_bare_struct_literal.take();
-        if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) =
-            (block.could_be_bare_literal, &block.stmts[..])
-            && let ExprKind::Type(..) = expr.kind
-        {
-            self.diag_metadata.current_block_could_be_bare_struct_literal = Some(block.span);
-        }
         // Descend into the block.
         for stmt in &block.stmts {
             if let StmtKind::Item(ref item) = stmt.kind
@@ -4681,7 +4669,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
 
             self.visit_stmt(stmt);
         }
-        self.diag_metadata.current_block_could_be_bare_struct_literal = prev;
 
         // Move back up.
         self.parent_scope.module = orig_module;
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 75232e0de00..cf8db2267f4 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -450,7 +450,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
         }
 
-        self.suggest_bare_struct_literal(&mut err);
         self.suggest_changing_type_to_const_param(&mut err, res, source, span);
         self.explain_functions_in_pattern(&mut err, res, source);
 
@@ -1279,19 +1278,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         }
     }
 
-    fn suggest_bare_struct_literal(&mut self, err: &mut Diag<'_>) {
-        if let Some(span) = self.diag_metadata.current_block_could_be_bare_struct_literal {
-            err.multipart_suggestion(
-                "you might have meant to write a `struct` literal",
-                vec![
-                    (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
-                    (span.shrink_to_hi(), "}".to_string()),
-                ],
-                Applicability::HasPlaceholders,
-            );
-        }
-    }
-
     fn explain_functions_in_pattern(
         &mut self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 03475058ce8..4cc666b3e37 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -94,45 +94,49 @@ fn tmod_push_impl(
     tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
     tmods: &mut Vec<TargetModifier>,
 ) {
-    tmods.push(TargetModifier { opt, value_name: tmod_vals.get(&opt).cloned().unwrap_or_default() })
+    if let Some(v) = tmod_vals.get(&opt) {
+        tmods.push(TargetModifier { opt, value_name: v.clone() })
+    }
 }
 
 macro_rules! tmod_push {
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $mods:expr, $tmod_vals:expr) => {
-        tmod_push_impl(
-            OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name),
-            $tmod_vals,
-            $mods,
-        );
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr) => {
+        if *$opt_expr != $init {
+            tmod_push_impl(
+                OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name),
+                $tmod_vals,
+                $mods,
+            );
+        }
     };
 }
 
 macro_rules! gather_tmods {
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [SUBSTRUCT], [TARGET_MODIFIER]) => {
         compile_error!("SUBSTRUCT can't be target modifier");
     };
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [UNTRACKED], [TARGET_MODIFIER]) => {
-        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
+        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
     };
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [TRACKED], [TARGET_MODIFIER]) => {
-        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
+        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
     };
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => {
-        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
+        tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
     };
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [SUBSTRUCT], []) => {
         $opt_expr.gather_target_modifiers($mods, $tmod_vals);
     };
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [UNTRACKED], []) => {{}};
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [TRACKED], []) => {{}};
-    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
+    ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
         [TRACKED_NO_CRATE_HASH], []) => {{}};
 }
 
@@ -474,7 +478,8 @@ macro_rules! tmod_enum {
                 $($pout)*
                 Self::$opt => {
                     let mut parsed : $t = Default::default();
-                    parse::$parse(&mut parsed, Some($puser_value));
+                    let val = if $puser_value.is_empty() { None } else { Some($puser_value) };
+                    parse::$parse(&mut parsed, val);
                     ExtendedTargetModifierInfo {
                         prefix: $prefix.to_string(),
                         name: stringify!($opt).to_string().replace('_', "-"),
@@ -569,7 +574,7 @@ macro_rules! options {
             _tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
         ) {
             $({
-                gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, _mods, _tmod_vals,
+                gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, $init, _mods, _tmod_vals,
                     [$dep_tracking_marker], [$($tmod),*]);
             })*
         }
@@ -681,10 +686,9 @@ fn build_options<O: Default>(
                         ),
                     }
                 }
-                if let Some(tmod) = *tmod
-                    && let Some(value) = value
-                {
-                    target_modifiers.insert(tmod, value.to_string());
+                if let Some(tmod) = *tmod {
+                    let v = value.map_or(String::new(), ToOwned::to_owned);
+                    target_modifiers.insert(tmod, v);
                 }
             }
             None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")),
diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs
index 283b1fe9a33..e8aea8b706a 100644
--- a/library/std/src/sys/net/connection/xous/tcpstream.rs
+++ b/library/std/src/sys/net/connection/xous/tcpstream.rs
@@ -324,7 +324,7 @@ impl TcpStream {
                 }
                 Ok(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.local_port, 0, 0)))
             }
-            _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "tnternal error")),
+            _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "internal error")),
         }
     }
 
diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs
index b6daac32a44..fdff9cd18ce 100644
--- a/src/build_helper/src/metrics.rs
+++ b/src/build_helper/src/metrics.rs
@@ -109,6 +109,8 @@ pub struct BuildStep {
     pub r#type: String,
     pub children: Vec<BuildStep>,
     pub duration: Duration,
+    // Full name of the step, including all parent names
+    pub full_name: String,
 }
 
 impl BuildStep {
@@ -116,7 +118,7 @@ impl BuildStep {
     /// The most important thing is that the build step aggregates the
     /// durations of all children, so that it can be easily accessed.
     pub fn from_invocation(invocation: &JsonInvocation) -> Self {
-        fn parse(node: &JsonNode) -> Option<BuildStep> {
+        fn parse(node: &JsonNode, parent_name: &str) -> Option<BuildStep> {
             match node {
                 JsonNode::RustbuildStep {
                     type_: kind,
@@ -124,11 +126,14 @@ impl BuildStep {
                     duration_excluding_children_sec,
                     ..
                 } => {
-                    let children: Vec<_> = children.into_iter().filter_map(parse).collect();
+                    let full_name = format!("{parent_name}-{kind}");
+                    let children: Vec<_> =
+                        children.into_iter().filter_map(|s| parse(s, &full_name)).collect();
                     let children_duration = children.iter().map(|c| c.duration).sum::<Duration>();
                     Some(BuildStep {
                         r#type: kind.to_string(),
                         children,
+                        full_name,
                         duration: children_duration
                             + Duration::from_secs_f64(*duration_excluding_children_sec),
                     })
@@ -138,8 +143,13 @@ impl BuildStep {
         }
 
         let duration = Duration::from_secs_f64(invocation.duration_including_children_sec);
-        let children: Vec<_> = invocation.children.iter().filter_map(parse).collect();
-        Self { r#type: "total".to_string(), children, duration }
+
+        // The root "total" step is kind of a virtual step that encompasses all other steps,
+        // but it is not a real parent of the other steps.
+        // We thus start the parent name hierarchy here and use an empty string
+        // as the parent name of the top-level steps.
+        let children: Vec<_> = invocation.children.iter().filter_map(|s| parse(s, "")).collect();
+        Self { r#type: "total".to_string(), children, duration, full_name: "total".to_string() }
     }
 
     pub fn find_all_by_type(&self, r#type: &str) -> Vec<&Self> {
@@ -156,33 +166,38 @@ impl BuildStep {
             child.find_by_type(r#type, result);
         }
     }
-}
 
-/// Writes build steps into a nice indented table.
-pub fn format_build_steps(root: &BuildStep) -> String {
-    use std::fmt::Write;
-
-    let mut substeps: Vec<(u32, &BuildStep)> = Vec::new();
+    /// Returns a Vec with all substeps, ordered by their hierarchical order.
+    /// The first element of the tuple is the depth of a given step.
+    pub fn linearize_steps(&self) -> Vec<(u32, &BuildStep)> {
+        let mut substeps: Vec<(u32, &BuildStep)> = Vec::new();
 
-    fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) {
-        substeps.push((level, step));
-        for child in &step.children {
-            visit(child, level + 1, substeps);
+        fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) {
+            substeps.push((level, step));
+            for child in &step.children {
+                visit(child, level + 1, substeps);
+            }
         }
+
+        visit(self, 0, &mut substeps);
+        substeps
     }
+}
 
-    visit(root, 0, &mut substeps);
+/// Writes build steps into a nice indented table.
+pub fn format_build_steps(root: &BuildStep) -> String {
+    use std::fmt::Write;
 
     let mut output = String::new();
-    for (level, step) in substeps {
-        let label = format!(
-            "{}{}",
-            ".".repeat(level as usize),
-            // Bootstrap steps can be generic and thus contain angle brackets (<...>).
-            // However, Markdown interprets these as HTML, so we need to escap ethem.
-            step.r#type.replace('<', "&lt;").replace('>', "&gt;")
-        );
+    for (level, step) in root.linearize_steps() {
+        let label = format!("{}{}", ".".repeat(level as usize), escape_step_name(step));
         writeln!(output, "{label:.<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap();
     }
     output
 }
+
+/// Bootstrap steps can be generic and thus contain angle brackets (<...>).
+/// However, Markdown interprets these as HTML, so we need to escap ethem.
+pub fn escape_step_name(step: &BuildStep) -> String {
+    step.r#type.replace('<', "&lt;").replace('>', "&gt;")
+}
diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock
index c061ec6ebdc..800eaae0766 100644
--- a/src/ci/citool/Cargo.lock
+++ b/src/ci/citool/Cargo.lock
@@ -107,6 +107,7 @@ dependencies = [
  "build_helper",
  "clap",
  "csv",
+ "diff",
  "glob-match",
  "insta",
  "serde",
@@ -242,6 +243,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "diff"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
+
+[[package]]
 name = "displaydoc"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml
index dde09224afe..f18436a1263 100644
--- a/src/ci/citool/Cargo.toml
+++ b/src/ci/citool/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 anyhow = "1"
 clap = { version = "4.5", features = ["derive"] }
 csv = "1"
+diff = "0.1"
 glob-match = "0.2"
 serde = { version = "1", features = ["derive"] }
 serde_yaml = "0.9"
diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs
index 98e9be0f35a..2b001f28b0e 100644
--- a/src/ci/citool/src/analysis.rs
+++ b/src/ci/citool/src/analysis.rs
@@ -1,33 +1,134 @@
 use std::collections::{BTreeMap, HashMap, HashSet};
+use std::fmt::Debug;
 
 use build_helper::metrics::{
-    BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps,
+    BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name,
+    format_build_steps,
 };
 
 use crate::metrics;
 use crate::metrics::{JobMetrics, JobName, get_test_suites};
 use crate::utils::{output_details, pluralize};
 
-pub fn output_bootstrap_stats(metrics: &JsonRoot) {
+/// Outputs durations of individual bootstrap steps from the gathered bootstrap invocations,
+/// and also a table with summarized information about executed tests.
+pub fn output_bootstrap_stats(metrics: &JsonRoot, parent_metrics: Option<&JsonRoot>) {
     if !metrics.invocations.is_empty() {
         println!("# Bootstrap steps");
-        record_bootstrap_step_durations(&metrics);
+        record_bootstrap_step_durations(&metrics, parent_metrics);
         record_test_suites(&metrics);
     }
 }
 
-fn record_bootstrap_step_durations(metrics: &JsonRoot) {
+fn record_bootstrap_step_durations(metrics: &JsonRoot, parent_metrics: Option<&JsonRoot>) {
+    let parent_steps: HashMap<String, BuildStep> = parent_metrics
+        .map(|metrics| {
+            metrics
+                .invocations
+                .iter()
+                .map(|invocation| {
+                    (invocation.cmdline.clone(), BuildStep::from_invocation(invocation))
+                })
+                .collect()
+        })
+        .unwrap_or_default();
+
     for invocation in &metrics.invocations {
         let step = BuildStep::from_invocation(invocation);
         let table = format_build_steps(&step);
         eprintln!("Step `{}`\n{table}\n", invocation.cmdline);
-        output_details(&invocation.cmdline, || {
+        output_details(&format!("{} (steps)", invocation.cmdline), || {
             println!("<pre><code>{table}</code></pre>");
         });
+
+        // If there was a parent bootstrap invocation with the same cmdline, diff it
+        if let Some(parent_step) = parent_steps.get(&invocation.cmdline) {
+            let table = format_build_step_diffs(&step, parent_step);
+
+            let duration_before = parent_step.duration.as_secs();
+            let duration_after = step.duration.as_secs();
+            output_details(
+                &format!("{} (diff) ({duration_before}s -> {duration_after}s)", invocation.cmdline),
+                || {
+                    println!("{table}");
+                },
+            );
+        }
     }
     eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len());
 }
 
+/// Creates a table that displays a diff between the durations of steps between
+/// two bootstrap invocations.
+/// It also shows steps that were missing before/after.
+fn format_build_step_diffs(current: &BuildStep, parent: &BuildStep) -> String {
+    use std::fmt::Write;
+
+    // Helper struct that compares steps by their full name
+    struct StepByName<'a>((u32, &'a BuildStep));
+
+    impl<'a> PartialEq for StepByName<'a> {
+        fn eq(&self, other: &Self) -> bool {
+            self.0.1.full_name.eq(&other.0.1.full_name)
+        }
+    }
+
+    fn get_steps(step: &BuildStep) -> Vec<StepByName> {
+        step.linearize_steps().into_iter().map(|v| StepByName(v)).collect()
+    }
+
+    let steps_before = get_steps(parent);
+    let steps_after = get_steps(current);
+
+    let mut table = "| Step | Before | After | Change |\n".to_string();
+    writeln!(table, "|:-----|-------:|------:|-------:|").unwrap();
+
+    // Try to match removed, added and same steps using a classic diff algorithm
+    for result in diff::slice(&steps_before, &steps_after) {
+        let (step, before, after, change) = match result {
+            // The step was found both before and after
+            diff::Result::Both(before, after) => {
+                let duration_before = before.0.1.duration;
+                let duration_after = after.0.1.duration;
+                let pct_change = duration_after.as_secs_f64() / duration_before.as_secs_f64();
+                let pct_change = pct_change * 100.0;
+                // Normalize around 100, to get + for regression and - for improvements
+                let pct_change = pct_change - 100.0;
+                (
+                    before,
+                    format!("{:.2}s", duration_before.as_secs_f64()),
+                    format!("{:.2}s", duration_after.as_secs_f64()),
+                    format!("{pct_change:.1}%"),
+                )
+            }
+            // The step was only found in the parent, so it was likely removed
+            diff::Result::Left(removed) => (
+                removed,
+                format!("{:.2}s", removed.0.1.duration.as_secs_f64()),
+                "".to_string(),
+                "(removed)".to_string(),
+            ),
+            // The step was only found in the current commit, so it was likely added
+            diff::Result::Right(added) => (
+                added,
+                "".to_string(),
+                format!("{:.2}s", added.0.1.duration.as_secs_f64()),
+                "(added)".to_string(),
+            ),
+        };
+
+        let prefix = ".".repeat(step.0.0 as usize);
+        writeln!(
+            table,
+            "| {prefix}{} | {before} | {after} | {change} |",
+            escape_step_name(step.0.1),
+        )
+        .unwrap();
+    }
+
+    table
+}
+
 fn record_test_suites(metrics: &JsonRoot) {
     let suites = metrics::get_test_suites(&metrics);
 
@@ -82,8 +183,7 @@ fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
     table
 }
 
-/// Computes a post merge CI analysis report of test differences
-/// between the `parent` and `current` commits.
+/// Outputs a report of test differences between the `parent` and `current` commits.
 pub fn output_test_diffs(job_metrics: HashMap<JobName, JobMetrics>) {
     let aggregated_test_diffs = aggregate_test_diffs(&job_metrics);
     report_test_diffs(aggregated_test_diffs);
diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs
index 5a84ecb5e47..5f5c50dc43a 100644
--- a/src/ci/citool/src/main.rs
+++ b/src/ci/citool/src/main.rs
@@ -144,31 +144,35 @@ fn postprocess_metrics(
     job_name: Option<String>,
 ) -> anyhow::Result<()> {
     let metrics = load_metrics(&metrics_path)?;
-    output_bootstrap_stats(&metrics);
 
-    let (Some(parent), Some(job_name)) = (parent, job_name) else {
-        return Ok(());
-    };
-
-    // This command is executed also on PR builds, which might not have parent metrics
-    // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics
-    // due to missing permissions.
-    // To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs,
-    // we simply print an error if the parent metrics were not found, but otherwise exit
-    // successfully.
-    match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") {
-        Ok(parent_metrics) => {
-            let job_metrics = HashMap::from([(
-                job_name,
-                JobMetrics { parent: Some(parent_metrics), current: metrics },
-            )]);
-            output_test_diffs(job_metrics);
-        }
-        Err(error) => {
-            eprintln!("Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}");
+    if let (Some(parent), Some(job_name)) = (parent, job_name) {
+        // This command is executed also on PR builds, which might not have parent metrics
+        // available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics
+        // due to missing permissions.
+        // To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs,
+        // we simply print an error if the parent metrics were not found, but otherwise exit
+        // successfully.
+        match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") {
+            Ok(parent_metrics) => {
+                output_bootstrap_stats(&metrics, Some(&parent_metrics));
+
+                let job_metrics = HashMap::from([(
+                    job_name,
+                    JobMetrics { parent: Some(parent_metrics), current: metrics },
+                )]);
+                output_test_diffs(job_metrics);
+                return Ok(());
+            }
+            Err(error) => {
+                eprintln!(
+                    "Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}"
+                );
+            }
         }
     }
 
+    output_bootstrap_stats(&metrics, None);
+
     Ok(())
 }
 
diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs
index a37b47e3bc9..61e148cdf18 100644
--- a/src/tools/rustfmt/src/closures.rs
+++ b/src/tools/rustfmt/src/closures.rs
@@ -176,7 +176,6 @@ fn rewrite_closure_with_block(
             .first()
             .map(|attr| attr.span.to(body.span))
             .unwrap_or(body.span),
-        could_be_bare_literal: false,
     };
     let block = crate::expr::rewrite_block_with_visitor(
         context,
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index 664c90b991a..e239ff47c04 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -423,7 +423,6 @@ fn rewrite_empty_macro_def_body(
         rules: ast::BlockCheckMode::Default,
         span,
         tokens: None,
-        could_be_bare_literal: false,
     };
     block.rewrite_result(context, shape)
 }
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 4a929a376d7..a33e03d5861 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -3189,7 +3189,6 @@ ui/parser/issues/issue-108495-dec.rs
 ui/parser/issues/issue-110014.rs
 ui/parser/issues/issue-111148.rs
 ui/parser/issues/issue-111416.rs
-ui/parser/issues/issue-111692.rs
 ui/parser/issues/issue-112188.rs
 ui/parser/issues/issue-112458.rs
 ui/parser/issues/issue-113110-non-item-at-module-root.rs
diff --git a/tests/codegen/assign-desugar-debuginfo.rs b/tests/codegen/assign-desugar-debuginfo.rs
new file mode 100644
index 00000000000..77ee8758b3b
--- /dev/null
+++ b/tests/codegen/assign-desugar-debuginfo.rs
@@ -0,0 +1,18 @@
+//@ compile-flags: -g -Zmir-opt-level=0
+
+#![crate_type = "lib"]
+
+#[inline(never)]
+fn swizzle(a: u32, b: u32, c: u32) -> (u32, (u32, u32)) {
+    (b, (c, a))
+}
+
+pub fn work() {
+    let mut a = 1;
+    let mut b = 2;
+    let mut c = 3;
+    (a, (b, c)) = swizzle(a, b, c);
+    println!("{a} {b} {c}");
+}
+
+// CHECK-NOT: !DILocalVariable(name: "lhs",
diff --git a/tests/incremental/define-opaques.rs b/tests/incremental/define-opaques.rs
new file mode 100644
index 00000000000..d6eae238341
--- /dev/null
+++ b/tests/incremental/define-opaques.rs
@@ -0,0 +1,19 @@
+//@ revisions: rpass1 cfail2
+
+#![feature(type_alias_impl_trait)]
+
+pub type Foo = impl Sized;
+
+#[cfg_attr(rpass1, define_opaque())]
+#[cfg_attr(cfail2, define_opaque(Foo))]
+fn a() {
+    //[cfail2]~^ ERROR item does not constrain `Foo::{opaque#0}`
+    let _: Foo = b();
+}
+
+#[define_opaque(Foo)]
+fn b() -> Foo {
+    ()
+}
+
+fn main() {}
diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
index 37e328a315f..4a866560e79 100644
--- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -114,7 +114,6 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                     rules: BlockCheckMode::Default,
                     span: DUMMY_SP,
                     tokens: None,
-                    could_be_bare_literal: false,
                 });
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
             }
diff --git a/tests/ui/closures/upvar-or-pattern-issue-138958.rs b/tests/ui/closures/upvar-or-pattern-issue-138958.rs
new file mode 100644
index 00000000000..fe9ebc0a7e6
--- /dev/null
+++ b/tests/ui/closures/upvar-or-pattern-issue-138958.rs
@@ -0,0 +1,11 @@
+//@ edition:2024
+//@ check-pass
+
+pub fn f(x: (u32, u32)) {
+    let _ = || {
+        let ((0, a) | (a, _)) = x;
+        a
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-111692.rs b/tests/ui/parser/issues/issue-111692.rs
deleted file mode 100644
index 56096f706a8..00000000000
--- a/tests/ui/parser/issues/issue-111692.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-mod module {
-    #[derive(Eq, PartialEq)]
-    pub struct Type {
-        pub x: u8,
-        pub y: u8,
-    }
-
-    pub const C: u8 = 32u8;
-}
-
-fn test(x: module::Type) {
-    if x == module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
-    }
-}
-
-fn test2(x: module::Type) {
-    if x ==module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
-    }
-}
-
-
-fn test3(x: module::Type) {
-    if x == Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
-    }
-}
-
-fn test4(x: module::Type) {
-    if x == demo_module::Type { x: module::C, y: 1 } { //~ ERROR invalid struct literal
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/parser/issues/issue-111692.stderr b/tests/ui/parser/issues/issue-111692.stderr
deleted file mode 100644
index 068b0483b0f..00000000000
--- a/tests/ui/parser/issues/issue-111692.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: invalid struct literal
-  --> $DIR/issue-111692.rs:12:21
-   |
-LL |     if x == module::Type { x: module::C, y: 1 } {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: you might need to surround the struct literal with parentheses
-   |
-LL |     if x == (module::Type { x: module::C, y: 1 }) {
-   |             +                                   +
-
-error: invalid struct literal
-  --> $DIR/issue-111692.rs:17:20
-   |
-LL |     if x ==module::Type { x: module::C, y: 1 } {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: you might need to surround the struct literal with parentheses
-   |
-LL |     if x ==(module::Type { x: module::C, y: 1 }) {
-   |            +                                   +
-
-error: invalid struct literal
-  --> $DIR/issue-111692.rs:23:13
-   |
-LL |     if x == Type { x: module::C, y: 1 } {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: you might need to surround the struct literal with parentheses
-   |
-LL |     if x == (Type { x: module::C, y: 1 }) {
-   |             +                           +
-
-error: invalid struct literal
-  --> $DIR/issue-111692.rs:28:26
-   |
-LL |     if x == demo_module::Type { x: module::C, y: 1 } {
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: you might need to surround the struct literal with parentheses
-   |
-LL |     if x == (demo_module::Type { x: module::C, y: 1 }) {
-   |             +                                        +
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs
deleted file mode 100644
index 8be7c9ee8ac..00000000000
--- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-pub struct Example { a: i32 }
-
-impl Example {
-    fn is_pos(&self) -> bool { self.a > 0 }
-}
-
-fn one() -> i32 { 1 }
-
-fn main() {
-    if Example { a: one(), }.is_pos() { //~ ERROR invalid struct literal
-        println!("Positive!");
-    }
-}
diff --git a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr b/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr
deleted file mode 100644
index f7822ba1124..00000000000
--- a/tests/ui/parser/method-call-on-struct-literal-in-if-condition.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error: invalid struct literal
-  --> $DIR/method-call-on-struct-literal-in-if-condition.rs:10:8
-   |
-LL |     if Example { a: one(), }.is_pos() {
-   |        ^^^^^^^^^^^^^^^^^^^^^
-   |
-help: you might need to surround the struct literal with parentheses
-   |
-LL |     if (Example { a: one(), }).is_pos() {
-   |        +                     +
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/parser/struct-literal-in-for.rs b/tests/ui/parser/struct-literal-in-for.rs
deleted file mode 100644
index 3227ae37bfd..00000000000
--- a/tests/ui/parser/struct-literal-in-for.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-struct Foo {
-    x: isize,
-}
-
-impl Foo {
-    fn hi(&self) -> bool {
-        true
-    }
-}
-
-fn main() {
-    for x in Foo { //~ ERROR struct literals are not allowed here
-        x: 3       //~^ ERROR `bool` is not an iterator
-    }.hi() {
-        println!("yo");
-    }
-}
diff --git a/tests/ui/parser/struct-literal-in-for.stderr b/tests/ui/parser/struct-literal-in-for.stderr
deleted file mode 100644
index 1c91eba68e3..00000000000
--- a/tests/ui/parser/struct-literal-in-for.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-in-for.rs:12:14
-   |
-LL |       for x in Foo {
-   |  ______________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |_____^
-   |
-help: surround the struct literal with parentheses
-   |
-LL ~     for x in (Foo {
-LL |         x: 3
-LL ~     }).hi() {
-   |
-
-error[E0277]: `bool` is not an iterator
-  --> $DIR/struct-literal-in-for.rs:12:14
-   |
-LL |       for x in Foo {
-   |  ______________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |__________^ `bool` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `bool`
-   = note: required for `bool` to implement `IntoIterator`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/parser/struct-literal-in-if.rs b/tests/ui/parser/struct-literal-in-if.rs
deleted file mode 100644
index c4a253c3da2..00000000000
--- a/tests/ui/parser/struct-literal-in-if.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-struct Foo {
-    x: isize,
-}
-
-impl Foo {
-    fn hi(&self) -> bool {
-        true
-    }
-}
-
-fn main() {
-    if Foo { //~ ERROR struct literals are not allowed here
-        x: 3
-    }.hi() {
-        println!("yo");
-    }
-    if let true = Foo { //~ ERROR struct literals are not allowed here
-        x: 3
-    }.hi() {
-        println!("yo");
-    }
-}
diff --git a/tests/ui/parser/struct-literal-in-if.stderr b/tests/ui/parser/struct-literal-in-if.stderr
deleted file mode 100644
index 8b72469fcf5..00000000000
--- a/tests/ui/parser/struct-literal-in-if.stderr
+++ /dev/null
@@ -1,34 +0,0 @@
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-in-if.rs:12:8
-   |
-LL |       if Foo {
-   |  ________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |_____^
-   |
-help: surround the struct literal with parentheses
-   |
-LL ~     if (Foo {
-LL |         x: 3
-LL ~     }).hi() {
-   |
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-in-if.rs:17:19
-   |
-LL |       if let true = Foo {
-   |  ___________________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |_____^
-   |
-help: surround the struct literal with parentheses
-   |
-LL ~     if let true = (Foo {
-LL |         x: 3
-LL ~     }).hi() {
-   |
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/parser/struct-literal-in-match-discriminant.rs b/tests/ui/parser/struct-literal-in-match-discriminant.rs
deleted file mode 100644
index ce132df5a88..00000000000
--- a/tests/ui/parser/struct-literal-in-match-discriminant.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-struct Foo {
-    x: isize,
-}
-
-fn main() {
-    match Foo { //~ ERROR struct literals are not allowed here
-        x: 3
-    } {
-        Foo {
-            x: x
-        } => {}
-    }
-}
diff --git a/tests/ui/parser/struct-literal-in-match-discriminant.stderr b/tests/ui/parser/struct-literal-in-match-discriminant.stderr
deleted file mode 100644
index 5177f5f126e..00000000000
--- a/tests/ui/parser/struct-literal-in-match-discriminant.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-in-match-discriminant.rs:6:11
-   |
-LL |       match Foo {
-   |  ___________^
-LL | |         x: 3
-LL | |     } {
-   | |_____^
-   |
-help: surround the struct literal with parentheses
-   |
-LL ~     match (Foo {
-LL |         x: 3
-LL ~     }) {
-   |
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/parser/struct-literal-in-while.rs b/tests/ui/parser/struct-literal-in-while.rs
deleted file mode 100644
index 86931f7888d..00000000000
--- a/tests/ui/parser/struct-literal-in-while.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-struct Foo {
-    x: isize,
-}
-
-impl Foo {
-    fn hi(&self) -> bool {
-        true
-    }
-}
-
-fn main() {
-    while Foo { //~ ERROR struct literals are not allowed here
-        x: 3
-    }.hi() {
-        println!("yo");
-    }
-    while let true = Foo { //~ ERROR struct literals are not allowed here
-        x: 3
-    }.hi() {
-        println!("yo");
-    }
-}
diff --git a/tests/ui/parser/struct-literal-in-while.stderr b/tests/ui/parser/struct-literal-in-while.stderr
deleted file mode 100644
index 13d003608a1..00000000000
--- a/tests/ui/parser/struct-literal-in-while.stderr
+++ /dev/null
@@ -1,34 +0,0 @@
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-in-while.rs:12:11
-   |
-LL |       while Foo {
-   |  ___________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |_____^
-   |
-help: surround the struct literal with parentheses
-   |
-LL ~     while (Foo {
-LL |         x: 3
-LL ~     }).hi() {
-   |
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-in-while.rs:17:22
-   |
-LL |       while let true = Foo {
-   |  ______________________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |_____^
-   |
-help: surround the struct literal with parentheses
-   |
-LL ~     while let true = (Foo {
-LL |         x: 3
-LL ~     }).hi() {
-   |
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/parser/struct-literal-restrictions-in-lamda.rs b/tests/ui/parser/struct-literal-restrictions-in-lamda.rs
deleted file mode 100644
index e185153dcf6..00000000000
--- a/tests/ui/parser/struct-literal-restrictions-in-lamda.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-struct Foo {
-    x: isize,
-}
-
-impl Foo {
-    fn hi(&self) -> bool {
-        true
-    }
-}
-
-fn main() {
-    while || Foo { //~ ERROR struct literals are not allowed here
-        x: 3       //~^ ERROR mismatched types
-    }.hi() {
-        println!("yo");
-    }
-}
diff --git a/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr b/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr
deleted file mode 100644
index c715486e2da..00000000000
--- a/tests/ui/parser/struct-literal-restrictions-in-lamda.stderr
+++ /dev/null
@@ -1,37 +0,0 @@
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-restrictions-in-lamda.rs:12:14
-   |
-LL |       while || Foo {
-   |  ______________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |_____^
-   |
-help: surround the struct literal with parentheses
-   |
-LL ~     while || (Foo {
-LL |         x: 3
-LL ~     }).hi() {
-   |
-
-error[E0308]: mismatched types
-  --> $DIR/struct-literal-restrictions-in-lamda.rs:12:11
-   |
-LL |       while || Foo {
-   |  ___________^
-LL | |         x: 3
-LL | |     }.hi() {
-   | |__________^ expected `bool`, found closure
-   |
-   = note: expected type `bool`
-           found closure `{closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 12:13}`
-help: use parentheses to call this closure
-   |
-LL ~     while (|| Foo {
-LL |         x: 3
-LL ~     }.hi())() {
-   |
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/struct-literal-variant-in-if.rs b/tests/ui/parser/struct-literal-variant-in-if.rs
deleted file mode 100644
index 4ef8effaf1f..00000000000
--- a/tests/ui/parser/struct-literal-variant-in-if.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-enum E {
-    V { field: bool },
-    I { field1: bool, field2: usize },
-    J { field: isize },
-    K { field: &'static str},
-}
-fn test_E(x: E) {
-    let field = true;
-    if x == E::V { field } {}
-    //~^ ERROR expected value, found struct variant `E::V`
-    //~| ERROR mismatched types
-    if x == E::I { field1: true, field2: 42 } {}
-    //~^ ERROR struct literals are not allowed here
-    if x == E::V { field: false } {}
-    //~^ ERROR struct literals are not allowed here
-    if x == E::J { field: -42 } {}
-    //~^ ERROR struct literals are not allowed here
-    if x == E::K { field: "" } {}
-    //~^ ERROR struct literals are not allowed here
-    let y: usize = ();
-    //~^ ERROR mismatched types
-}
-
-fn main() {}
diff --git a/tests/ui/parser/struct-literal-variant-in-if.stderr b/tests/ui/parser/struct-literal-variant-in-if.stderr
deleted file mode 100644
index 15f059f145b..00000000000
--- a/tests/ui/parser/struct-literal-variant-in-if.stderr
+++ /dev/null
@@ -1,76 +0,0 @@
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:13:13
-   |
-LL |     if x == E::I { field1: true, field2: 42 } {}
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::I { field1: true, field2: 42 }) {}
-   |             +                                 +
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:15:13
-   |
-LL |     if x == E::V { field: false } {}
-   |             ^^^^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::V { field: false }) {}
-   |             +                     +
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:17:13
-   |
-LL |     if x == E::J { field: -42 } {}
-   |             ^^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::J { field: -42 }) {}
-   |             +                   +
-
-error: struct literals are not allowed here
-  --> $DIR/struct-literal-variant-in-if.rs:19:13
-   |
-LL |     if x == E::K { field: "" } {}
-   |             ^^^^^^^^^^^^^^^^^^
-   |
-help: surround the struct literal with parentheses
-   |
-LL |     if x == (E::K { field: "" }) {}
-   |             +                  +
-
-error[E0533]: expected value, found struct variant `E::V`
-  --> $DIR/struct-literal-variant-in-if.rs:10:13
-   |
-LL |     if x == E::V { field } {}
-   |             ^^^^ not a value
-   |
-help: you might have meant to create a new value of the struct
-   |
-LL |     if x == (E::V { field }) {}
-   |             +              +
-
-error[E0308]: mismatched types
-  --> $DIR/struct-literal-variant-in-if.rs:10:20
-   |
-LL |     if x == E::V { field } {}
-   |     ---------------^^^^^--
-   |     |              |
-   |     |              expected `()`, found `bool`
-   |     expected this to be `()`
-
-error[E0308]: mismatched types
-  --> $DIR/struct-literal-variant-in-if.rs:21:20
-   |
-LL |     let y: usize = ();
-   |            -----   ^^ expected `usize`, found `()`
-   |            |
-   |            expected due to this
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0308, E0533.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/struct-literals-in-invalid-places.rs b/tests/ui/parser/struct-literals-in-invalid-places.rs
new file mode 100644
index 00000000000..eed51b94583
--- /dev/null
+++ b/tests/ui/parser/struct-literals-in-invalid-places.rs
@@ -0,0 +1,92 @@
+fn main() {
+    if Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
+        println!("yo");
+    }
+    if let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
+        println!("yo");
+    }
+
+    for x in Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
+        //~^ ERROR `bool` is not an iterator
+        println!("yo");
+    }
+
+    while Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
+        println!("yo");
+    }
+    while let true = Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
+        println!("yo");
+    }
+
+    match Foo { x: 3 } { //~ ERROR struct literals are not allowed here
+        Foo { x: x } => {}
+    }
+
+    let _ = |x: E| {
+        let field = true;
+        if x == E::V { field } {}
+        //~^ ERROR expected value, found struct variant `E::V`
+        //~| ERROR mismatched types
+        if x == E::I { field1: true, field2: 42 } {}
+        //~^ ERROR struct literals are not allowed here
+        if x == E::V { field: false } {}
+        //~^ ERROR struct literals are not allowed here
+        if x == E::J { field: -42 } {}
+        //~^ ERROR struct literals are not allowed here
+        if x == E::K { field: "" } {}
+        //~^ ERROR struct literals are not allowed here
+        let y: usize = ();
+        //~^ ERROR mismatched types
+    };
+
+    // Regression test for <https://github.com/rust-lang/rust/issues/43412>.
+    while || Foo { x: 3 }.hi() { //~ ERROR struct literals are not allowed here
+        //~^ ERROR mismatched types
+        println!("yo");
+    }
+
+    // This uses `one()` over `1` as token `one` may begin a type and thus back when type ascription
+    // `$expr : $ty` still existed, `{ x: one` could've been the start of a block expr which used to
+    // make the compiler take a different execution path. Now it no longer makes a difference tho.
+
+    // Regression test for <https://github.com/rust-lang/rust/issues/82051>.
+    if Foo { x: one(), }.hi() { //~ ERROR struct literals are not allowed here
+        println!("Positive!");
+    }
+
+    const FOO: Foo = Foo { x: 1 };
+    // Below, test that we correctly parenthesize the struct literals.
+
+    // Regression test for <https://github.com/rust-lang/rust/issues/112278>.
+    if FOO == self::Foo { x: one() } {} //~ ERROR struct literals are not allowed here
+
+    if FOO == Foo::<> { x: one() } {} //~ ERROR struct literals are not allowed here
+
+    fn env<T: Trait<Out = Foo>>() {
+        if FOO == <T as Trait>::Out { x: one() } {} //~ ERROR struct literals are not allowed here
+        //~^ ERROR usage of qualified paths in this context is experimental
+    }
+}
+
+#[derive(PartialEq, Eq)]
+struct Foo {
+    x: isize,
+}
+
+impl Foo {
+    fn hi(&self) -> bool {
+        true
+    }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum E {
+    V { field: bool },
+    I { field1: bool, field2: usize },
+    J { field: isize },
+    K { field: &'static str},
+}
+
+fn one() -> isize { 1 }
+
+trait Trait { type Out; }
diff --git a/tests/ui/parser/struct-literals-in-invalid-places.stderr b/tests/ui/parser/struct-literals-in-invalid-places.stderr
new file mode 100644
index 00000000000..39dc2d2efb7
--- /dev/null
+++ b/tests/ui/parser/struct-literals-in-invalid-places.stderr
@@ -0,0 +1,234 @@
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:2:8
+   |
+LL |     if Foo { x: 3 }.hi() {
+   |        ^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if (Foo { x: 3 }).hi() {
+   |        +            +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:5:19
+   |
+LL |     if let true = Foo { x: 3 }.hi() {
+   |                   ^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if let true = (Foo { x: 3 }).hi() {
+   |                   +            +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:9:14
+   |
+LL |     for x in Foo { x: 3 }.hi() {
+   |              ^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     for x in (Foo { x: 3 }).hi() {
+   |              +            +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:14:11
+   |
+LL |     while Foo { x: 3 }.hi() {
+   |           ^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     while (Foo { x: 3 }).hi() {
+   |           +            +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:17:22
+   |
+LL |     while let true = Foo { x: 3 }.hi() {
+   |                      ^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     while let true = (Foo { x: 3 }).hi() {
+   |                      +            +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:21:11
+   |
+LL |     match Foo { x: 3 } {
+   |           ^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     match (Foo { x: 3 }) {
+   |           +            +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:30:17
+   |
+LL |         if x == E::I { field1: true, field2: 42 } {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |         if x == (E::I { field1: true, field2: 42 }) {}
+   |                 +                                 +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:32:17
+   |
+LL |         if x == E::V { field: false } {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |         if x == (E::V { field: false }) {}
+   |                 +                     +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:34:17
+   |
+LL |         if x == E::J { field: -42 } {}
+   |                 ^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |         if x == (E::J { field: -42 }) {}
+   |                 +                   +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:36:17
+   |
+LL |         if x == E::K { field: "" } {}
+   |                 ^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |         if x == (E::K { field: "" }) {}
+   |                 +                  +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:43:14
+   |
+LL |     while || Foo { x: 3 }.hi() {
+   |              ^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     while || (Foo { x: 3 }).hi() {
+   |              +            +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:53:8
+   |
+LL |     if Foo { x: one(), }.hi() {
+   |        ^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if (Foo { x: one(), }).hi() {
+   |        +                 +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:61:15
+   |
+LL |     if FOO == self::Foo { x: one() } {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if FOO == (self::Foo { x: one() }) {}
+   |               +                      +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:63:15
+   |
+LL |     if FOO == Foo::<> { x: one() } {}
+   |               ^^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |     if FOO == (Foo::<> { x: one() }) {}
+   |               +                    +
+
+error: struct literals are not allowed here
+  --> $DIR/struct-literals-in-invalid-places.rs:66:19
+   |
+LL |         if FOO == <T as Trait>::Out { x: one() } {}
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: surround the struct literal with parentheses
+   |
+LL |         if FOO == (<T as Trait>::Out { x: one() }) {}
+   |                   +                              +
+
+error[E0658]: usage of qualified paths in this context is experimental
+  --> $DIR/struct-literals-in-invalid-places.rs:66:19
+   |
+LL |         if FOO == <T as Trait>::Out { x: one() } {}
+   |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0277]: `bool` is not an iterator
+  --> $DIR/struct-literals-in-invalid-places.rs:9:14
+   |
+LL |     for x in Foo { x: 3 }.hi() {
+   |              ^^^^^^^^^^^^^^^^^ `bool` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `bool`
+   = note: required for `bool` to implement `IntoIterator`
+
+error[E0533]: expected value, found struct variant `E::V`
+  --> $DIR/struct-literals-in-invalid-places.rs:27:17
+   |
+LL |         if x == E::V { field } {}
+   |                 ^^^^ not a value
+   |
+help: you might have meant to create a new value of the struct
+   |
+LL |         if x == (E::V { field }) {}
+   |                 +              +
+
+error[E0308]: mismatched types
+  --> $DIR/struct-literals-in-invalid-places.rs:27:24
+   |
+LL |         if x == E::V { field } {}
+   |         ---------------^^^^^--
+   |         |              |
+   |         |              expected `()`, found `bool`
+   |         expected this to be `()`
+   |
+help: you might have meant to return this value
+   |
+LL |         if x == E::V { return field; } {}
+   |                        ++++++      +
+
+error[E0308]: mismatched types
+  --> $DIR/struct-literals-in-invalid-places.rs:38:24
+   |
+LL |         let y: usize = ();
+   |                -----   ^^ expected `usize`, found `()`
+   |                |
+   |                expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/struct-literals-in-invalid-places.rs:43:11
+   |
+LL |     while || Foo { x: 3 }.hi() {
+   |           ^^^^^^^^^^^^^^^^^^^^ expected `bool`, found closure
+   |
+   = note: expected type `bool`
+           found closure `{closure@$DIR/struct-literals-in-invalid-places.rs:43:11: 43:13}`
+help: use parentheses to call this closure
+   |
+LL |     while (|| Foo { x: 3 }.hi())() {
+   |           +                    +++
+
+error: aborting due to 21 previous errors
+
+Some errors have detailed explanations: E0277, E0308, E0533, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/parser/type-ascription-in-pattern.rs b/tests/ui/parser/type-ascription-in-pattern.rs
index fec168afba1..18d7061d69c 100644
--- a/tests/ui/parser/type-ascription-in-pattern.rs
+++ b/tests/ui/parser/type-ascription-in-pattern.rs
@@ -1,11 +1,10 @@
 fn foo(x: bool) -> i32 {
-    match x {
+    match x { //~ ERROR struct literals are not allowed here
         x: i32 => x, //~ ERROR expected
-        //~^ ERROR mismatched types
-        true => 42.,
-        false => 0.333,
+        true => 42., //~ ERROR expected identifier
+        false => 0.333, //~ ERROR expected identifier
     }
-}
+} //~ ERROR expected one of
 
 fn main() {
     match foo(true) {
diff --git a/tests/ui/parser/type-ascription-in-pattern.stderr b/tests/ui/parser/type-ascription-in-pattern.stderr
index 09190754993..135879f208b 100644
--- a/tests/ui/parser/type-ascription-in-pattern.stderr
+++ b/tests/ui/parser/type-ascription-in-pattern.stderr
@@ -1,18 +1,64 @@
-error: expected one of `@` or `|`, found `:`
-  --> $DIR/type-ascription-in-pattern.rs:3:10
+error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>`
+  --> $DIR/type-ascription-in-pattern.rs:3:16
    |
+LL |     match x {
+   |           - while parsing this struct
 LL |         x: i32 => x,
-   |          ^ --- specifying the type of a pattern isn't supported
-   |          |
-   |          expected one of `@` or `|`
+   |               -^^ expected one of 8 possible tokens
+   |               |
+   |               help: try adding a comma: `,`
+
+error: expected identifier, found keyword `true`
+  --> $DIR/type-ascription-in-pattern.rs:4:9
    |
-help: maybe write a path separator here
+LL |     match x {
+   |           - while parsing this struct
+LL |         x: i32 => x,
+LL |         true => 42.,
+   |         ^^^^ expected identifier, found keyword
+
+error: expected identifier, found keyword `false`
+  --> $DIR/type-ascription-in-pattern.rs:5:9
    |
-LL |         x::i32 => x,
-   |          ~~
+LL |     match x {
+   |           - while parsing this struct
+...
+LL |         false => 0.333,
+   |         ^^^^^ expected identifier, found keyword
+
+error: struct literals are not allowed here
+  --> $DIR/type-ascription-in-pattern.rs:2:11
+   |
+LL |       match x {
+   |  ___________^
+LL | |         x: i32 => x,
+LL | |         true => 42.,
+LL | |         false => 0.333,
+LL | |     }
+   | |_____^
+   |
+help: surround the struct literal with parentheses
+   |
+LL ~     match (x {
+LL |         x: i32 => x,
+LL |         true => 42.,
+LL |         false => 0.333,
+LL ~     })
+   |
+
+error: expected one of `.`, `?`, `{`, or an operator, found `}`
+  --> $DIR/type-ascription-in-pattern.rs:7:1
+   |
+LL |     match x {
+   |     ----- while parsing this `match` expression
+...
+LL |     }
+   |      - expected one of `.`, `?`, `{`, or an operator
+LL | }
+   | ^ unexpected token
 
 error: expected one of `...`, `..=`, `..`, or `|`, found `:`
-  --> $DIR/type-ascription-in-pattern.rs:12:11
+  --> $DIR/type-ascription-in-pattern.rs:11:11
    |
 LL |         42: i32 => (),
    |           ^ --- specifying the type of a pattern isn't supported
@@ -20,7 +66,7 @@ LL |         42: i32 => (),
    |           expected one of `...`, `..=`, `..`, or `|`
 
 error: expected `|`, found `:`
-  --> $DIR/type-ascription-in-pattern.rs:13:10
+  --> $DIR/type-ascription-in-pattern.rs:12:10
    |
 LL |         _: f64 => (),
    |          ^ --- specifying the type of a pattern isn't supported
@@ -28,7 +74,7 @@ LL |         _: f64 => (),
    |          expected `|`
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/type-ascription-in-pattern.rs:14:10
+  --> $DIR/type-ascription-in-pattern.rs:13:10
    |
 LL |         x: i32 => (),
    |          ^ --- specifying the type of a pattern isn't supported
@@ -40,15 +86,5 @@ help: maybe write a path separator here
 LL |         x::i32 => (),
    |          ~~
 
-error[E0308]: mismatched types
-  --> $DIR/type-ascription-in-pattern.rs:3:19
-   |
-LL | fn foo(x: bool) -> i32 {
-   |                    --- expected `i32` because of return type
-LL |     match x {
-LL |         x: i32 => x,
-   |                   ^ expected `i32`, found `bool`
-
-error: aborting due to 5 previous errors
+error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs b/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs
new file mode 100644
index 00000000000..4bda4ba24c5
--- /dev/null
+++ b/tests/ui/target_modifiers/auxiliary/enabled_reg_struct_return.rs
@@ -0,0 +1,7 @@
+//@ no-prefer-dynamic
+//@ compile-flags: --target i686-unknown-linux-gnu -Zreg-struct-return=true
+//@ needs-llvm-components: x86
+
+#![feature(no_core)]
+#![crate_type = "rlib"]
+#![no_core]
diff --git a/tests/ui/target_modifiers/defaults_check.error.stderr b/tests/ui/target_modifiers/defaults_check.error.stderr
index 4833fe90677..936fbbc94d6 100644
--- a/tests/ui/target_modifiers/defaults_check.error.stderr
+++ b/tests/ui/target_modifiers/defaults_check.error.stderr
@@ -5,8 +5,8 @@ LL | #![feature(no_core)]
    | ^
    |
    = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
-   = note: `-Zreg-struct-return=true` in this crate is incompatible with `-Zreg-struct-return=` in dependency `default_reg_struct_return`
-   = help: set `-Zreg-struct-return=` in this crate or `-Zreg-struct-return=true` in `default_reg_struct_return`
+   = note: `-Zreg-struct-return=true` in this crate is incompatible with unset `-Zreg-struct-return` in dependency `default_reg_struct_return`
+   = help: unset `-Zreg-struct-return` in this crate or set `-Zreg-struct-return=true` in `default_reg_struct_return`
    = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/target_modifiers/no_value_bool.error.stderr b/tests/ui/target_modifiers/no_value_bool.error.stderr
new file mode 100644
index 00000000000..0484960dc62
--- /dev/null
+++ b/tests/ui/target_modifiers/no_value_bool.error.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
+  --> $DIR/no_value_bool.rs:16:1
+   |
+LL | #![feature(no_core)]
+   | ^
+   |
+   = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return`
+   = help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr b/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr
new file mode 100644
index 00000000000..0484960dc62
--- /dev/null
+++ b/tests/ui/target_modifiers/no_value_bool.error_explicit.stderr
@@ -0,0 +1,13 @@
+error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
+  --> $DIR/no_value_bool.rs:16:1
+   |
+LL | #![feature(no_core)]
+   | ^
+   |
+   = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
+   = note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return`
+   = help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return`
+   = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/target_modifiers/no_value_bool.rs b/tests/ui/target_modifiers/no_value_bool.rs
new file mode 100644
index 00000000000..ceba40afa89
--- /dev/null
+++ b/tests/ui/target_modifiers/no_value_bool.rs
@@ -0,0 +1,22 @@
+// Tests that bool target modifier value (true) in dependency crate is ok linked
+// with the -Zflag specified without value (-Zflag=true is consistent with -Zflag)
+
+//@ aux-build:enabled_reg_struct_return.rs
+//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
+//@ needs-llvm-components: x86
+
+//@ revisions: ok ok_explicit error error_explicit
+//@[ok] compile-flags: -Zreg-struct-return
+//@[ok_explicit] compile-flags: -Zreg-struct-return=true
+//@[error] compile-flags:
+//@[error_explicit] compile-flags: -Zreg-struct-return=false
+//@[ok] check-pass
+//@[ok_explicit] check-pass
+
+#![feature(no_core)]
+//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
+//[error_explicit]~^^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
+#![crate_type = "rlib"]
+#![no_core]
+
+extern crate enabled_reg_struct_return;