about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_data_structures/src/sync.rs176
-rw-r--r--compiler/rustc_data_structures/src/sync/parallel.rs188
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs10
-rw-r--r--compiler/rustc_interface/src/queries.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs7
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs13
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/tools/miri/src/bin/miri.rs4
-rw-r--r--tests/codegen/issues/issue-115385-llvm-jump-threading.rs46
-rw-r--r--tests/run-make-fulldeps/obtain-borrowck/driver.rs3
-rw-r--r--tests/run-make/lto-linkage-used-attr/Makefile9
-rw-r--r--tests/run-make/lto-linkage-used-attr/lib.rs50
-rw-r--r--tests/run-make/lto-linkage-used-attr/main.rs10
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs6
-rw-r--r--tests/ui/abi/compatibility.rs10
-rw-r--r--tests/ui/layout/homogeneous-aggr-transparent.rs44
-rw-r--r--tests/ui/layout/homogeneous-aggr-transparent.stderr32
-rw-r--r--tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs8
-rw-r--r--tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr16
25 files changed, 442 insertions, 196 deletions
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 63f137516bd..cca043ba0d1 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -41,12 +41,9 @@
 //! [^2] `MTLockRef` is a typedef.
 
 pub use crate::marker::*;
-use parking_lot::Mutex;
-use std::any::Any;
 use std::collections::HashMap;
 use std::hash::{BuildHasher, Hash};
 use std::ops::{Deref, DerefMut};
-use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
 
 mod lock;
 pub use lock::{Lock, LockGuard, Mode};
@@ -54,6 +51,11 @@ pub use lock::{Lock, LockGuard, Mode};
 mod worker_local;
 pub use worker_local::{Registry, WorkerLocal};
 
+mod parallel;
+#[cfg(parallel_compiler)]
+pub use parallel::scope;
+pub use parallel::{join, par_for_each_in, par_map, parallel_guard};
+
 pub use std::sync::atomic::Ordering;
 pub use std::sync::atomic::Ordering::SeqCst;
 
@@ -107,37 +109,6 @@ mod mode {
 
 pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
 
-/// A guard used to hold panics that occur during a parallel section to later by unwound.
-/// This is used for the parallel compiler to prevent fatal errors from non-deterministically
-/// hiding errors by ensuring that everything in the section has completed executing before
-/// continuing with unwinding. It's also used for the non-parallel code to ensure error message
-/// output match the parallel compiler for testing purposes.
-pub struct ParallelGuard {
-    panic: Mutex<Option<Box<dyn Any + std::marker::Send + 'static>>>,
-}
-
-impl ParallelGuard {
-    pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
-        catch_unwind(AssertUnwindSafe(f))
-            .map_err(|err| {
-                *self.panic.lock() = Some(err);
-            })
-            .ok()
-    }
-}
-
-/// This gives access to a fresh parallel guard in the closure and will unwind any panics
-/// caught in it after the closure returns.
-#[inline]
-pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
-    let guard = ParallelGuard { panic: Mutex::new(None) };
-    let ret = f(&guard);
-    if let Some(panic) = guard.panic.into_inner() {
-        resume_unwind(panic);
-    }
-    ret
-}
-
 cfg_if! {
     if #[cfg(not(parallel_compiler))] {
         use std::ops::Add;
@@ -229,44 +200,6 @@ cfg_if! {
         pub type AtomicU32 = Atomic<u32>;
         pub type AtomicU64 = Atomic<u64>;
 
-        pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
-            where A: FnOnce() -> RA,
-                  B: FnOnce() -> RB
-        {
-            let (a, b) = parallel_guard(|guard| {
-                let a = guard.run(oper_a);
-                let b = guard.run(oper_b);
-                (a, b)
-            });
-            (a.unwrap(), b.unwrap())
-        }
-
-        #[macro_export]
-        macro_rules! parallel {
-            ($($blocks:block),*) => {{
-                $crate::sync::parallel_guard(|guard| {
-                    $(guard.run(|| $blocks);)*
-                });
-            }}
-        }
-
-        pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) {
-            parallel_guard(|guard| {
-                t.into_iter().for_each(|i| {
-                    guard.run(|| for_each(i));
-                });
-            })
-        }
-
-        pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
-            t: T,
-            mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
-        ) -> C {
-            parallel_guard(|guard| {
-                t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
-            })
-        }
-
         pub use std::rc::Rc as Lrc;
         pub use std::rc::Weak as Weak;
         pub use std::cell::Ref as ReadGuard;
