about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-24 10:03:12 +0000
committerbors <bors@rust-lang.org>2023-04-24 10:03:12 +0000
commit64bcb326516ef7490db46de88b87a4c0990097fe (patch)
treee29965e59cfdd41bd229d7142a55d549965122f3
parentf65615f02d22b85e9205f2716ab36182d34bab2b (diff)
parent2ce9b574a40ff27980578aa7ad7843dacc32acb7 (diff)
downloadrust-64bcb326516ef7490db46de88b87a4c0990097fe.tar.gz
rust-64bcb326516ef7490db46de88b87a4c0990097fe.zip
Auto merge of #110752 - matthiaskrgr:rollup-959s77u, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #110255 (Suggest using integration tests for test crate using own proc-macro)
 - #110514 (Remove `find_map_relevant_impl`)
 - #110566 (Don't create projection ty for const projection)
 - #110637 (Group some sections of our logs in github actions)
 - #110706 (Add `intrinsics::transmute_unchecked`)
 - #110714 (Normalize types and consts in MIR opts.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs2
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs62
-rw-r--r--compiler/rustc_middle/src/ty/util.rs37
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs2
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs2
-rw-r--r--compiler/rustc_mir_transform/src/reveal_all.rs14
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs2
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs2
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs4
-rw-r--r--compiler/rustc_resolve/messages.ftl3
-rw-r--r--compiler/rustc_resolve/src/errors.rs9
-rw-r--r--compiler/rustc_resolve/src/macros.rs10
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs145
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs22
-rw-r--r--library/core/src/array/iter.rs18
-rw-r--r--library/core/src/intrinsics.rs22
-rw-r--r--library/core/src/mem/maybe_uninit.rs10
-rw-r--r--src/bootstrap/bootstrap.py10
-rw-r--r--src/bootstrap/check.rs66
-rw-r--r--src/bootstrap/compile.rs59
-rw-r--r--src/bootstrap/install.rs4
-rw-r--r--src/bootstrap/lib.rs82
-rw-r--r--src/bootstrap/llvm.rs12
-rw-r--r--src/bootstrap/test.rs49
-rw-r--r--src/bootstrap/tool.rs61
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs20
-rw-r--r--src/tools/build_helper/src/ci.rs24
-rw-r--r--tests/codegen/intrinsics/transmute.rs42
-rw-r--r--tests/ui/associated-consts/projection-unspecified-but-bounded.rs16
-rw-r--r--tests/ui/associated-consts/projection-unspecified-but-bounded.stderr17
-rw-r--r--tests/ui/proc-macro/test-same-crate.rs16
-rw-r--r--tests/ui/proc-macro/test-same-crate.stderr10
38 files changed, 509 insertions, 395 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 854974d1605..0fcbaa2efab 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -198,7 +198,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             | sym::assert_zero_valid
             | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()),
             sym::forget => (1, vec![param(0)], tcx.mk_unit()),
-            sym::transmute => (2, vec![param(0)], param(1)),
+            sym::transmute | sym::transmute_unchecked => (2, vec![param(0)], param(1)),
             sym::prefetch_read_data
             | sym::prefetch_write_data
             | sym::prefetch_read_instruction
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 6747da7abd3..e61037e5ea8 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -139,40 +139,6 @@ impl<'tcx> TyCtxt<'tcx> {
         treat_projections: TreatProjections,
         mut f: impl FnMut(DefId),
     ) {
-        let _: Option<()> =
-            self.find_map_relevant_impl(trait_def_id, self_ty, treat_projections, |did| {
-                f(did);
-                None
-            });
-    }
-
-    /// `trait_def_id` MUST BE the `DefId` of a trait.
-    pub fn non_blanket_impls_for_ty(
-        self,
-        trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-    ) -> impl Iterator<Item = DefId> + 'tcx {
-        let impls = self.trait_impls_of(trait_def_id);
-        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
-            if let Some(impls) = impls.non_blanket_impls.get(&simp) {
-                return impls.iter().copied();
-            }
-        }
-
-        [].iter().copied()
-    }
-
-    /// Applies function to every impl that could possibly match the self type `self_ty` and returns
-    /// the first non-none value.
-    ///
-    /// `trait_def_id` MUST BE the `DefId` of a trait.
-    pub fn find_map_relevant_impl<T>(
-        self,
-        trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        treat_projections: TreatProjections,
-        mut f: impl FnMut(DefId) -> Option<T>,
-    ) -> Option<T> {
         // FIXME: This depends on the set of all impls for the trait. That is
         // unfortunate wrt. incremental compilation.
         //
@@ -181,9 +147,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let impls = self.trait_impls_of(trait_def_id);
 
         for &impl_def_id in impls.blanket_impls.iter() {
-            if let result @ Some(_) = f(impl_def_id) {
-                return result;
-            }
+            f(impl_def_id);
         }
 
         // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
@@ -199,20 +163,30 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
-                    if let result @ Some(_) = f(impl_def_id) {
-                        return result;
-                    }
+                    f(impl_def_id);
                 }
             }
         } else {
             for &impl_def_id in impls.non_blanket_impls.values().flatten() {
-                if let result @ Some(_) = f(impl_def_id) {
-                    return result;
-                }
+                f(impl_def_id);
             }
         }
+    }
 
-        None
+    /// `trait_def_id` MUST BE the `DefId` of a trait.
+    pub fn non_blanket_impls_for_ty(
+        self,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+    ) -> impl Iterator<Item = DefId> + 'tcx {
+        let impls = self.trait_impls_of(trait_def_id);
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
+            if let Some(impls) = impls.non_blanket_impls.get(&simp) {
+                return impls.iter().copied();
+            }
+        }
+
+        [].iter().copied()
     }
 
     /// Returns an iterator containing all impls for `trait_def_id`.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index dbe2eebe336..9dbd9fbbb5b 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -2,7 +2,6 @@
 
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir;
-use crate::ty::fast_reject::TreatProjections;
 use crate::ty::layout::IntegerExt;
 use crate::ty::{
     self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -359,21 +358,29 @@ impl<'tcx> TyCtxt<'tcx> {
         self.ensure().coherent_trait(drop_trait);
 
         let ty = self.type_of(adt_did).subst_identity();
-        let (did, constness) = self.find_map_relevant_impl(
-            drop_trait,
-            ty,
-            // FIXME: This could also be some other mode, like "unexpected"
-            TreatProjections::ForLookup,
-            |impl_did| {
-                if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
-                    if validate(self, impl_did).is_ok() {
-                        return Some((*item_id, self.constness(impl_did)));
-                    }
-                }
-                None
-            },
-        )?;
+        let mut dtor_candidate = None;
+        self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
+            let Some(item_id) = self.associated_item_def_ids(impl_did).first() else {
+                self.sess.delay_span_bug(self.def_span(impl_did), "Drop impl without drop function");
+                return;
+            };
+
+            if validate(self, impl_did).is_err() {
+                // Already `ErrorGuaranteed`, no need to delay a span bug here.
+                return;
+            }
+
+            if let Some((old_item_id, _)) = dtor_candidate {
+                self.sess
+                    .struct_span_err(self.def_span(item_id), "multiple drop impls found")
+                    .span_note(self.def_span(old_item_id), "other impl here")
+                    .delay_as_bug();
+            }
+
+            dtor_candidate = Some((*item_id, self.constness(impl_did)));
+        });
 
+        let (did, constness) = dtor_candidate?;
         Some(ty::Destructor { did, constness })
     }
 
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index a56c5cc5c12..c0861f99620 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -323,7 +323,7 @@ impl<'tcx> std::fmt::Debug for ScalarTy<'tcx> {
 
 impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self {
-        let param_env = tcx.param_env(body.source.def_id());
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         Self {
             map,
             tcx,
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 9447a2ff040..430a6f6cef5 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -120,7 +120,7 @@ impl EnumSizeOpt {
     fn optim<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut alloc_cache = FxHashMap::default();
         let body_did = body.source.def_id();
-        let param_env = tcx.param_env(body_did);
+        let param_env = tcx.param_env_reveal_all_normalized(body_did);
 
         let blocks = body.basic_blocks.as_mut();
         let local_decls = &mut body.local_decls;
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index c136642dff2..c7d3f6c9f04 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -221,7 +221,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                             terminator.kind = TerminatorKind::Goto { target };
                         }
                     }
-                    sym::transmute => {
+                    sym::transmute | sym::transmute_unchecked => {
                         let dst_ty = destination.ty(local_decls, tcx).ty;
                         let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else {
                             span_bug!(
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index ce05db5b762..59942dc76f9 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -46,7 +46,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let def_id = body.source.def_id();
-        let param_env = tcx.param_env(def_id);
+        let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
         let bbs = body.basic_blocks.as_mut();
         let mut should_cleanup = false;
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index abe6cb285f5..23442f8b97b 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -35,10 +35,22 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
     }
 
     #[inline]
+    fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _: Location) {
+        // We have to use `try_normalize_erasing_regions` here, since it's
+        // possible that we visit impossible-to-satisfy where clauses here,
+        // see #91745
+        if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.literal) {
+            constant.literal = c;
+        }
+    }
+
+    #[inline]
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
         // We have to use `try_normalize_erasing_regions` here, since it's
         // possible that we visit impossible-to-satisfy where clauses here,
         // see #91745
-        *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(*ty);
+        if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.param_env, *ty) {
+            *ty = t;
+        }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 4396a83e8b8..d4debae5c58 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -355,7 +355,7 @@ fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'t
 fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
     debug!("build_clone_shim(def_id={:?})", def_id);
 
-    let param_env = tcx.param_env(def_id);
+    let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
     let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
@@ -836,7 +836,7 @@ fn build_call_shim<'tcx>(
 pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
     debug_assert!(tcx.is_constructor(ctor_id));
 
-    let param_env = tcx.param_env(ctor_id);
+    let param_env = tcx.param_env_reveal_all_normalized(ctor_id);
 
     // Normalize the sig.
     let sig = tcx
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index c65a7ec6783..1ff48816986 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -16,7 +16,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(body.source.def_id());
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         for block in body.basic_blocks_mut() {
             let terminator = block.terminator_mut();
             terminator.kind = match terminator.kind {
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index dcad1518eb6..113ca2fc5ad 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -37,7 +37,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
         let opts = helper.find_optimizations();
         let mut storage_deads_to_insert = vec![];
         let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![];
-        let param_env = tcx.param_env(body.source.def_id());
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         for opt in opts {
             trace!("SUCCESS: Applying {:?}", opt);
             // replace terminator with a switchInt that switches on the integer directly
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index be0aa0fc4c1..5389b9f52eb 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -109,7 +109,9 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
                 continue;
             };
 
-            let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty));
+            let layout = tcx.layout_of(
+                tcx.param_env_reveal_all_normalized(body.source.def_id()).and(discriminant_ty),
+            );
 
             let allowed_variants = if let Ok(layout) = layout {
                 variant_discriminants(&layout, discriminant_ty, tcx)
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 01f002c9408..192badcbc37 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -223,3 +223,6 @@ resolve_remove_surrounding_derive =
 resolve_add_as_non_derive =
     add as non-Derive macro
     `#[{$macro_path}]`
+
+resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
+    .help = you can define integration tests in a directory named `tests`
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index af0ec236df0..6197af105a9 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -508,3 +508,12 @@ pub(crate) struct RemoveSurroundingDerive {
 pub(crate) struct AddAsNonDerive<'a> {
     pub(crate) macro_path: &'a str,
 }
+
+#[derive(Diagnostic)]
+#[diag(resolve_proc_macro_same_crate)]
+pub(crate) struct ProcMacroSameCrate {
+    #[primary_span]
+    pub(crate) span: Span,
+    #[help]
+    pub(crate) is_test: bool,
+}
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 22b014c0651..2211fb56ccd 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1,7 +1,7 @@
 //! A bunch of methods and structures more or less related to resolving macros and
 //! interface provided by `Resolver` to macro expander.
 
-use crate::errors::{AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive};
+use crate::errors::{self, AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive};
 use crate::Namespace::*;
 use crate::{BuiltinMacroState, Determinacy};
 use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
@@ -513,10 +513,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 if let Some(def_id) = def_id.as_local() {
                     self.unused_macros.remove(&def_id);
                     if self.proc_macro_stubs.contains(&def_id) {
-                        self.tcx.sess.span_err(
-                            path.span,
-                            "can't use a procedural macro from the same crate that defines it",
-                        );
+                        self.tcx.sess.emit_err(errors::ProcMacroSameCrate {
+                            span: path.span,
+                            is_test: self.tcx.sess.is_test_crate(),
+                        });
                     }
                 }
             }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9891915d076..70b9088de50 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1505,6 +1505,7 @@ symbols! {
         transmute_generic_consts,
         transmute_opts,
         transmute_trait,
+        transmute_unchecked,
         transparent,
         transparent_enums,
         transparent_unions,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 1abcc80d01a..8e7097ce4a7 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -645,12 +645,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             // FIXME: Handling opaques here is kinda sus. Especially because we
             // simplify them to PlaceholderSimplifiedType.
             | ty::Alias(ty::Opaque, _) => {
-                if let Some(def_id) = self.tcx().find_map_relevant_impl(
+                let mut disqualifying_impl = None;
+                self.tcx().for_each_relevant_impl_treating_projections(
                     goal.predicate.def_id(),
                     goal.predicate.self_ty(),
                     TreatProjections::NextSolverLookup,
-                    Some,
-                ) {
+                    |impl_def_id| {
+                        disqualifying_impl = Some(impl_def_id);
+                    },
+                );
+                if let Some(def_id) = disqualifying_impl {
                     debug!(?def_id, ?goal, "disqualified auto-trait implementation");
                     // No need to actually consider the candidate here,
                     // since we do that in `consider_impl_candidate`.
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index ae21dcd2a36..61e382bbe49 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -32,7 +32,6 @@ use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
 use rustc_middle::ty::{
@@ -1836,57 +1835,61 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 });
             let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
 
-            let secondary_span = match predicate.kind().skip_binder() {
-                ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
-                    .tcx
-                    .opt_associated_item(proj.projection_ty.def_id)
-                    .and_then(|trait_assoc_item| {
-                        self.tcx
-                            .trait_of_item(proj.projection_ty.def_id)
-                            .map(|id| (trait_assoc_item, id))
-                    })
-                    .and_then(|(trait_assoc_item, id)| {
-                        let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
-                        self.tcx.find_map_relevant_impl(
-                            id,
-                            proj.projection_ty.self_ty(),
-                            TreatProjections::ForLookup,
-                            |did| {
-                                self.tcx
-                                    .associated_items(did)
-                                    .in_definition_order()
-                                    .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
-                            },
-                        )
-                    })
-                    .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
-                        Some(
-                            hir::Node::TraitItem(hir::TraitItem {
-                                kind: hir::TraitItemKind::Type(_, Some(ty)),
-                                ..
-                            })
-                            | hir::Node::ImplItem(hir::ImplItem {
-                                kind: hir::ImplItemKind::Type(ty),
-                                ..
-                            }),
-                        ) => Some((
-                            ty.span,
-                            with_forced_trimmed_paths!(format!(
-                                "type mismatch resolving `{}`",
-                                self.resolve_vars_if_possible(predicate)
-                                    .print(FmtPrinter::new_with_limit(
-                                        self.tcx,
-                                        Namespace::TypeNS,
-                                        rustc_session::Limit(5),
-                                    ))
-                                    .unwrap()
-                                    .into_buffer()
-                            )),
+            let secondary_span = (|| {
+                let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) =
+                    predicate.kind().skip_binder()
+                else {
+                    return None;
+                };
+
+                let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
+                let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
+
+                let mut associated_items = vec![];
+                self.tcx.for_each_relevant_impl(
+                    self.tcx.trait_of_item(proj.projection_ty.def_id)?,
+                    proj.projection_ty.self_ty(),
+                    |impl_def_id| {
+                        associated_items.extend(
+                            self.tcx
+                                .associated_items(impl_def_id)
+                                .in_definition_order()
+                                .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident),
+                        );
+                    },
+                );
+
+                let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
+                    return None;
+                };
+                match self.tcx.hir().get_if_local(associated_item.def_id) {
+                    Some(
+                        hir::Node::TraitItem(hir::TraitItem {
+                            kind: hir::TraitItemKind::Type(_, Some(ty)),
+                            ..
+                        })
+                        | hir::Node::ImplItem(hir::ImplItem {
+                            kind: hir::ImplItemKind::Type(ty),
+                            ..
+                        }),
+                    ) => Some((
+                        ty.span,
+                        with_forced_trimmed_paths!(format!(
+                            "type mismatch resolving `{}`",
+                            self.resolve_vars_if_possible(predicate)
+                                .print(FmtPrinter::new_with_limit(
+                                    self.tcx,
+                                    Namespace::TypeNS,
+                                    rustc_session::Limit(5),
+                                ))
+                                .unwrap()
+                                .into_buffer()
                         )),
-                        _ => None,
-                    }),
-                _ => None,
-            };
+                    )),
+                    _ => None,
+                }
+            })();
+
             self.note_type_err(
                 &mut diag,
                 &obligation.cause,
@@ -2228,14 +2231,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err: &mut Diagnostic,
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) -> bool {
-        let get_trait_impl = |trait_def_id| {
-            self.tcx.find_map_relevant_impl(
+        let get_trait_impls = |trait_def_id| {
+            let mut trait_impls = vec![];
+            self.tcx.for_each_relevant_impl(
                 trait_def_id,
                 trait_ref.skip_binder().self_ty(),
-                TreatProjections::ForLookup,
-                Some,
-            )
+                |impl_def_id| {
+                    trait_impls.push(impl_def_id);
+                },
+            );
+            trait_impls
         };
+
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
         let traits_with_same_path: std::collections::BTreeSet<_> = self
             .tcx
@@ -2245,17 +2252,23 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             .collect();
         let mut suggested = false;
         for trait_with_same_path in traits_with_same_path {
-            if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
-                let impl_span = self.tcx.def_span(impl_def_id);
-                err.span_help(impl_span, "trait impl with same name found");
-                let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
-                let crate_msg = format!(
-                    "perhaps two different versions of crate `{}` are being used?",
-                    trait_crate
-                );
-                err.note(&crate_msg);
-                suggested = true;
+            let trait_impls = get_trait_impls(trait_with_same_path);
+            if trait_impls.is_empty() {
+                continue;
             }
+            let impl_spans: Vec<_> =
+                trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
+            err.span_help(
+                impl_spans,
+                format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
+            );
+            let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
+            let crate_msg = format!(
+                "perhaps two different versions of crate `{}` are being used?",
+                trait_crate
+            );
+            err.note(&crate_msg);
+            suggested = true;
         }
         suggested
     }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 6ba05387173..ea45412e47f 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1272,14 +1272,29 @@ fn project<'cx, 'tcx>(
         ProjectionCandidateSet::Single(candidate) => {
             Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
         }
-        ProjectionCandidateSet::None => Ok(Projected::NoProgress(
-            // FIXME(associated_const_generics): this may need to change in the future?
-            // need to investigate whether or not this is fine.
-            selcx
-                .tcx()
-                .mk_projection(obligation.predicate.def_id, obligation.predicate.substs)
-                .into(),
-        )),
+        ProjectionCandidateSet::None => {
+            let tcx = selcx.tcx();
+            let term = match tcx.def_kind(obligation.predicate.def_id) {
+                DefKind::AssocTy | DefKind::ImplTraitPlaceholder => tcx
+                    .mk_projection(obligation.predicate.def_id, obligation.predicate.substs)
+                    .into(),
+                DefKind::AssocConst => tcx
+                    .mk_const(
+                        ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(
+                            obligation.predicate.def_id,
+                            obligation.predicate.substs,
+                        )),
+                        tcx.type_of(obligation.predicate.def_id)
+                            .subst(tcx, obligation.predicate.substs),
+                    )
+                    .into(),
+                kind => {
+                    bug!("unknown projection def-id: {}", kind.descr(obligation.predicate.def_id))
+                }
+            };
+
+            Ok(Projected::NoProgress(term))
+        }
         // Error occurred while trying to processing impls.
         ProjectionCandidateSet::Error(e) => Err(ProjectionError::TraitSelectionError(e)),
         // Inherent ambiguity that prevents us from even enumerating the
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index a019d00461b..1db9b8ce92e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -11,7 +11,7 @@ use hir::LangItem;
 use rustc_hir as hir;
 use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
 use crate::traits;
@@ -875,12 +875,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ty::Adt(..) => {
-                // Find a custom `impl Drop` impl, if it exists
-                let relevant_impl = self.tcx().find_map_relevant_impl(
+                let mut relevant_impl = None;
+                self.tcx().for_each_relevant_impl(
                     self.tcx().require_lang_item(LangItem::Drop, None),
                     obligation.predicate.skip_binder().trait_ref.self_ty(),
-                    TreatProjections::ForLookup,
-                    Some,
+                    |impl_def_id| {
+                        if let Some(old_impl_def_id) = relevant_impl {
+                            self.tcx()
+                                .sess
+                                .struct_span_err(
+                                    self.tcx().def_span(impl_def_id),
+                                    "multiple drop impls found",
+                                )
+                                .span_note(self.tcx().def_span(old_impl_def_id), "other impl here")
+                                .delay_as_bug();
+                        }
+
+                        relevant_impl = Some(impl_def_id);
+                    },
                 );
 
                 if let Some(impl_def_id) = relevant_impl {
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 73e2c2cfbbe..587877dff55 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -3,8 +3,9 @@
 use crate::num::NonZeroUsize;
 use crate::{
     fmt,
+    intrinsics::transmute_unchecked,
     iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
-    mem::{self, MaybeUninit},
+    mem::MaybeUninit,
     ops::{IndexRange, Range},
     ptr,
 };
@@ -63,18 +64,11 @@ impl<T, const N: usize> IntoIterator for [T; N] {
         // an array of `T`.
         //
         // With that, this initialization satisfies the invariants.
-
-        // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
-        // works with const generics:
-        //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
         //
-        // Until then, we can use `mem::transmute_copy` to create a bitwise copy
-        // as a different type, then forget `array` so that it is not dropped.
-        unsafe {
-            let iter = IntoIter { data: mem::transmute_copy(&self), alive: IndexRange::zero_to(N) };
-            mem::forget(self);
-            iter
-        }
+        // FIXME: If normal `transmute` ever gets smart enough to allow this
+        // directly, use it instead of `transmute_unchecked`.
+        let data: [MaybeUninit<T>; N] = unsafe { transmute_unchecked(self) };
+        IntoIter { data, alive: IndexRange::zero_to(N) }
     }
 }
 
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index ba03da411e3..39edfd8265b 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1376,6 +1376,20 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn transmute<Src, Dst>(src: Src) -> Dst;
 
+    /// Like [`transmute`], but even less checked at compile-time: rather than
+    /// giving an error for `size_of::<Src>() != size_of::<Dst>()`, it's
+    /// **Undefined Behaviour** at runtime.
+    ///
+    /// Prefer normal `transmute` where possible, for the extra checking, since
+    /// both do exactly the same thing at runtime, if they both compile.
+    ///
+    /// This is not expected to ever be exposed directly to users, rather it
+    /// may eventually be exposed through some more-constrained API.
+    #[cfg(not(bootstrap))]
+    #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
+    #[rustc_nounwind]
+    pub fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
+
     /// Returns `true` if the actual type given as `T` requires drop
     /// glue; returns `false` if the actual type provided for `T`
     /// implements `Copy`.
@@ -2798,3 +2812,11 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
         write_bytes(dst, val, count)
     }
 }
+
+/// Polyfill for bootstrap
+#[cfg(bootstrap)]
+pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
+    use crate::mem::*;
+    // SAFETY: It's a transmute -- the caller promised it's fine.
+    unsafe { transmute_copy(&ManuallyDrop::new(src)) }
+}
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 9c6d48675a6..2588b7d2bef 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -945,14 +945,10 @@ impl<T> MaybeUninit<T> {
         // * `MaybeUninit<T>` and T are guaranteed to have the same layout
         // * `MaybeUninit` does not drop, so there are no double-frees
         // And thus the conversion is safe
-        let ret = unsafe {
+        unsafe {
             intrinsics::assert_inhabited::<[T; N]>();
-            (&array as *const _ as *const [T; N]).read()
-        };
-
-        // FIXME: required to avoid `~const Destruct` bound
-        super::forget(array);
-        ret
+            intrinsics::transmute_unchecked(array)
+        }
     }
 
     /// Assuming all the elements are initialized, get a slice to them.
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index e6788ee6fee..680a8da6adf 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -722,11 +722,14 @@ class RustBuild(object):
 
     def build_bootstrap(self, color, verbose_count):
         """Build bootstrap"""
-        print("Building bootstrap")
+        env = os.environ.copy()
+        if "GITHUB_ACTIONS" in env:
+            print("::group::Building bootstrap")
+        else:
+            print("Building bootstrap")
         build_dir = os.path.join(self.build_dir, "bootstrap")
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
-        env = os.environ.copy()
         # `CARGO_BUILD_TARGET` breaks bootstrap build.
         # See also: <https://github.com/rust-lang/rust/issues/70208>.
         if "CARGO_BUILD_TARGET" in env:
@@ -798,6 +801,9 @@ class RustBuild(object):
         # Run this from the source directory so cargo finds .cargo/config
         run(args, env=env, verbose=self.verbose, cwd=self.rust_root)
 
+        if "GITHUB_ACTIONS" in env:
+            print("::endgroup::")
+
     def build_triple(self):
         """Build triple as in LLVM
 
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 44efc502e39..60de46ce64c 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -105,15 +105,7 @@ impl Step for Std {
             cargo.arg("--lib");
         }
 
-        let msg = if compiler.host == target {
-            format!("Checking stage{} library artifacts ({target})", builder.top_stage)
-        } else {
-            format!(
-                "Checking stage{} library artifacts ({} -> {})",
-                builder.top_stage, &compiler.host, target
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg_check("library artifacts", target);
         run_cargo(
             builder,
             cargo,
@@ -167,18 +159,7 @@ impl Step for Std {
             cargo.arg("-p").arg(krate.name);
         }
 
-        let msg = if compiler.host == target {
-            format!(
-                "Checking stage{} library test/bench/example targets ({target})",
-                builder.top_stage
-            )
-        } else {
-            format!(
-                "Checking stage{} library test/bench/example targets ({} -> {})",
-                builder.top_stage, &compiler.host, target
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg_check("library test/bench/example targets", target);
         run_cargo(
             builder,
             cargo,
@@ -252,15 +233,7 @@ impl Step for Rustc {
             cargo.arg("-p").arg(krate.name);
         }
 
-        let msg = if compiler.host == target {
-            format!("Checking stage{} compiler artifacts ({target})", builder.top_stage)
-        } else {
-            format!(
-                "Checking stage{} compiler artifacts ({} -> {})",
-                builder.top_stage, &compiler.host, target
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg_check("compiler artifacts", target);
         run_cargo(
             builder,
             cargo,
@@ -317,15 +290,7 @@ impl Step for CodegenBackend {
             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
         rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
 
-        let msg = if compiler.host == target {
-            format!("Checking stage{} {} artifacts ({target})", builder.top_stage, backend)
-        } else {
-            format!(
-                "Checking stage{} {} library ({} -> {})",
-                builder.top_stage, backend, &compiler.host.triple, target.triple
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg_check(&backend, target);
 
         run_cargo(
             builder,
@@ -385,15 +350,7 @@ impl Step for RustAnalyzer {
             cargo.arg("--benches");
         }
 
-        let msg = if compiler.host == target {
-            format!("Checking stage{} {} artifacts ({target})", compiler.stage, "rust-analyzer")
-        } else {
-            format!(
-                "Checking stage{} {} artifacts ({} -> {})",
-                compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg_check("rust-analyzer artifacts", target);
         run_cargo(
             builder,
             cargo,
@@ -460,18 +417,7 @@ macro_rules! tool_check_step {
                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
                 cargo.rustflag("-Zunstable-options");
-                let msg = if compiler.host == target {
-                    format!("Checking stage{} {} artifacts ({target})", builder.top_stage, stringify!($name).to_lowercase())
-                } else {
-                    format!(
-                        "Checking stage{} {} artifacts ({} -> {})",
-                        builder.top_stage,
-                        stringify!($name).to_lowercase(),
-                        &compiler.host.triple,
-                        target.triple
-                    )
-                };
-                builder.info(&msg);
+                let _guard = builder.msg_check(&concat!(stringify!($name), " artifacts").to_lowercase(), target);
                 run_cargo(
                     builder,
                     cargo,
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index ab307d4d038..7d2a6862500 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -143,23 +143,13 @@ impl Step for Std {
             cargo.arg("-p").arg(krate);
         }
 
-        let msg = if compiler.host == target {
-            format!(
-                "Building{} stage{} library artifacts ({}) ",
-                crate_description(&self.crates),
-                compiler.stage,
-                compiler.host
-            )
-        } else {
-            format!(
-                "Building{} stage{} library artifacts ({} -> {})",
-                crate_description(&self.crates),
-                compiler.stage,
-                compiler.host,
-                target,
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg(
+            Kind::Build,
+            compiler.stage,
+            format_args!("library artifacts{}", crate_description(&self.crates)),
+            compiler.host,
+            target,
+        );
         run_cargo(
             builder,
             cargo,
@@ -790,24 +780,13 @@ impl Step for Rustc {
             cargo.arg("-p").arg(krate);
         }
 
-        let msg = if compiler.host == target {
-            format!(
-                "Building{} compiler artifacts (stage{} -> stage{})",
-                crate_description(&self.crates),
-                compiler.stage,
-                compiler.stage + 1
-            )
-        } else {
-            format!(
-                "Building{} compiler artifacts (stage{}:{} -> stage{}:{})",
-                crate_description(&self.crates),
-                compiler.stage,
-                compiler.host,
-                compiler.stage + 1,
-                target,
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg_sysroot_tool(
+            Kind::Build,
+            compiler.stage,
+            format_args!("compiler artifacts{}", crate_description(&self.crates)),
+            compiler.host,
+            target,
+        );
         run_cargo(
             builder,
             cargo,
@@ -1114,15 +1093,7 @@ impl Step for CodegenBackend {
 
         let tmp_stamp = out_dir.join(".tmp.stamp");
 
-        let msg = if compiler.host == target {
-            format!("Building stage{} codegen backend {}", compiler.stage, backend)
-        } else {
-            format!(
-                "Building stage{} codegen backend {} ({} -> {})",
-                compiler.stage, backend, compiler.host, target
-            )
-        };
-        builder.info(&msg);
+        let _guard = builder.msg_build(compiler, format_args!("codegen backend {backend}"), target);
         let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false, false);
         if builder.config.dry_run() {
             return;
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 42d895a3413..b62aa999246 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -12,7 +12,7 @@ use crate::util::t;
 
 use crate::dist;
 use crate::tarball::GeneratedTarball;
-use crate::Compiler;
+use crate::{Compiler, Kind};
 
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::config::{Config, TargetSelection};
@@ -52,7 +52,7 @@ fn install_sh(
     host: Option<TargetSelection>,
     tarball: &GeneratedTarball,
 ) {
-    builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));
+    let _guard = builder.msg(Kind::Install, stage, package, host, host);
 
     let prefix = default_path(&builder.config.prefix, "/usr/local");
     let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index bfdb029951f..238d167c4c2 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -19,13 +19,14 @@
 use std::cell::{Cell, RefCell};
 use std::collections::{HashMap, HashSet};
 use std::env;
+use std::fmt::Display;
 use std::fs::{self, File};
 use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::str;
 
-use build_helper::ci::CiEnv;
+use build_helper::ci::{gha, CiEnv};
 use channel::GitInfo;
 use config::{DryRun, Target};
 use filetime::FileTime;
@@ -993,6 +994,85 @@ impl Build {
         }
     }
 
+    fn msg_check(
+        &self,
+        what: impl Display,
+        target: impl Into<Option<TargetSelection>>,
+    ) -> Option<gha::Group> {
+        self.msg(Kind::Check, self.config.stage, what, self.config.build, target)
+    }
+
+    fn msg_build(
+        &self,
+        compiler: Compiler,
+        what: impl Display,
+        target: impl Into<Option<TargetSelection>>,
+    ) -> Option<gha::Group> {
+        self.msg(Kind::Build, compiler.stage, what, compiler.host, target)
+    }
+
+    /// Return a `Group` guard for a [`Step`] that is built for each `--stage`.
+    fn msg(
+        &self,
+        action: impl Into<Kind>,
+        stage: u32,
+        what: impl Display,
+        host: impl Into<Option<TargetSelection>>,
+        target: impl Into<Option<TargetSelection>>,
+    ) -> Option<gha::Group> {
+        let action = action.into();
+        let msg = |fmt| format!("{action:?}ing stage{stage} {what}{fmt}");
+        let msg = if let Some(target) = target.into() {
+            let host = host.into().unwrap();
+            if host == target {
+                msg(format_args!(" ({target})"))
+            } else {
+                msg(format_args!(" ({host} -> {target})"))
+            }
+        } else {
+            msg(format_args!(""))
+        };
+        self.group(&msg)
+    }
+
+    /// Return a `Group` guard for a [`Step`] that is only built once and isn't affected by `--stage`.
+    fn msg_unstaged(
+        &self,
+        action: impl Into<Kind>,
+        what: impl Display,
+        target: TargetSelection,
+    ) -> Option<gha::Group> {
+        let action = action.into();
+        let msg = format!("{action:?}ing {what} for {target}");
+        self.group(&msg)
+    }
+
+    fn msg_sysroot_tool(
+        &self,
+        action: impl Into<Kind>,
+        stage: u32,
+        what: impl Display,
+        host: TargetSelection,
+        target: TargetSelection,
+    ) -> Option<gha::Group> {
+        let action = action.into();
+        let msg = |fmt| format!("{action:?}ing {what} {fmt}");
+        let msg = if host == target {
+            msg(format_args!("(stage{stage} -> stage{}, {target})", stage + 1))
+        } else {
+            msg(format_args!("(stage{stage}:{host} -> stage{}:{target})", stage + 1))
+        };
+        self.group(&msg)
+    }
+
+    fn group(&self, msg: &str) -> Option<gha::Group> {
+        self.info(&msg);
+        match self.config.dry_run {
+            DryRun::SelfCheck => None,
+            DryRun::Disabled | DryRun::UserSelected => Some(gha::group(&msg)),
+        }
+    }
+
     /// Returns the number of parallel jobs that have been configured for this
     /// build.
     fn jobs(&self) -> u32 {
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index cfc74186313..67cb8837391 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -21,7 +21,7 @@ use crate::channel;
 use crate::config::{Config, TargetSelection};
 use crate::util::get_clang_cl_resource_dir;
 use crate::util::{self, exe, output, t, up_to_date};
-use crate::{CLang, GitRepo};
+use crate::{CLang, GitRepo, Kind};
 
 use build_helper::ci::CiEnv;
 
@@ -271,7 +271,7 @@ impl Step for Llvm {
             panic!("shared linking to LLVM is not currently supported on {}", target.triple);
         }
 
-        builder.info(&format!("Building LLVM for {}", target));
+        let _guard = builder.msg_unstaged(Kind::Build, "LLVM", target);
         t!(stamp.remove());
         let _time = util::timeit(&builder);
         t!(fs::create_dir_all(&out_dir));
@@ -813,7 +813,7 @@ impl Step for Lld {
             return out_dir;
         }
 
-        builder.info(&format!("Building LLD for {}", target));
+        let _guard = builder.msg_unstaged(Kind::Build, "LLD", target);
         let _time = util::timeit(&builder);
         t!(fs::create_dir_all(&out_dir));
 
@@ -911,7 +911,7 @@ impl Step for Sanitizers {
             return runtimes;
         }
 
-        builder.info(&format!("Building sanitizers for {}", self.target));
+        let _guard = builder.msg_unstaged(Kind::Build, "sanitizers", self.target);
         t!(stamp.remove());
         let _time = util::timeit(&builder);
 
@@ -1103,7 +1103,7 @@ impl Step for CrtBeginEnd {
             return out_dir;
         }
 
-        builder.info("Building crtbegin.o and crtend.o");
+        let _guard = builder.msg_unstaged(Kind::Build, "crtbegin.o and crtend.o", self.target);
         t!(fs::create_dir_all(&out_dir));
 
         let mut cfg = cc::Build::new();
@@ -1168,7 +1168,7 @@ impl Step for Libunwind {
             return out_dir;
         }
 
-        builder.info(&format!("Building libunwind.a for {}", self.target.triple));
+        let _guard = builder.msg_unstaged(Kind::Build, "libunwind.a", self.target);
         t!(fs::create_dir_all(&out_dir));
 
         let mut cc_cfg = cc::Build::new();
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index ccf83974b8c..601351ea8e3 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -5,7 +5,6 @@
 
 use std::env;
 use std::ffi::OsString;
-use std::fmt;
 use std::fs;
 use std::iter;
 use std::path::{Path, PathBuf};
@@ -57,12 +56,12 @@ impl TestKind {
     }
 }
 
-impl fmt::Display for TestKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match *self {
-            TestKind::Test => "Testing",
-            TestKind::Bench => "Benchmarking",
-        })
+impl Into<Kind> for TestKind {
+    fn into(self) -> Kind {
+        match self {
+            TestKind::Test => Kind::Test,
+            TestKind::Bench => Kind::Bench,
+        }
     }
 }
 
@@ -1905,7 +1904,13 @@ impl BookTest {
         rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
         rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
         builder.add_rust_test_threads(&mut rustbook_cmd);
-        builder.info(&format!("Testing rustbook {}", self.path.display()));
+        let _guard = builder.msg(
+            Kind::Test,
+            compiler.stage,
+            format_args!("rustbook {}", self.path.display()),
+            compiler.host,
+            compiler.host,
+        );
         let _time = util::timeit(&builder);
         let toolstate = if try_run(builder, &mut rustbook_cmd) {
             ToolState::TestPass
@@ -2033,7 +2038,8 @@ impl Step for ErrorIndex {
         let mut tool = tool::ErrorIndex::command(builder);
         tool.arg("markdown").arg(&output);
 
-        builder.info(&format!("Testing error-index stage{}", compiler.stage));
+        let _guard =
+            builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host);
         let _time = util::timeit(&builder);
         builder.run_quiet(&mut tool);
         // The tests themselves need to link to std, so make sure it is
@@ -2263,14 +2269,13 @@ impl Step for Crate {
             );
         }
 
-        builder.info(&format!(
-            "{}{} stage{} ({} -> {})",
+        let _guard = builder.msg(
             test_kind,
-            crate_description(&self.crates),
             compiler.stage,
-            &compiler.host,
-            target
-        ));
+            crate_description(&self.crates),
+            compiler.host,
+            target,
+        );
         let _time = util::timeit(&builder);
         crate::render_tests::try_run_tests(builder, &mut cargo.into());
     }
@@ -2386,10 +2391,8 @@ impl Step for CrateRustdoc {
             cargo.arg("--quiet");
         }
 
-        builder.info(&format!(
-            "{} rustdoc stage{} ({} -> {})",
-            test_kind, compiler.stage, &compiler.host, target
-        ));
+        let _guard = builder.msg(test_kind, compiler.stage, "rustdoc", compiler.host, target);
+
         let _time = util::timeit(&builder);
 
         add_flags_and_try_run_tests(builder, &mut cargo.into());
@@ -2453,10 +2456,8 @@ impl Step for CrateRustdocJsonTypes {
             cargo.arg("'-Ctarget-feature=-crt-static'");
         }
 
-        builder.info(&format!(
-            "{} rustdoc-json-types stage{} ({} -> {})",
-            test_kind, compiler.stage, &compiler.host, target
-        ));
+        let _guard =
+            builder.msg(test_kind, compiler.stage, "rustdoc-json-types", compiler.host, target);
         let _time = util::timeit(&builder);
 
         add_flags_and_try_run_tests(builder, &mut cargo.into());
@@ -2845,7 +2846,7 @@ impl Step for TestHelpers {
             return;
         }
 
-        builder.info("Building test helpers");
+        let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
         t!(fs::create_dir_all(&dst));
         let mut cfg = cc::Build::new();
         // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index f8da6df0c7c..f3724b2c0e4 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -11,6 +11,7 @@ use crate::toolstate::ToolState;
 use crate::util::{add_dylib_path, exe, t};
 use crate::Compiler;
 use crate::Mode;
+use crate::{gha, Kind};
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub enum SourceType {
@@ -32,41 +33,27 @@ struct ToolBuild {
     allow_features: &'static str,
 }
 
-fn tooling_output(
-    mode: Mode,
-    tool: &str,
-    build_stage: u32,
-    host: &TargetSelection,
-    target: &TargetSelection,
-) -> String {
-    match mode {
-        // depends on compiler stage, different to host compiler
-        Mode::ToolRustc => {
-            if host == target {
-                format!("Building tool {} (stage{} -> stage{})", tool, build_stage, build_stage + 1)
-            } else {
-                format!(
-                    "Building tool {} (stage{}:{} -> stage{}:{})",
-                    tool,
-                    build_stage,
-                    host,
-                    build_stage + 1,
-                    target
-                )
-            }
-        }
-        // doesn't depend on compiler, same as host compiler
-        Mode::ToolStd => {
-            if host == target {
-                format!("Building tool {} (stage{})", tool, build_stage)
-            } else {
-                format!(
-                    "Building tool {} (stage{}:{} -> stage{}:{})",
-                    tool, build_stage, host, build_stage, target
-                )
-            }
+impl Builder<'_> {
+    fn msg_tool(
+        &self,
+        mode: Mode,
+        tool: &str,
+        build_stage: u32,
+        host: &TargetSelection,
+        target: &TargetSelection,
+    ) -> Option<gha::Group> {
+        match mode {
+            // depends on compiler stage, different to host compiler
+            Mode::ToolRustc => self.msg_sysroot_tool(
+                Kind::Build,
+                build_stage,
+                format_args!("tool {tool}"),
+                *host,
+                *target,
+            ),
+            // doesn't depend on compiler, same as host compiler
+            _ => self.msg(Kind::Build, build_stage, format_args!("tool {tool}"), *host, *target),
         }
-        _ => format!("Building tool {} (stage{})", tool, build_stage),
     }
 }
 
@@ -111,14 +98,13 @@ impl Step for ToolBuild {
         if !self.allow_features.is_empty() {
             cargo.allow_features(self.allow_features);
         }
-        let msg = tooling_output(
+        let _guard = builder.msg_tool(
             self.mode,
             self.tool,
             self.compiler.stage,
             &self.compiler.host,
             &self.target,
         );
-        builder.info(&msg);
 
         let mut cargo = Command::from(cargo);
         let is_expected = builder.try_run(&mut cargo);
@@ -492,14 +478,13 @@ impl Step for Rustdoc {
             cargo.rustflag("--cfg=parallel_compiler");
         }
 
-        let msg = tooling_output(
+        let _guard = builder.msg_tool(
             Mode::ToolRustc,
             "rustdoc",
             build_compiler.stage,
             &self.compiler.host,
             &target,
         );
-        builder.info(&msg);
         builder.run(&mut cargo.into());
 
         // Cargo adds a number of paths to the dylib search path on windows, which results in
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 33e80df9ed7..f2486abaaa7 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -13,7 +13,7 @@ use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{DefKind, Namespace, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::Mutability;
-use rustc_middle::ty::{fast_reject::TreatProjections, Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{bug, ty};
 use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
 use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics};
@@ -772,11 +772,10 @@ fn trait_impls_for<'a>(
     module: DefId,
 ) -> FxHashSet<(DefId, DefId)> {
     let tcx = cx.tcx;
-    let iter = tcx.doc_link_traits_in_scope(module).iter().flat_map(|&trait_| {
-        trace!("considering explicit impl for trait {:?}", trait_);
+    let mut impls = FxHashSet::default();
 
-        // Look at each trait implementation to see if it's an impl for `did`
-        tcx.find_map_relevant_impl(trait_, ty, TreatProjections::ForLookup, |impl_| {
+    for &trait_ in tcx.doc_link_traits_in_scope(module) {
+        tcx.for_each_relevant_impl(trait_, ty, |impl_| {
             let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
             // Check if these are the same type.
             let impl_type = trait_ref.skip_binder().self_ty();
@@ -800,10 +799,13 @@ fn trait_impls_for<'a>(
                     _ => false,
                 };
 
-            if saw_impl { Some((impl_, trait_)) } else { None }
-        })
-    });
-    iter.collect()
+            if saw_impl {
+                impls.insert((impl_, trait_));
+            }
+        });
+    }
+
+    impls
 }
 
 /// Check for resolve collisions between a trait and its derive.
diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs
index 9f113c72b93..d2e9c324af8 100644
--- a/src/tools/build_helper/src/ci.rs
+++ b/src/tools/build_helper/src/ci.rs
@@ -38,3 +38,27 @@ impl CiEnv {
         }
     }
 }
+
+pub mod gha {
+    /// All github actions log messages from this call to the Drop of the return value
+    /// will be grouped and hidden by default in logs. Note that nesting these does
+    /// not really work.
+    pub fn group(name: impl std::fmt::Display) -> Group {
+        if std::env::var_os("GITHUB_ACTIONS").is_some() {
+            eprintln!("::group::{name}");
+        }
+        Group(())
+    }
+
+    /// A guard that closes the current github actions log group on drop.
+    #[must_use]
+    pub struct Group(());
+
+    impl Drop for Group {
+        fn drop(&mut self) {
+            if std::env::var_os("GITHUB_ACTIONS").is_some() {
+                eprintln!("::endgroup::");
+            }
+        }
+    }
+}
diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs
index 51c000b82ea..664e697c2a5 100644
--- a/tests/codegen/intrinsics/transmute.rs
+++ b/tests/codegen/intrinsics/transmute.rs
@@ -8,10 +8,10 @@
 #![feature(inline_const)]
 #![allow(unreachable_code)]
 
-use std::mem::{transmute, MaybeUninit};
+use std::mem::MaybeUninit;
+use std::intrinsics::{transmute, transmute_unchecked};
 
-// Some of the cases here are statically rejected by `mem::transmute`, so
-// we need to generate custom MIR for those cases to get to codegen.
+// Some of these need custom MIR to not get removed by MIR optimizations.
 use std::intrinsics::mir::*;
 
 enum Never {}
@@ -30,59 +30,35 @@ pub struct Aggregate8(u8);
 
 // CHECK-LABEL: @check_bigger_size(
 #[no_mangle]
-#[custom_mir(dialect = "runtime", phase = "initial")]
 pub unsafe fn check_bigger_size(x: u16) -> u32 {
     // CHECK: call void @llvm.trap
-    mir!{
-        {
-            RET = CastTransmute(x);
-            Return()
-        }
-    }
+    transmute_unchecked(x)
 }
 
 // CHECK-LABEL: @check_smaller_size(
 #[no_mangle]
-#[custom_mir(dialect = "runtime", phase = "initial")]
 pub unsafe fn check_smaller_size(x: u32) -> u16 {
     // CHECK: call void @llvm.trap
-    mir!{
-        {
-            RET = CastTransmute(x);
-            Return()
-        }
-    }
+    transmute_unchecked(x)
 }
 
 // CHECK-LABEL: @check_smaller_array(
 #[no_mangle]
-#[custom_mir(dialect = "runtime", phase = "initial")]
 pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] {
     // CHECK: call void @llvm.trap
-    mir!{
-        {
-            RET = CastTransmute(x);
-            Return()
-        }
-    }
+    transmute_unchecked(x)
 }
 
 // CHECK-LABEL: @check_bigger_array(
 #[no_mangle]
-#[custom_mir(dialect = "runtime", phase = "initial")]
 pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] {
     // CHECK: call void @llvm.trap
-    mir!{
-        {
-            RET = CastTransmute(x);
-            Return()
-        }
-    }
+    transmute_unchecked(x)
 }
 
 // CHECK-LABEL: @check_to_uninhabited(
 #[no_mangle]
-#[custom_mir(dialect = "runtime", phase = "initial")]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
 pub unsafe fn check_to_uninhabited(x: u16) -> BigNever {
     // CHECK: call void @llvm.trap
     mir!{
@@ -95,7 +71,7 @@ pub unsafe fn check_to_uninhabited(x: u16) -> BigNever {
 
 // CHECK-LABEL: @check_from_uninhabited(
 #[no_mangle]
-#[custom_mir(dialect = "runtime", phase = "initial")]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
 pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
     // CHECK: ret i16 poison
     mir!{
diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs
new file mode 100644
index 00000000000..b1a0f39962b
--- /dev/null
+++ b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs
@@ -0,0 +1,16 @@
+#![feature(associated_const_equality)]
+
+// Issue 110549
+
+pub trait TraitWAssocConst {
+    const A: usize;
+}
+
+fn foo<T: TraitWAssocConst<A = 32>>() {}
+
+fn bar<T: TraitWAssocConst>() {
+    foo::<T>();
+    //~^ ERROR type mismatch resolving `<T as TraitWAssocConst>::A == 32`
+}
+
+fn main() {}
diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr b/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr
new file mode 100644
index 00000000000..8175e510a09
--- /dev/null
+++ b/tests/ui/associated-consts/projection-unspecified-but-bounded.stderr
@@ -0,0 +1,17 @@
+error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 32`
+  --> $DIR/projection-unspecified-but-bounded.rs:12:11
+   |
+LL |     foo::<T>();
+   |           ^ expected `32`, found `<T as TraitWAssocConst>::A`
+   |
+   = note: expected constant `32`
+              found constant `<T as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+  --> $DIR/projection-unspecified-but-bounded.rs:9:28
+   |
+LL | fn foo<T: TraitWAssocConst<A = 32>>() {}
+   |                            ^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/proc-macro/test-same-crate.rs b/tests/ui/proc-macro/test-same-crate.rs
new file mode 100644
index 00000000000..c13f384fa3a
--- /dev/null
+++ b/tests/ui/proc-macro/test-same-crate.rs
@@ -0,0 +1,16 @@
+// compile-flags: --test
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn mac(input: TokenStream) -> TokenStream { loop {} }
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn t() { crate::mac!(A) }
+    //~^ ERROR can't use a procedural macro from the same crate that defines it
+    //~| HELP you can define integration tests in a directory named `tests`
+}
diff --git a/tests/ui/proc-macro/test-same-crate.stderr b/tests/ui/proc-macro/test-same-crate.stderr
new file mode 100644
index 00000000000..5d12e149c3c
--- /dev/null
+++ b/tests/ui/proc-macro/test-same-crate.stderr
@@ -0,0 +1,10 @@
+error: can't use a procedural macro from the same crate that defines it
+  --> $DIR/test-same-crate.rs:13:14
+   |
+LL |     fn t() { crate::mac!(A) }
+   |              ^^^^^^^^^^
+   |
+   = help: you can define integration tests in a directory named `tests`
+
+error: aborting due to previous error
+