@@ -372,105 +305,6 @@ cfg_if! {
 
         use std::thread;
 
-        #[inline]
-        pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
-        where
-            A: FnOnce() -> RA + DynSend,
-            B: FnOnce() -> RB + DynSend,
-        {
-            if mode::is_dyn_thread_safe() {
-                let oper_a = FromDyn::from(oper_a);
-                let oper_b = FromDyn::from(oper_b);
-                let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()()));
-                (a.into_inner(), b.into_inner())
-            } else {
-                let (a, b) = parallel_guard(|guard| {
-                    let a = guard.run(oper_a);
-                    let b = guard.run(oper_b);
-                    (a, b)
-                });
-                (a.unwrap(), b.unwrap())
-            }
-        }
-
-        // This function only works when `mode::is_dyn_thread_safe()`.
-        pub fn scope<'scope, OP, R>(op: OP) -> R
-        where
-            OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
-            R: DynSend,
-        {
-            let op = FromDyn::from(op);
-            rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
-        }
-
-        /// Runs a list of blocks in parallel. The first block is executed immediately on
-        /// the current thread. Use that for the longest running block.
-        #[macro_export]
-        macro_rules! parallel {
-            (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
-                parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
-            };
-            (impl $fblock:block [$($blocks:expr,)*] []) => {
-                ::rustc_data_structures::sync::scope(|s| {
-                    $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks);
-                    s.spawn(move |_| block.into_inner()());)*
-                    (|| $fblock)();
-                });
-            };
-            ($fblock:block, $($blocks:block),*) => {
-                if rustc_data_structures::sync::is_dyn_thread_safe() {
-                    // Reverse the order of the later blocks since Rayon executes them in reverse order
-                    // when using a single thread. This ensures the execution order matches that
-                    // of a single threaded rustc.
-                    parallel!(impl $fblock [] [$($blocks),*]);
-                } else {
-                    $crate::sync::parallel_guard(|guard| {
-                        guard.run(|| $fblock);
-                        $(guard.run(|| $blocks);)*
-                    });
-                }
-            };
-        }
-
-        use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
-
-        pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
-            t: T,
-            for_each: impl Fn(I) + DynSync + DynSend
-        ) {
-            parallel_guard(|guard| {
-                if mode::is_dyn_thread_safe() {
-                    let for_each = FromDyn::from(for_each);
-                    t.into_par_iter().for_each(|i| {
-                        guard.run(|| for_each(i));
-                    });
-                } else {
-                    t.into_iter().for_each(|i| {
-                        guard.run(|| for_each(i));
-                    });
-                }
-            });
-        }
-
-        pub fn par_map<
-            I,
-            T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
-            R: std::marker::Send,
-            C: FromIterator<R> + FromParallelIterator<R>
-        >(
-            t: T,
-            map: impl Fn(I) -> R + DynSync + DynSend
-        ) -> C {
-            parallel_guard(|guard| {
-                if mode::is_dyn_thread_safe() {
-                    let map = FromDyn::from(map);
-                    t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
-                } else {
-                    t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
-                }
-            })
-        }
-
         /// This makes locks panic if they are already held.
         /// It is only useful when you are running in a single thread
         const ERROR_CHECKING: bool = false;
diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs
new file mode 100644
index 00000000000..1944ddfb710
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sync/parallel.rs
@@ -0,0 +1,188 @@
+//! This module defines parallel operations that are implemented in
+//! one way for the serial compiler, and another way the parallel compiler.
+
+#![allow(dead_code)]
+
+use parking_lot::Mutex;
+use std::any::Any;
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+#[cfg(not(parallel_compiler))]
+pub use disabled::*;
+#[cfg(parallel_compiler)]
+pub use enabled::*;
+
+/// A guard used to hold panics that occur during a parallel section to later by unwound.
+/// This is used for the parallel compiler to prevent fatal errors from non-deterministically
+/// hiding errors by ensuring that everything in the section has completed executing before
+/// continuing with unwinding. It's also used for the non-parallel code to ensure error message
+/// output match the parallel compiler for testing purposes.
+pub struct ParallelGuard {
+    panic: Mutex<Option<Box<dyn Any + Send + 'static>>>,
+}
+
+impl ParallelGuard {
+    pub fn run<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
+        catch_unwind(AssertUnwindSafe(f))
+            .map_err(|err| {
+                *self.panic.lock() = Some(err);
+            })
+            .ok()
+    }
+}
+
+/// This gives access to a fresh parallel guard in the closure and will unwind any panics
+/// caught in it after the closure returns.
+#[inline]
+pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
+    let guard = ParallelGuard { panic: Mutex::new(None) };
+    let ret = f(&guard);
+    if let Some(panic) = guard.panic.into_inner() {
+        resume_unwind(panic);
+    }
+    ret
+}
+
+mod disabled {
+    use crate::sync::parallel_guard;
+
+    #[macro_export]
+    #[cfg(not(parallel_compiler))]
+    macro_rules! parallel {
+        ($($blocks:block),*) => {{
+            $crate::sync::parallel_guard(|guard| {
+                $(guard.run(|| $blocks);)*
+            });
+        }}
+    }
+
+    pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+    where
+        A: FnOnce() -> RA,
+        B: FnOnce() -> RB,
+    {
+        let (a, b) = parallel_guard(|guard| {
+            let a = guard.run(oper_a);
+            let b = guard.run(oper_b);
+            (a, b)
+        });
+        (a.unwrap(), b.unwrap())
+    }
+
+    pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item)) {
+        parallel_guard(|guard| {
+            t.into_iter().for_each(|i| {
+                guard.run(|| for_each(i));
+            });
+        })
+    }
+
+    pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
+        t: T,
+        mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
+    ) -> C {
+        parallel_guard(|guard| t.into_iter().filter_map(|i| guard.run(|| map(i))).collect())
+    }
+}
+
+#[cfg(parallel_compiler)]
+mod enabled {
+    use crate::sync::{mode, parallel_guard, DynSend, DynSync, FromDyn};
+
+    /// Runs a list of blocks in parallel. The first block is executed immediately on
+    /// the current thread. Use that for the longest running block.
+    #[macro_export]
+    macro_rules! parallel {
+        (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
+            parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
+        };
+        (impl $fblock:block [$($blocks:expr,)*] []) => {
+            ::rustc_data_structures::sync::scope(|s| {
+                $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks);
+                s.spawn(move |_| block.into_inner()());)*
+                (|| $fblock)();
+            });
+        };
+        ($fblock:block, $($blocks:block),*) => {
+            if rustc_data_structures::sync::is_dyn_thread_safe() {
+                // Reverse the order of the later blocks since Rayon executes them in reverse order
+                // when using a single thread. This ensures the execution order matches that
+                // of a single threaded rustc.
+                parallel!(impl $fblock [] [$($blocks),*]);
+            } else {
+                $crate::sync::parallel_guard(|guard| {
+                    guard.run(|| $fblock);
+                    $(guard.run(|| $blocks);)*
+                });
+            }
+        };
+    }
+
+    // This function only works when `mode::is_dyn_thread_safe()`.
+    pub fn scope<'scope, OP, R>(op: OP) -> R
+    where
+        OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
+        R: DynSend,
+    {
+        let op = FromDyn::from(op);
+        rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
+    }
+
+    #[inline]
+    pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
+    where
+        A: FnOnce() -> RA + DynSend,
+        B: FnOnce() -> RB + DynSend,
+    {
+        if mode::is_dyn_thread_safe() {
+            let oper_a = FromDyn::from(oper_a);
+            let oper_b = FromDyn::from(oper_b);
+            let (a, b) = rayon::join(
+                move || FromDyn::from(oper_a.into_inner()()),
+                move || FromDyn::from(oper_b.into_inner()()),
+            );
+            (a.into_inner(), b.into_inner())
+        } else {
+            super::disabled::join(oper_a, oper_b)
+        }
+    }
+
+    use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
+
+    pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
+        t: T,
+        for_each: impl Fn(I) + DynSync + DynSend,
+    ) {
+        parallel_guard(|guard| {
+            if mode::is_dyn_thread_safe() {
+                let for_each = FromDyn::from(for_each);
+                t.into_par_iter().for_each(|i| {
+                    guard.run(|| for_each(i));
+                });
+            } else {
+                t.into_iter().for_each(|i| {
+                    guard.run(|| for_each(i));
+                });
+            }
+        });
+    }
+
+    pub fn par_map<
+        I,
+        T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
+        R: std::marker::Send,
+        C: FromIterator<R> + FromParallelIterator<R>,
+    >(
+        t: T,
+        map: impl Fn(I) -> R + DynSync + DynSend,
+    ) -> C {
+        parallel_guard(|guard| {
+            if mode::is_dyn_thread_safe() {
+                let map = FromDyn::from(map);
+                t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
+            } else {
+                t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
+            }
+        })
+    }
+}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index e56347ab38e..f38adefa7c0 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -162,9 +162,10 @@ pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T
 pub trait Callbacks {
     /// Called before creating the compiler instance
     fn config(&mut self, _config: &mut interface::Config) {}
-    /// Called after parsing. Return value instructs the compiler whether to
+    /// Called after parsing the crate root. Submodules are not yet parsed when
+    /// this callback is called. Return value instructs the compiler whether to
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
-    fn after_parsing<'tcx>(
+    fn after_crate_root_parsing<'tcx>(
         &mut self,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
@@ -184,7 +185,6 @@ pub trait Callbacks {
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
@@ -407,7 +407,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            if callbacks.after_parsing(compiler, queries) == Compilation::Stop {
+            if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
@@ -445,7 +445,7 @@ fn run_compiler(
 
             queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
 
-            if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop {
+            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 29a5837eb7c..449d7a29590 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -114,6 +114,7 @@ impl<'tcx> Queries<'tcx> {
             .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
     }
 
+    #[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."]
     pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
         self.pre_configure.compute(|| {
             let mut krate = self.parse()?.steal();
@@ -171,6 +172,7 @@ impl<'tcx> Queries<'tcx> {
     pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
         self.gcx.compute(|| {
             let sess = self.session();
+            #[allow(deprecated)]
             let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
 
             // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index c38c6337b7b..57c2e289f20 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -923,7 +923,12 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
         }
 
         // Return the nullable type this Option-like enum can be safely represented with.
-        let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi;
+        let field_ty_layout = tcx.layout_of(param_env.and(field_ty));
+        if field_ty_layout.is_err() && !field_ty.has_non_region_param() {
+            bug!("should be able to compute the layout of non-polymorphic type");
+        }
+
+        let field_ty_abi = &field_ty_layout.ok()?.abi;
         if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
             match field_ty_scalar.valid_range(&tcx) {
                 WrappingRange { start: 0, end }
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 73b8e060dd8..4203990ab05 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -16,7 +16,6 @@ use rustc_driver::{Callbacks, Compilation, RunCompiler};
 use rustc_interface::{interface, Queries};
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::EarlyErrorHandler;
 pub use rustc_span::def_id::{CrateNum, DefId};
 
 fn with_tables<R>(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R {
@@ -233,7 +232,6 @@ where
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 2250891028a..321ee790509 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -84,7 +84,7 @@ impl<'tcx> Context for Tables<'tcx> {
 
     fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body {
         let def_id = self[item];
-        let mir = self.tcx.optimized_mir(def_id);
+        let mir = self.tcx.instance_mir(ty::InstanceDef::Item(def_id));
         stable_mir::mir::Body {
             blocks: mir
                 .basic_blocks
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 5d75974279e..1a4a46ceb40 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -382,8 +382,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
     /// only a single type (e.g., `(u32, u32)`). Such aggregates are often
     /// special-cased in ABIs.
     ///
-    /// Note: We generally ignore fields of zero-sized type when computing
-    /// this value (see #56877).
+    /// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
     ///
     /// This is public so that it can be used in unit tests, but
     /// should generally only be relevant to the ABI details of
@@ -441,12 +440,18 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
                         let mut total = start;
 
                         for i in 0..layout.fields.count() {
+                            let field = layout.field(cx, i);
+                            if field.is_1zst() {
+                                // No data here and no impact on layout, can be ignored.
+                                // (We might be able to also ignore all aligned ZST but that's less clear.)
+                                continue;
+                            }
+
                             if !is_union && total != layout.fields.offset(i) {
+                                // This field isn't just after the previous one we considered, abort.
                                 return Err(Heterogeneous);
                             }
 
-                            let field = layout.field(cx, i);
-
                             result = result.merge(field.homogeneous_aggregate(cx)?)?;
 
                             // Keep track of the offset (without padding).
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 2751bdcef125468ea2ee006c11992cd1405aebe
+Subproject 34fca48ed284525b2f124bf93c51af36d668549
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 388750b081c0893c275044d37203f97709e058b
+Subproject e3f3af69dce71cd37a785bccb7e58449197d940
diff --git a/src/doc/reference b/src/doc/reference
-Subproject d43038932adeb16ada80e206d4c073d85129810
+Subproject ee7c676fd6e287459cb407337652412c990686c
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 07e0df2f006e59d171c6bf3cafa9d61dbeb520d
+Subproject c954202c1e1720cba5628f99543cc01188c7d6f
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject b123ab4754127d822ffb38349ce0fbf561f1b2f
+Subproject 08bb147d51e815b96e8db7ba4cf870f201c11ff
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 97718f1f4a9..1e9219d4bb2 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -59,7 +59,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
 
     fn after_analysis<'tcx>(
         &mut self,
-        handler: &EarlyErrorHandler,
         _: &rustc_interface::interface::Compiler,
         queries: &'tcx rustc_interface::Queries<'tcx>,
     ) -> Compilation {
@@ -68,7 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 tcx.sess.fatal("miri cannot be run on programs that fail compilation");
             }
 
-            init_late_loggers(handler, tcx);
+            let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format);
+            init_late_loggers(&handler, tcx);
             if !tcx.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
             }
diff --git a/tests/codegen/issues/issue-115385-llvm-jump-threading.rs b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs
new file mode 100644
index 00000000000..142e3596d96
--- /dev/null
+++ b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs
@@ -0,0 +1,46 @@
+// compile-flags: -O -Ccodegen-units=1
+
+#![crate_type = "lib"]
+
+#[repr(i64)]
+pub enum Boolean {
+    False = 0,
+    True = 1,
+}
+
+impl Clone for Boolean {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Copy for Boolean {}
+
+extern "C" {
+    fn set_value(foo: *mut i64);
+    fn bar();
+}
+
+pub fn foo(x: bool) {
+    let mut foo = core::mem::MaybeUninit::<i64>::uninit();
+    unsafe {
+        set_value(foo.as_mut_ptr());
+    }
+
+    if x {
+        let l1 = unsafe { *foo.as_mut_ptr().cast::<Boolean>() };
+        if matches!(l1, Boolean::False) {
+            unsafe {
+                *foo.as_mut_ptr() = 0;
+            }
+        }
+    }
+
+    let l2 = unsafe { *foo.as_mut_ptr() };
+    if l2 == 2 {
+        // CHECK: call void @bar
+        unsafe {
+            bar();
+        }
+    }
+}
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index 04c551cf4bb..b59a65a713f 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -27,7 +27,7 @@ use rustc_interface::{Config, Queries};
 use rustc_middle::query::queries::mir_borrowck::ProvidedValue;
 use rustc_middle::query::{ExternProviders, Providers};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::{Session, EarlyErrorHandler};
+use rustc_session::Session;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::thread_local;
@@ -58,7 +58,6 @@ impl rustc_driver::Callbacks for CompilerCalls {
     // the result.
     fn after_analysis<'tcx>(
         &mut self,
-        _handler: &EarlyErrorHandler,
         compiler: &Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/tests/run-make/lto-linkage-used-attr/Makefile b/tests/run-make/lto-linkage-used-attr/Makefile
new file mode 100644
index 00000000000..e78b83890ed
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/Makefile
@@ -0,0 +1,9 @@
+include ../tools.mk
+
+# Verify that the impl_* symbols are preserved. #108030
+# only-x86_64-unknown-linux-gnu
+# min-llvm-version: 17
+
+all:
+	$(RUSTC) -Cdebuginfo=0 -Copt-level=3 lib.rs
+	$(RUSTC) -Clto=fat -Cdebuginfo=0 -Copt-level=3 main.rs
diff --git a/tests/run-make/lto-linkage-used-attr/lib.rs b/tests/run-make/lto-linkage-used-attr/lib.rs
new file mode 100644
index 00000000000..0a92ea9cd22
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/lib.rs
@@ -0,0 +1,50 @@
+#![crate_type = "rlib"]
+#![crate_type = "cdylib"]
+
+#[macro_export]
+macro_rules! asm_func {
+    ($name:expr, $body:expr $(, $($args:tt)*)?) => {
+        core::arch::global_asm!(
+            concat!(
+                ".p2align 4\n",
+                ".hidden ", $name, "\n",
+                ".global ", $name, "\n",
+                ".type ", $name, ",@function\n",
+                $name, ":\n",
+                $body,
+                ".size ", $name, ",.-", $name,
+            )
+            $(, $($args)*)?
+        );
+    };
+}
+
+macro_rules! libcall_trampoline {
+    ($libcall:ident ; $libcall_impl:ident) => {
+        asm_func!(
+            stringify!($libcall),
+            concat!(
+                "
+                   .cfi_startproc simple
+                   .cfi_def_cfa_offset 0
+                    jmp {}
+                    .cfi_endproc
+                ",
+            ),
+            sym $libcall_impl
+        );
+    };
+}
+
+pub mod trampolines {
+    extern "C" {
+        pub fn table_fill_funcref();
+        pub fn table_fill_externref();
+    }
+
+    unsafe extern "C" fn impl_table_fill_funcref() {}
+    unsafe extern "C" fn impl_table_fill_externref() {}
+
+    libcall_trampoline!(table_fill_funcref ; impl_table_fill_funcref);
+    libcall_trampoline!(table_fill_externref ; impl_table_fill_externref);
+}
diff --git a/tests/run-make/lto-linkage-used-attr/main.rs b/tests/run-make/lto-linkage-used-attr/main.rs
new file mode 100644
index 00000000000..256b02e5b0b
--- /dev/null
+++ b/tests/run-make/lto-linkage-used-attr/main.rs
@@ -0,0 +1,10 @@
+extern crate lib;
+
+use lib::trampolines::*;
+
+fn main() {
+    unsafe {
+        table_fill_externref();
+        table_fill_funcref();
+    }
+}
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index d55eae86f07..a11720c4b55 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -154,6 +154,10 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> {
         }
     }
 
+    let foo_const = get_item(tcx, &items, (DefKind::Const, "FOO")).unwrap();
+    // Ensure we don't panic trying to get the body of a constant.
+    foo_const.body();
+
     ControlFlow::Continue(())
 }
 
@@ -191,6 +195,8 @@ fn generate_input(path: &str) -> std::io::Result<()> {
     write!(
         file,
         r#"
+    pub const FOO: u32 = 1 + 2;
+
     fn generic<T, const U: usize>(t: T) -> [(); U] {{
         _ = t;
         [(); U]
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 86fb365507a..bfe0a5cf81d 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -106,6 +106,8 @@ test_transparent!(zst, Zst);
 test_transparent!(unit, ());
 test_transparent!(pair, (i32, f32)); // mixing in some floats since they often get special treatment
 test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit
+test_transparent!(triple_f32, (f32, f32, f32)); // homogeneous case
+test_transparent!(triple_f64, (f64, f64, f64));
 test_transparent!(tuple, (i32, f32, i64, f64));
 test_transparent!(empty_array, [u32; 0]);
 test_transparent!(empty_1zst_array, [u8; 0]);
@@ -113,14 +115,6 @@ test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit
 test_transparent!(large_array, [i32; 16]);
 test_transparent!(enum_, Option<i32>);
 test_transparent!(enum_niched, Option<&'static i32>);
-// Pure-float types that are not ScalarPair seem to be tricky.
-// FIXME: <https://github.com/rust-lang/rust/issues/115664>
-#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
-mod tricky {
-    use super::*;
-    test_transparent!(triple_f32, (f32, f32, f32));
-    test_transparent!(triple_f64, (f64, f64, f64));
-}
 
 // RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
 macro_rules! test_nonnull {
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.rs b/tests/ui/layout/homogeneous-aggr-transparent.rs
new file mode 100644
index 00000000000..9703d2bf294
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-transparent.rs
@@ -0,0 +1,44 @@
+#![feature(rustc_attrs)]
+#![feature(transparent_unions)]
+use std::marker::PhantomData;
+
+// Regression test for #115664. We want to ensure that `repr(transparent)` wrappers do not affect
+// the result of `homogeneous_aggregate`.
+
+type Tuple = (f32, f32, f32);
+
+struct Zst;
+
+#[repr(transparent)]
+struct Wrapper1<T>(T);
+#[repr(transparent)]
+struct Wrapper2<T>((), Zst, T);
+#[repr(transparent)]
+struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
+#[repr(transparent)]
+union WrapperUnion<T: Copy> {
+    nothing: (),
+    something: T,
+}
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test0 = Tuple;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test1 = Wrapper1<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test2 = Wrapper2<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test3 = Wrapper3<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+#[rustc_layout(homogeneous_aggregate)]
+pub type Test4 = WrapperUnion<Tuple>;
+//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+
+fn main() {}
diff --git a/tests/ui/layout/homogeneous-aggr-transparent.stderr b/tests/ui/layout/homogeneous-aggr-transparent.stderr
new file mode 100644
index 00000000000..99eb703ac82
--- /dev/null
+++ b/tests/ui/layout/homogeneous-aggr-transparent.stderr
@@ -0,0 +1,32 @@
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:25:1
+   |
+LL | pub type Test0 = Tuple;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:29:1
+   |
+LL | pub type Test1 = Wrapper1<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:33:1
+   |
+LL | pub type Test2 = Wrapper2<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:37:1
+   |
+LL | pub type Test3 = Wrapper3<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
+  --> $DIR/homogeneous-aggr-transparent.rs:41:1
+   |
+LL | pub type Test4 = WrapperUnion<Tuple>;
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs
new file mode 100644
index 00000000000..ca08eb23a57
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs
@@ -0,0 +1,8 @@
+#![deny(improper_ctypes_definitions)]
+
+extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
+    //~^ ERROR `extern` fn uses type `Option<&T>`, which is not FFI-safe
+    None
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr
new file mode 100644
index 00000000000..f59fb3cc750
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr
@@ -0,0 +1,16 @@
+error: `extern` fn uses type `Option<&T>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45
+   |
+LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
+   |                                             ^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9
+   |
+LL | #![deny(improper_ctypes_definitions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+