summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-01-03 00:49:40 +0000
committerbors <bors@rust-lang.org>2025-01-03 00:49:40 +0000
commit953a5caef005993f93d8fe9baa344cc2591496c2 (patch)
treed37e31ad625b41a460d0ad445f6d25521d09872c
parent0857a8e32cd55fca2e6c648e586f9ce46c22eb42 (diff)
parentf72c836093960d1f2027e4316ad099da049ceaa0 (diff)
downloadrust-953a5caef005993f93d8fe9baa344cc2591496c2.tar.gz
rust-953a5caef005993f93d8fe9baa344cc2591496c2.zip
Auto merge of #135048 - cuviper:beta-next, r=cuviper
[beta] backports

- Do not call `extern_crate` on current trait on crate mismatch errors #133585
- Correctly handle comments in attributes in doctests source code #134260
- Correctly document CTFE behavior of is_null and methods that call is_null. #134325
- Make sure we handle `backwards_incompatible_lint` drops appropriately in drop elaboration #134486
- Bump compiler `cc` to 1.2.5 #134505
- Handle `DropKind::ForLint` in coroutines correctly #134575
- docs: inline `std::ffi::c_str` types to `std::ffi` #134791
- docs: inline `alloc::ffi::c_str` types to `alloc::ffi` #134851

r? cuviper
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml4
-rw-r--r--compiler/rustc_llvm/Cargo.toml4
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs148
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs4
-rw-r--r--library/alloc/src/ffi/mod.rs2
-rw-r--r--library/core/src/ffi/mod.rs4
-rw-r--r--library/core/src/ptr/const_ptr.rs38
-rw-r--r--library/core/src/ptr/mut_ptr.rs58
-rw-r--r--library/core/src/ptr/non_null.rs7
-rw-r--r--library/std/src/ffi/mod.rs10
-rw-r--r--src/librustdoc/doctest/make.rs60
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs6
-rw-r--r--tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir159
-rw-r--r--tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir159
-rw-r--r--tests/mir-opt/tail_expr_drop_order_unwind.rs36
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs14
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs6
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr29
-rw-r--r--tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs31
-rw-r--r--tests/run-make/crate-loading/multiple-dep-versions.stderr113
-rw-r--r--tests/run-make/crate-loading/rmake.rs89
-rw-r--r--tests/rustdoc-ui/doctest/comment-in-attr-134221-2.rs15
-rw-r--r--tests/rustdoc-ui/doctest/comment-in-attr-134221-2.stdout31
-rw-r--r--tests/rustdoc-ui/doctest/comment-in-attr-134221.rs27
-rw-r--r--tests/rustdoc-ui/doctest/comment-in-attr-134221.stdout50
-rw-r--r--tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs29
-rw-r--r--tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr52
28 files changed, 1034 insertions, 155 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e4dcf13a84b..f34baa8077d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -411,9 +411,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.1.34"
+version = "1.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9"
+checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
 dependencies = [
  "shlex",
 ]
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index b898cfec796..eb9a8ebbd3b 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -8,7 +8,9 @@ edition = "2021"
 ar_archive_writer = "0.4.2"
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
-cc = "1.1.23"
+# Pinned so `cargo update` bumps don't cause breakage. Please also update the
+# `cc` in `rustc_llvm` if you update the `cc` here.
+cc = "=1.2.5"
 either = "1.5.0"
 itertools = "0.12"
 jobserver = "0.1.28"
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index b29d6b79250..79a6454dbb9 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -10,5 +10,7 @@ libc = "0.2.73"
 
 [build-dependencies]
 # tidy-alphabetical-start
-cc = "1.1.23"
+# Pinned so `cargo update` bumps don't cause breakage. Please also update the
+# pinned `cc` in `rustc_codegen_ssa` if you update `cc` here.
+cc = "=1.2.5"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 636e47b7ad2..c2af064925c 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -151,15 +151,13 @@ struct DropData {
 
     /// Whether this is a value Drop or a StorageDead.
     kind: DropKind,
-
-    /// Whether this is a backwards-incompatible drop lint
-    backwards_incompatible_lint: bool,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub(crate) enum DropKind {
     Value,
     Storage,
+    ForLint,
 }
 
 #[derive(Debug)]
@@ -248,7 +246,7 @@ impl Scope {
     /// use of optimizations in the MIR coroutine transform.
     fn needs_cleanup(&self) -> bool {
         self.drops.iter().any(|drop| match drop.kind {
-            DropKind::Value => true,
+            DropKind::Value | DropKind::ForLint => true,
             DropKind::Storage => false,
         })
     }
@@ -277,12 +275,8 @@ impl DropTree {
         // represents the block in the tree that should be jumped to once all
         // of the required drops have been performed.
         let fake_source_info = SourceInfo::outermost(DUMMY_SP);
-        let fake_data = DropData {
-            source_info: fake_source_info,
-            local: Local::MAX,
-            kind: DropKind::Storage,
-            backwards_incompatible_lint: false,
-        };
+        let fake_data =
+            DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
         let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]);
         Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() }
     }
@@ -411,6 +405,27 @@ impl DropTree {
                     };
                     cfg.terminate(block, drop_node.data.source_info, terminator);
                 }
+                DropKind::ForLint => {
+                    let stmt = Statement {
+                        source_info: drop_node.data.source_info,
+                        kind: StatementKind::BackwardIncompatibleDropHint {
+                            place: Box::new(drop_node.data.local.into()),
+                            reason: BackwardIncompatibleDropReason::Edition2024,
+                        },
+                    };
+                    cfg.push(block, stmt);
+                    let target = blocks[drop_node.next].unwrap();
+                    if target != block {
+                        // Diagnostics don't use this `Span` but debuginfo
+                        // might. Since we don't want breakpoints to be placed
+                        // here, especially when this is on an unwind path, we
+                        // use `DUMMY_SP`.
+                        let source_info =
+                            SourceInfo { span: DUMMY_SP, ..drop_node.data.source_info };
+                        let terminator = TerminatorKind::Goto { target };
+                        cfg.terminate(block, source_info, terminator);
+                    }
+                }
                 // Root nodes don't correspond to a drop.
                 DropKind::Storage if drop_idx == ROOT_NODE => {}
                 DropKind::Storage => {
@@ -770,12 +785,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let local =
                         place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
 
-                    Some(DropData {
-                        source_info,
-                        local,
-                        kind: DropKind::Value,
-                        backwards_incompatible_lint: false,
-                    })
+                    Some(DropData { source_info, local, kind: DropKind::Value })
                 }
                 Operand::Constant(_) => None,
             })
@@ -822,6 +832,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         });
                         block = next;
                     }
+                    DropKind::ForLint => {
+                        self.cfg.push(block, Statement {
+                            source_info,
+                            kind: StatementKind::BackwardIncompatibleDropHint {
+                                place: Box::new(local.into()),
+                                reason: BackwardIncompatibleDropReason::Edition2024,
+                            },
+                        });
+                    }
                     DropKind::Storage => {
                         // Only temps and vars need their storage dead.
                         assert!(local.index() > self.arg_count);
@@ -1021,7 +1040,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         drop_kind: DropKind,
     ) {
         let needs_drop = match drop_kind {
-            DropKind::Value => {
+            DropKind::Value | DropKind::ForLint => {
                 if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) {
                     return;
                 }
@@ -1101,7 +1120,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
                     local,
                     kind: drop_kind,
-                    backwards_incompatible_lint: false,
                 });
 
                 return;
@@ -1135,8 +1153,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 scope.drops.push(DropData {
                     source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
                     local,
-                    kind: DropKind::Value,
-                    backwards_incompatible_lint: true,
+                    kind: DropKind::ForLint,
                 });
 
                 return;
@@ -1379,12 +1396,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 }
 
 /// Builds drops for `pop_scope` and `leave_top_scope`.
+///
+/// # Parameters
+///
+/// * `unwind_drops`, the drop tree data structure storing what needs to be cleaned up if unwind occurs
+/// * `scope`, describes the drops that will occur on exiting the scope in regular execution
+/// * `block`, the block to branch to once drops are complete (assuming no unwind occurs)
+/// * `unwind_to`, describes the drops that would occur at this point in the code if a
+///   panic occurred (a subset of the drops in `scope`, since we sometimes elide StorageDead and other
+///   instructions on unwinding)
+/// * `storage_dead_on_unwind`, if true, then we should emit `StorageDead` even when unwinding
+/// * `arg_count`, number of MIR local variables corresponding to fn arguments (used to assert that we don't drop those)
 fn build_scope_drops<'tcx>(
     cfg: &mut CFG<'tcx>,
     unwind_drops: &mut DropTree,
     scope: &Scope,
-    mut block: BasicBlock,
-    mut unwind_to: DropIdx,
+    block: BasicBlock,
+    unwind_to: DropIdx,
     storage_dead_on_unwind: bool,
     arg_count: usize,
 ) -> BlockAnd<()> {
@@ -1409,6 +1437,18 @@ fn build_scope_drops<'tcx>(
     // drops for the unwind path should have already been generated by
     // `diverge_cleanup_gen`.
 
+    // `unwind_to` indicates what needs to be dropped should unwinding occur.
+    // This is a subset of what needs to be dropped when exiting the scope.
+    // As we unwind the scope, we will also move `unwind_to` backwards to match,
+    // so that we can use it should a destructor panic.
+    let mut unwind_to = unwind_to;
+
+    // The block that we should jump to after drops complete. We start by building the final drop (`drops[n]`
+    // in the diagram above) and then build the drops (e.g., `drop[1]`, `drop[0]`) that come before it.
+    // block begins as the successor of `drops[n]` and then becomes `drops[n]` so that `drops[n-1]`
+    // will branch to `drops[n]`.
+    let mut block = block;
+
     for drop_data in scope.drops.iter().rev() {
         let source_info = drop_data.source_info;
         let local = drop_data.local;
@@ -1418,6 +1458,9 @@ fn build_scope_drops<'tcx>(
                 // `unwind_to` should drop the value that we're about to
                 // schedule. If dropping this value panics, then we continue
                 // with the *next* value on the unwind path.
+                //
+                // We adjust this BEFORE we create the drop (e.g., `drops[n]`)
+                // because `drops[n]` should unwind to `drops[n-1]`.
                 debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
                 debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
                 unwind_to = unwind_drops.drops[unwind_to].next;
@@ -1430,27 +1473,50 @@ fn build_scope_drops<'tcx>(
                     continue;
                 }
 
-                if drop_data.backwards_incompatible_lint {
-                    cfg.push(block, Statement {
-                        source_info,
-                        kind: StatementKind::BackwardIncompatibleDropHint {
-                            place: Box::new(local.into()),
-                            reason: BackwardIncompatibleDropReason::Edition2024,
-                        },
-                    });
-                } else {
-                    unwind_drops.add_entry_point(block, unwind_to);
-                    let next = cfg.start_new_block();
-                    cfg.terminate(block, source_info, TerminatorKind::Drop {
-                        place: local.into(),
-                        target: next,
-                        unwind: UnwindAction::Continue,
-                        replace: false,
-                    });
-                    block = next;
+                unwind_drops.add_entry_point(block, unwind_to);
+                let next = cfg.start_new_block();
+                cfg.terminate(block, source_info, TerminatorKind::Drop {
+                    place: local.into(),
+                    target: next,
+                    unwind: UnwindAction::Continue,
+                    replace: false,
+                });
+                block = next;
+            }
+            DropKind::ForLint => {
+                // As in the `DropKind::Storage` case below:
+                // normally lint-related drops are not emitted for unwind,
+                // so we can just leave `unwind_to` unmodified, but in some
+                // cases we emit things ALSO on the unwind path, so we need to adjust
+                // `unwind_to` in that case.
+                if storage_dead_on_unwind {
+                    debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
+                    debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
+                    unwind_to = unwind_drops.drops[unwind_to].next;
                 }
+
+                // If the operand has been moved, and we are not on an unwind
+                // path, then don't generate the drop. (We only take this into
+                // account for non-unwind paths so as not to disturb the
+                // caching mechanism.)
+                if scope.moved_locals.iter().any(|&o| o == local) {
+                    continue;
+                }
+
+                cfg.push(block, Statement {
+                    source_info,
+                    kind: StatementKind::BackwardIncompatibleDropHint {
+                        place: Box::new(local.into()),
+                        reason: BackwardIncompatibleDropReason::Edition2024,
+                    },
+                });
             }
             DropKind::Storage => {
+                // Ordinarily, storage-dead nodes are not emitted on unwind, so we don't
+                // need to adjust `unwind_to` on this path. However, in some specific cases
+                // we *do* emit storage-dead nodes on the unwind path, and in that case now that
+                // the storage-dead has completed, we need to adjust the `unwind_to` pointer
+                // so that any future drops we emit will not register storage-dead.
                 if storage_dead_on_unwind {
                     debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
                     debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
@@ -1489,7 +1555,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
             let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
             for (drop_idx, drop_node) in drops.drops.iter_enumerated().skip(1) {
                 match drop_node.data.kind {
-                    DropKind::Storage => {
+                    DropKind::Storage | DropKind::ForLint => {
                         if is_coroutine {
                             let unwind_drop = self
                                 .scopes
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 4e7d7b79ff4..20cef5e06a4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1732,6 +1732,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             span.push_span_label(self.tcx.def_span(trait_def_id), "this is the required trait");
             for (sp, label) in [trait_def_id, other_trait_def_id]
                 .iter()
+                // The current crate-version might depend on another version of the same crate
+                // (Think "semver-trick"). Do not call `extern_crate` in that case for the local
+                // crate as that doesn't make sense and ICEs (#133563).
+                .filter(|def_id| !def_id.is_local())
                 .filter_map(|def_id| self.tcx.extern_crate(def_id.krate))
                 .map(|data| {
                     let dependency = if data.dependency_of == LOCAL_CRATE {
diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs
index 4f9dc40a3cf..695d7ad07cf 100644
--- a/library/alloc/src/ffi/mod.rs
+++ b/library/alloc/src/ffi/mod.rs
@@ -83,7 +83,7 @@
 #[doc(inline)]
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
 pub use self::c_str::CString;
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
 pub use self::c_str::{FromVecWithNulError, IntoStringError, NulError};
 
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index dc107c5d22c..a963778bcc4 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -12,10 +12,10 @@
 #[doc(inline)]
 #[stable(feature = "core_c_str", since = "1.64.0")]
 pub use self::c_str::CStr;
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
 pub use self::c_str::FromBytesUntilNulError;
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "core_c_str", since = "1.64.0")]
 pub use self::c_str::FromBytesWithNulError;
 use crate::fmt;
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index dfe905544af..43eeb58d157 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -12,14 +12,17 @@ impl<T: ?Sized> *const T {
     /// Therefore, two pointers that are null may still not compare equal to
     /// each other.
     ///
-    /// ## Behavior during const evaluation
+    /// # Panics during const evaluation
     ///
-    /// When this function is used during const evaluation, it may return `false` for pointers
-    /// that turn out to be null at runtime. Specifically, when a pointer to some memory
-    /// is offset beyond its bounds in such a way that the resulting pointer is null,
-    /// the function will still return `false`. There is no way for CTFE to know
-    /// the absolute position of that memory, so we cannot tell if the pointer is
-    /// null or not.
+    /// If this method is used during const evaluation, and `self` is a pointer
+    /// that is offset beyond the bounds of the memory it initially pointed to,
+    /// then there might not be enough information to determine whether the
+    /// pointer is null. This is because the absolute address in memory is not
+    /// known at compile time. If the nullness of the pointer cannot be
+    /// determined, this method will panic.
+    ///
+    /// In-bounds pointers are never null, so the method will never panic for
+    /// such pointers.
     ///
     /// # Examples
     ///
@@ -255,6 +258,13 @@ impl<T: ?Sized> *const T {
     /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
     ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null
+    ///
     /// # Examples
     ///
     /// ```
@@ -332,6 +342,13 @@ impl<T: ?Sized> *const T {
     /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
     ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null
+    ///
     /// # Examples
     ///
     /// ```
@@ -1592,6 +1609,13 @@ impl<T> *const [T] {
     ///
     /// [valid]: crate::ptr#safety
     /// [allocated object]: crate::ptr#allocated-object
+    ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null
     #[inline]
     #[unstable(feature = "ptr_as_uninit", issue = "75402")]
     #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 5ed0b39f33b..4a2a1123f63 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -12,14 +12,17 @@ impl<T: ?Sized> *mut T {
     /// Therefore, two pointers that are null may still not compare equal to
     /// each other.
     ///
-    /// ## Behavior during const evaluation
+    /// # Panics during const evaluation
     ///
-    /// When this function is used during const evaluation, it may return `false` for pointers
-    /// that turn out to be null at runtime. Specifically, when a pointer to some memory
-    /// is offset beyond its bounds in such a way that the resulting pointer is null,
-    /// the function will still return `false`. There is no way for CTFE to know
-    /// the absolute position of that memory, so we cannot tell if the pointer is
-    /// null or not.
+    /// If this method is used during const evaluation, and `self` is a pointer
+    /// that is offset beyond the bounds of the memory it initially pointed to,
+    /// then there might not be enough information to determine whether the
+    /// pointer is null. This is because the absolute address in memory is not
+    /// known at compile time. If the nullness of the pointer cannot be
+    /// determined, this method will panic.
+    ///
+    /// In-bounds pointers are never null, so the method will never panic for
+    /// such pointers.
     ///
     /// # Examples
     ///
@@ -244,6 +247,13 @@ impl<T: ?Sized> *mut T {
     /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
     ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null-1
+    ///
     /// # Examples
     ///
     /// ```
@@ -328,6 +338,13 @@ impl<T: ?Sized> *mut T {
     /// Note that because the created reference is to `MaybeUninit<T>`, the
     /// source pointer can point to uninitialized memory.
     ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null-1
+    ///
     /// # Examples
     ///
     /// ```
@@ -592,6 +609,12 @@ impl<T: ?Sized> *mut T {
     /// the pointer is null *or*
     /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
     ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null-1
     ///
     /// # Examples
     ///
@@ -675,6 +698,13 @@ impl<T: ?Sized> *mut T {
     ///
     /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
+    ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null-1
     #[inline]
     #[unstable(feature = "ptr_as_uninit", issue = "75402")]
     #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
@@ -1947,6 +1977,13 @@ impl<T> *mut [T] {
     ///
     /// [valid]: crate::ptr#safety
     /// [allocated object]: crate::ptr#allocated-object
+    ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null-1
     #[inline]
     #[unstable(feature = "ptr_as_uninit", issue = "75402")]
     #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
@@ -1999,6 +2036,13 @@ impl<T> *mut [T] {
     ///
     /// [valid]: crate::ptr#safety
     /// [allocated object]: crate::ptr#allocated-object
+    ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: #method.is_null-1
     #[inline]
     #[unstable(feature = "ptr_as_uninit", issue = "75402")]
     #[rustc_const_unstable(feature = "ptr_as_uninit", issue = "75402")]
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 0fb5880fd1a..e56d17d4f6f 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -202,6 +202,13 @@ impl<T: ?Sized> NonNull<T> {
 
     /// Creates a new `NonNull` if `ptr` is non-null.
     ///
+    /// # Panics during const evaluation
+    ///
+    /// This method will panic during const evaluation if the pointer cannot be
+    /// determined to be null or not. See [`is_null`] for more information.
+    ///
+    /// [`is_null`]: ../primitive.pointer.html#method.is_null-1
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 469136be883..7d7cce09a3f 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -179,19 +179,19 @@ pub use core::ffi::{
     c_ulong, c_ulonglong, c_ushort,
 };
 
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
 pub use self::c_str::FromBytesUntilNulError;
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
 pub use self::c_str::FromBytesWithNulError;
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 pub use self::c_str::FromVecWithNulError;
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "cstring_into", since = "1.7.0")]
 pub use self::c_str::IntoStringError;
-#[doc(no_inline)]
+#[doc(inline)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::c_str::NulError;
 #[doc(inline)]
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index 3ae60938749..a188bc8ebd9 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -51,8 +51,17 @@ impl DocTestBuilder {
                 !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate
             });
 
-        let SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else } =
-            partition_source(source, edition);
+        let Some(SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else }) =
+            partition_source(source, edition)
+        else {
+            return Self::invalid(
+                String::new(),
+                String::new(),
+                String::new(),
+                source.to_string(),
+                test_id,
+            );
+        };
 
         // Uses librustc_ast to parse the doctest and find if there's a main fn and the extern
         // crate already is included.
@@ -77,18 +86,7 @@ impl DocTestBuilder {
         else {
             // If the parser panicked due to a fatal error, pass the test code through unchanged.
             // The error will be reported during compilation.
-            return Self {
-                supports_color: false,
-                has_main_fn: false,
-                crate_attrs,
-                maybe_crate_attrs,
-                crates,
-                everything_else,
-                already_has_extern_crate: false,
-                test_id,
-                failed_ast: true,
-                can_be_merged: false,
-            };
+            return Self::invalid(crate_attrs, maybe_crate_attrs, crates, everything_else, test_id);
         };
         // If the AST returned an error, we don't want this doctest to be merged with the
         // others. Same if it contains `#[feature]` or `#[no_std]`.
@@ -113,6 +111,27 @@ impl DocTestBuilder {
         }
     }
 
+    fn invalid(
+        crate_attrs: String,
+        maybe_crate_attrs: String,
+        crates: String,
+        everything_else: String,
+        test_id: Option<String>,
+    ) -> Self {
+        Self {
+            supports_color: false,
+            has_main_fn: false,
+            crate_attrs,
+            maybe_crate_attrs,
+            crates,
+            everything_else,
+            already_has_extern_crate: false,
+            test_id,
+            failed_ast: true,
+            can_be_merged: false,
+        }
+    }
+
     /// Transforms a test into code that can be compiled into a Rust binary, and returns the number of
     /// lines before the test code begins.
     pub(crate) fn generate_unique_doctest(
@@ -518,8 +537,8 @@ fn handle_attr(mod_attr_pending: &mut String, source_info: &mut SourceInfo, edit
         push_to.push('\n');
         // If it's complete, then we can clear the pending content.
         mod_attr_pending.clear();
-    } else if mod_attr_pending.ends_with('\\') {
-        mod_attr_pending.push('n');
+    } else {
+        mod_attr_pending.push_str("\n");
     }
 }
 
@@ -531,7 +550,7 @@ struct SourceInfo {
     everything_else: String,
 }
 
-fn partition_source(s: &str, edition: Edition) -> SourceInfo {
+fn partition_source(s: &str, edition: Edition) -> Option<SourceInfo> {
     #[derive(Copy, Clone, PartialEq)]
     enum PartitionState {
         Attrs,
@@ -606,11 +625,16 @@ fn partition_source(s: &str, edition: Edition) -> SourceInfo {
         }
     }
 
+    if !mod_attr_pending.is_empty() {
+        debug!("invalid doctest code: {s:?}");
+        return None;
+    }
+
     source_info.everything_else = source_info.everything_else.trim().to_string();
 
     debug!("crate_attrs:\n{}{}", source_info.crate_attrs, source_info.maybe_crate_attrs);
     debug!("crates:\n{}", source_info.crates);
     debug!("after:\n{}", source_info.everything_else);
 
-    source_info
+    Some(source_info)
 }
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 494daeca963..ffe10092cc2 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -227,6 +227,12 @@ impl Rustc {
         self
     }
 
+    /// Normalize the line number in the stderr output
+    pub fn ui_testing(&mut self) -> &mut Self {
+        self.cmd.arg(format!("-Zui-testing"));
+        self
+    }
+
     /// Specify the target triple, or a path to a custom target json spec file.
     pub fn target<S: AsRef<str>>(&mut self, target: S) -> &mut Self {
         let target = target.as_ref();
diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir
new file mode 100644
index 00000000000..e9bbe30bd77
--- /dev/null
+++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir
@@ -0,0 +1,159 @@
+// MIR for `method_1` after ElaborateDrops
+
+fn method_1(_1: Guard) -> () {
+    debug g => _1;
+    let mut _0: ();
+    let mut _2: std::result::Result<OtherDrop, ()>;
+    let mut _3: &Guard;
+    let _4: &Guard;
+    let _5: Guard;
+    let mut _6: &Guard;
+    let mut _7: isize;
+    let _8: OtherDrop;
+    let _9: ();
+    let mut _10: bool;
+    let mut _11: isize;
+    let mut _12: isize;
+    let mut _13: isize;
+    scope 1 {
+        debug other_drop => _8;
+    }
+    scope 2 {
+        debug err => _9;
+    }
+
+    bb0: {
+        _10 = const false;
+        StorageLive(_2);
+        StorageLive(_3);
+        StorageLive(_4);
+        StorageLive(_5);
+        StorageLive(_6);
+        _6 = &_1;
+        _5 = <Guard as Clone>::clone(move _6) -> [return: bb1, unwind: bb13];
+    }
+
+    bb1: {
+        StorageDead(_6);
+        _4 = &_5;
+        _3 = &(*_4);
+        _2 = method_2(move _3) -> [return: bb2, unwind: bb12];
+    }
+
+    bb2: {
+        _10 = const true;
+        StorageDead(_3);
+        PlaceMention(_2);
+        _7 = discriminant(_2);
+        switchInt(move _7) -> [0: bb5, 1: bb4, otherwise: bb3];
+    }
+
+    bb3: {
+        unreachable;
+    }
+
+    bb4: {
+        StorageLive(_9);
+        _9 = copy ((_2 as Err).0: ());
+        _0 = const ();
+        StorageDead(_9);
+        goto -> bb7;
+    }
+
+    bb5: {
+        StorageLive(_8);
+        _8 = move ((_2 as Ok).0: OtherDrop);
+        _0 = const ();
+        drop(_8) -> [return: bb6, unwind: bb11];
+    }
+
+    bb6: {
+        StorageDead(_8);
+        goto -> bb7;
+    }
+
+    bb7: {
+        backward incompatible drop(_2);
+        backward incompatible drop(_5);
+        goto -> bb21;
+    }
+
+    bb8: {
+        drop(_5) -> [return: bb9, unwind: bb13];
+    }
+
+    bb9: {
+        StorageDead(_5);
+        StorageDead(_4);
+        _10 = const false;
+        StorageDead(_2);
+        drop(_1) -> [return: bb10, unwind: bb14];
+    }
+
+    bb10: {
+        return;
+    }
+
+    bb11 (cleanup): {
+        goto -> bb25;
+    }
+
+    bb12 (cleanup): {
+        drop(_5) -> [return: bb13, unwind terminate(cleanup)];
+    }
+
+    bb13 (cleanup): {
+        drop(_1) -> [return: bb14, unwind terminate(cleanup)];
+    }
+
+    bb14 (cleanup): {
+        resume;
+    }
+
+    bb15: {
+        goto -> bb8;
+    }
+
+    bb16 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb17 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb18: {
+        goto -> bb15;
+    }
+
+    bb19: {
+        goto -> bb15;
+    }
+
+    bb20 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb21: {
+        _11 = discriminant(_2);
+        switchInt(move _11) -> [0: bb18, otherwise: bb19];
+    }
+
+    bb22 (cleanup): {
+        _12 = discriminant(_2);
+        switchInt(move _12) -> [0: bb16, otherwise: bb20];
+    }
+
+    bb23 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb24 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb25 (cleanup): {
+        _13 = discriminant(_2);
+        switchInt(move _13) -> [0: bb23, otherwise: bb24];
+    }
+}
diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir
new file mode 100644
index 00000000000..e9bbe30bd77
--- /dev/null
+++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir
@@ -0,0 +1,159 @@
+// MIR for `method_1` after ElaborateDrops
+
+fn method_1(_1: Guard) -> () {
+    debug g => _1;
+    let mut _0: ();
+    let mut _2: std::result::Result<OtherDrop, ()>;
+    let mut _3: &Guard;
+    let _4: &Guard;
+    let _5: Guard;
+    let mut _6: &Guard;
+    let mut _7: isize;
+    let _8: OtherDrop;
+    let _9: ();
+    let mut _10: bool;
+    let mut _11: isize;
+    let mut _12: isize;
+    let mut _13: isize;
+    scope 1 {
+        debug other_drop => _8;
+    }
+    scope 2 {
+        debug err => _9;
+    }
+
+    bb0: {
+        _10 = const false;
+        StorageLive(_2);
+        StorageLive(_3);
+        StorageLive(_4);
+        StorageLive(_5);
+        StorageLive(_6);
+        _6 = &_1;
+        _5 = <Guard as Clone>::clone(move _6) -> [return: bb1, unwind: bb13];
+    }
+
+    bb1: {
+        StorageDead(_6);
+        _4 = &_5;
+        _3 = &(*_4);
+        _2 = method_2(move _3) -> [return: bb2, unwind: bb12];
+    }
+
+    bb2: {
+        _10 = const true;
+        StorageDead(_3);
+        PlaceMention(_2);
+        _7 = discriminant(_2);
+        switchInt(move _7) -> [0: bb5, 1: bb4, otherwise: bb3];
+    }
+
+    bb3: {
+        unreachable;
+    }
+
+    bb4: {
+        StorageLive(_9);
+        _9 = copy ((_2 as Err).0: ());
+        _0 = const ();
+        StorageDead(_9);
+        goto -> bb7;
+    }
+
+    bb5: {
+        StorageLive(_8);
+        _8 = move ((_2 as Ok).0: OtherDrop);
+        _0 = const ();
+        drop(_8) -> [return: bb6, unwind: bb11];
+    }
+
+    bb6: {
+        StorageDead(_8);
+        goto -> bb7;
+    }
+
+    bb7: {
+        backward incompatible drop(_2);
+        backward incompatible drop(_5);
+        goto -> bb21;
+    }
+
+    bb8: {
+        drop(_5) -> [return: bb9, unwind: bb13];
+    }
+
+    bb9: {
+        StorageDead(_5);
+        StorageDead(_4);
+        _10 = const false;
+        StorageDead(_2);
+        drop(_1) -> [return: bb10, unwind: bb14];
+    }
+
+    bb10: {
+        return;
+    }
+
+    bb11 (cleanup): {
+        goto -> bb25;
+    }
+
+    bb12 (cleanup): {
+        drop(_5) -> [return: bb13, unwind terminate(cleanup)];
+    }
+
+    bb13 (cleanup): {
+        drop(_1) -> [return: bb14, unwind terminate(cleanup)];
+    }
+
+    bb14 (cleanup): {
+        resume;
+    }
+
+    bb15: {
+        goto -> bb8;
+    }
+
+    bb16 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb17 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb18: {
+        goto -> bb15;
+    }
+
+    bb19: {
+        goto -> bb15;
+    }
+
+    bb20 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb21: {
+        _11 = discriminant(_2);
+        switchInt(move _11) -> [0: bb18, otherwise: bb19];
+    }
+
+    bb22 (cleanup): {
+        _12 = discriminant(_2);
+        switchInt(move _12) -> [0: bb16, otherwise: bb20];
+    }
+
+    bb23 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb24 (cleanup): {
+        goto -> bb12;
+    }
+
+    bb25 (cleanup): {
+        _13 = discriminant(_2);
+        switchInt(move _13) -> [0: bb23, otherwise: bb24];
+    }
+}
diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.rs b/tests/mir-opt/tail_expr_drop_order_unwind.rs
new file mode 100644
index 00000000000..065e08c3409
--- /dev/null
+++ b/tests/mir-opt/tail_expr_drop_order_unwind.rs
@@ -0,0 +1,36 @@
+// skip-filecheck
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// EMIT_MIR tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.mir
+
+#![deny(tail_expr_drop_order)]
+
+use std::backtrace::Backtrace;
+
+#[derive(Clone)]
+struct Guard;
+impl Drop for Guard {
+    fn drop(&mut self) {
+        println!("Drop!");
+    }
+}
+
+#[derive(Clone)]
+struct OtherDrop;
+impl Drop for OtherDrop {
+    fn drop(&mut self) {
+        println!("Drop!");
+    }
+}
+
+fn method_1(g: Guard) {
+    match method_2(&g.clone()) {
+        Ok(other_drop) => {
+            // repro needs something else being dropped too.
+        }
+        Err(err) => {}
+    }
+}
+
+fn method_2(_: &Guard) -> Result<OtherDrop, ()> {
+    panic!("Method 2 panics!");
+}
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs b/tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs
new file mode 100644
index 00000000000..71b27cd85bf
--- /dev/null
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo-current.rs
@@ -0,0 +1,14 @@
+#![crate_type = "lib"]
+#![crate_name = "foo"]
+
+extern crate foo;
+
+pub struct Struct;
+pub trait Trait {}
+impl Trait for Struct {}
+
+fn check_trait<T: Trait>() {}
+
+fn ice() {
+    check_trait::<foo::Struct>();
+}
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs b/tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs
new file mode 100644
index 00000000000..19d3f3c972b
--- /dev/null
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo-prev.rs
@@ -0,0 +1,6 @@
+#![crate_type = "lib"]
+#![crate_name = "foo"]
+
+pub struct Struct;
+pub trait Trait {}
+impl Trait for Struct {}
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
new file mode 100644
index 00000000000..9c2fcabe5ba
--- /dev/null
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/foo.stderr
@@ -0,0 +1,29 @@
+error[E0277]: the trait bound `foo::Struct: Trait` is not satisfied because the trait comes from a different crate version
+  --> foo-current.rs:13:19
+   |
+13 |     check_trait::<foo::Struct>();
+   |                   ^^^^^^^^^^^ the trait `Trait` is not implemented for `foo::Struct`
+   |
+note: there are multiple different versions of crate `foo` in the dependency graph
+  --> foo-current.rs:7:1
+   |
+4  | extern crate foo;
+   | ----------------- one version of crate `foo` is used here, as a direct dependency of the current crate
+5  |
+6  | pub struct Struct;
+   | ----------------- this type implements the required trait
+7  | pub trait Trait {}
+   | ^^^^^^^^^^^^^^^ this is the required trait
+   |
+  ::: foo-prev.rs:X:Y
+   |
+4  | pub struct Struct;
+   | ----------------- this type doesn't implement the required trait
+5  | pub trait Trait {}
+   | --------------- this is the found trait
+   = note: two types coming from two different versions of the same crate are different types even if they look the same
+   = help: you can use `cargo tree` to explore your dependency tree
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
\ No newline at end of file
diff --git a/tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs b/tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs
new file mode 100644
index 00000000000..57e0cab92f1
--- /dev/null
+++ b/tests/run-make/crate-loading-crate-depends-on-itself/rmake.rs
@@ -0,0 +1,31 @@
+//@ only-linux
+//@ ignore-wasm32
+//@ ignore-wasm64
+// ignore-tidy-linelength
+
+// Verify that if the current crate depends on a different version of the same crate, *and* types
+// and traits of the different versions are mixed, we produce diagnostic output and not an ICE.
+// #133563
+
+use run_make_support::{diff, rust_lib_name, rustc};
+
+fn main() {
+    rustc().input("foo-prev.rs").run();
+
+    let out = rustc()
+        .extra_filename("current")
+        .metadata("current")
+        .input("foo-current.rs")
+        .extern_("foo", rust_lib_name("foo"))
+        .run_fail()
+        .stderr_utf8();
+
+    // We don't remap the path of the `foo-prev` crate, so we remap it here.
+    let mut lines: Vec<_> = out.lines().collect();
+    for line in &mut lines {
+        if line.starts_with("  ::: ") {
+            *line = "  ::: foo-prev.rs:X:Y";
+        }
+    }
+    diff().expected_file("foo.stderr").actual_text("(rustc)", &lines.join("\n")).run();
+}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions.stderr b/tests/run-make/crate-loading/multiple-dep-versions.stderr
new file mode 100644
index 00000000000..7f04b2dd64a
--- /dev/null
+++ b/tests/run-make/crate-loading/multiple-dep-versions.stderr
@@ -0,0 +1,113 @@
+error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied because the trait comes from a different crate version
+  --> replaced
+   |
+LL |     do_something(Type);
+   |                  ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type`
+   |
+note: there are multiple different versions of crate `dependency` in the dependency graph
+  --> replaced
+   |
+LL | pub struct Type(pub i32);
+   | --------------- this type implements the required trait
+LL | pub trait Trait {
+   | ^^^^^^^^^^^^^^^ this is the required trait
+   |
+  ::: replaced
+   |
+LL | extern crate dep_2_reexport;
+   | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo`
+LL | extern crate dependency;
+   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
+   |
+  ::: replaced
+   |
+LL | pub struct Type;
+   | --------------- this type doesn't implement the required trait
+LL | pub trait Trait {
+   | --------------- this is the found trait
+   = note: two types coming from two different versions of the same crate are different types even if they look the same
+   = help: you can use `cargo tree` to explore your dependency tree
+
+error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope
+  --> replaced
+   |
+LL |     Type.foo();
+   |          ^^^ method not found in `Type`
+   |
+note: there are multiple different versions of crate `dependency` in the dependency graph
+  --> replaced
+   |
+LL | pub trait Trait {
+   | ^^^^^^^^^^^^^^^ this is the trait that is needed
+LL |     fn foo(&self);
+   |     -------------- the method is available for `dep_2_reexport::Type` here
+   |
+  ::: replaced
+   |
+LL | use dependency::{Trait, do_something};
+   |                  ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`
+   |
+  ::: replaced
+   |
+LL | pub trait Trait {
+   | --------------- this is the trait that was imported
+
+error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope
+  --> replaced
+   |
+LL |     Type::bar();
+   |           ^^^ function or associated item not found in `Type`
+   |
+note: there are multiple different versions of crate `dependency` in the dependency graph
+  --> replaced
+   |
+LL | pub trait Trait {
+   | ^^^^^^^^^^^^^^^ this is the trait that is needed
+LL |     fn foo(&self);
+LL |     fn bar();
+   |     --------- the associated function is available for `dep_2_reexport::Type` here
+   |
+  ::: replaced
+   |
+LL | use dependency::{Trait, do_something};
+   |                  ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`
+   |
+  ::: replaced
+   |
+LL | pub trait Trait {
+   | --------------- this is the trait that was imported
+
+error[E0277]: the trait bound `OtherType: Trait` is not satisfied because the trait comes from a different crate version
+  --> replaced
+   |
+LL |     do_something(OtherType);
+   |                  ^^^^^^^^^ the trait `Trait` is not implemented for `OtherType`
+   |
+note: there are multiple different versions of crate `dependency` in the dependency graph
+  --> replaced
+   |
+LL | pub trait Trait {
+   | ^^^^^^^^^^^^^^^ this is the required trait
+   |
+  ::: replaced
+   |
+LL | extern crate dep_2_reexport;
+   | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo`
+LL | extern crate dependency;
+   | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate
+   |
+  ::: replaced
+   |
+LL | pub struct OtherType;
+   | -------------------- this type doesn't implement the required trait
+   |
+  ::: replaced
+   |
+LL | pub trait Trait {
+   | --------------- this is the found trait
+   = help: you can use `cargo tree` to explore your dependency tree
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
\ No newline at end of file
diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs
index 2d5913c4bcb..6ad456e3e3e 100644
--- a/tests/run-make/crate-loading/rmake.rs
+++ b/tests/run-make/crate-loading/rmake.rs
@@ -3,7 +3,7 @@
 //@ ignore-wasm64
 // ignore-tidy-linelength
 
-use run_make_support::{rust_lib_name, rustc};
+use run_make_support::{diff, rust_lib_name, rustc};
 
 fn main() {
     rustc().input("multiple-dep-versions-1.rs").run();
@@ -13,77 +13,26 @@ fn main() {
         .extern_("dependency", rust_lib_name("dependency2"))
         .run();
 
-    rustc()
+    let out = rustc()
         .input("multiple-dep-versions.rs")
         .extern_("dependency", rust_lib_name("dependency"))
         .extern_("dep_2_reexport", rust_lib_name("foo"))
+        .ui_testing()
         .run_fail()
-        .assert_stderr_contains(r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied because the trait comes from a different crate version
- --> multiple-dep-versions.rs:7:18
-  |
-7 |     do_something(Type);
-  |                  ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type`
-  |
-note: there are multiple different versions of crate `dependency` in the dependency graph"#)
-        .assert_stderr_contains(r#"
-3 | pub struct Type(pub i32);
-  | --------------- this type implements the required trait
-4 | pub trait Trait {
-  | ^^^^^^^^^^^^^^^ this is the required trait
-"#)
-        .assert_stderr_contains(r#"
-1 | extern crate dep_2_reexport;
-  | ---------------------------- one version of crate `dependency` is used here, as a dependency of crate `foo`
-2 | extern crate dependency;
-  | ------------------------ one version of crate `dependency` is used here, as a direct dependency of the current crate"#)
-        .assert_stderr_contains(r#"
-3 | pub struct Type;
-  | --------------- this type doesn't implement the required trait
-4 | pub trait Trait {
-  | --------------- this is the found trait
-  = note: two types coming from two different versions of the same crate are different types even if they look the same
-  = help: you can use `cargo tree` to explore your dependency tree"#)
-        .assert_stderr_contains(r#"error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope
- --> multiple-dep-versions.rs:8:10
-  |
-8 |     Type.foo();
-  |          ^^^ method not found in `Type`
-  |
-note: there are multiple different versions of crate `dependency` in the dependency graph"#)
-        .assert_stderr_contains(r#"
-4 | pub trait Trait {
-  | ^^^^^^^^^^^^^^^ this is the trait that is needed
-5 |     fn foo(&self);
-  |     -------------- the method is available for `dep_2_reexport::Type` here
-  |
- ::: multiple-dep-versions.rs:4:18
-  |
-4 | use dependency::{Trait, do_something};
-  |                  ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#)
-        .assert_stderr_contains(r#"
-4 | pub trait Trait {
-  | --------------- this is the trait that was imported"#)
-        .assert_stderr_contains(r#"
-error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope
- --> multiple-dep-versions.rs:9:11
-  |
-9 |     Type::bar();
-  |           ^^^ function or associated item not found in `Type`
-  |
-note: there are multiple different versions of crate `dependency` in the dependency graph"#)
-        .assert_stderr_contains(r#"
-4 | pub trait Trait {
-  | ^^^^^^^^^^^^^^^ this is the trait that is needed
-5 |     fn foo(&self);
-6 |     fn bar();
-  |     --------- the associated function is available for `dep_2_reexport::Type` here
-  |
- ::: multiple-dep-versions.rs:4:18
-  |
-4 | use dependency::{Trait, do_something};
-  |                  ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#)
-        .assert_stderr_contains(
-          r#"
-6  | pub struct OtherType;
-   | -------------------- this type doesn't implement the required trait"#);
+        .stderr_utf8();
+
+    // We don't remap all the paths, so we remap it here.
+    let mut lines: Vec<_> = out.lines().collect();
+    for line in &mut lines {
+        if line.starts_with("  --> ") {
+            *line = "  --> replaced";
+        }
+        if line.starts_with("  ::: ") {
+            *line = "  ::: replaced";
+        }
+    }
+    diff()
+        .expected_file("multiple-dep-versions.stderr")
+        .actual_text("(rustc)", &lines.join("\n"))
+        .run();
 }
diff --git a/tests/rustdoc-ui/doctest/comment-in-attr-134221-2.rs b/tests/rustdoc-ui/doctest/comment-in-attr-134221-2.rs
new file mode 100644
index 00000000000..8cdd665ff69
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/comment-in-attr-134221-2.rs
@@ -0,0 +1,15 @@
+//@ compile-flags:--test --test-args --test-threads=1
+//@ failure-status: 101
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout-test: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
+
+//! ```
+#![doc = "#![all\
+ow(unused)]"]
+//! ```
+//!
+//! ```
+#![doc = r#"#![all\
+ow(unused)]"#]
+//! ```
diff --git a/tests/rustdoc-ui/doctest/comment-in-attr-134221-2.stdout b/tests/rustdoc-ui/doctest/comment-in-attr-134221-2.stdout
new file mode 100644
index 00000000000..0baff3df144
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/comment-in-attr-134221-2.stdout
@@ -0,0 +1,31 @@
+
+running 2 tests
+test $DIR/comment-in-attr-134221-2.rs - (line 11) ... FAILED
+test $DIR/comment-in-attr-134221-2.rs - (line 7) ... ok
+
+failures:
+
+---- $DIR/comment-in-attr-134221-2.rs - (line 11) stdout ----
+error: unknown start of token: \
+  --> $DIR/comment-in-attr-134221-2.rs:$LINE:$COL
+   |
+LL | #![all\
+   |       ^
+
+error: expected one of `(`, `::`, `=`, `[`, `]`, or `{`, found `ow`
+  --> $DIR/comment-in-attr-134221-2.rs:$LINE:$COL
+   |
+LL | #![all\
+   |       - expected one of `(`, `::`, `=`, `[`, `]`, or `{`
+LL | ow(unused)]
+   | ^^ unexpected token
+
+error: aborting due to 2 previous errors
+
+Couldn't compile the test.
+
+failures:
+    $DIR/comment-in-attr-134221-2.rs - (line 11)
+
+test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/doctest/comment-in-attr-134221.rs b/tests/rustdoc-ui/doctest/comment-in-attr-134221.rs
new file mode 100644
index 00000000000..3689ebe166a
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/comment-in-attr-134221.rs
@@ -0,0 +1,27 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/134221>.
+// It checks that even if there are comments in the attributes, the attributes
+// will still be generated correctly (and therefore fail in this test).
+
+//@ compile-flags:--test --test-args --test-threads=1
+//@ failure-status: 101
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout-test: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
+
+/*!
+```rust
+#![feature(
+  foo, //
+)]
+```
+
+```rust
+#![feature(
+  foo,
+)]
+```
+
+```rust
+#![
+```
+*/
diff --git a/tests/rustdoc-ui/doctest/comment-in-attr-134221.stdout b/tests/rustdoc-ui/doctest/comment-in-attr-134221.stdout
new file mode 100644
index 00000000000..aa1b27d1f0b
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/comment-in-attr-134221.stdout
@@ -0,0 +1,50 @@
+
+running 3 tests
+test $DIR/comment-in-attr-134221.rs - (line 11) ... FAILED
+test $DIR/comment-in-attr-134221.rs - (line 17) ... FAILED
+test $DIR/comment-in-attr-134221.rs - (line 23) ... FAILED
+
+failures:
+
+---- $DIR/comment-in-attr-134221.rs - (line 11) stdout ----
+error[E0635]: unknown feature `foo`
+  --> $DIR/comment-in-attr-134221.rs:$LINE:$COL
+   |
+LL |   foo, //
+   |   ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0635`.
+Couldn't compile the test.
+---- $DIR/comment-in-attr-134221.rs - (line 17) stdout ----
+error[E0635]: unknown feature `foo`
+  --> $DIR/comment-in-attr-134221.rs:$LINE:$COL
+   |
+LL |   foo,
+   |   ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0635`.
+Couldn't compile the test.
+---- $DIR/comment-in-attr-134221.rs - (line 23) stdout ----
+error: this file contains an unclosed delimiter
+  --> $DIR/comment-in-attr-134221.rs:$LINE:$COL
+   |
+LL | #![
+   |   -^
+   |   |
+   |   unclosed delimiter
+
+error: aborting due to 1 previous error
+
+Couldn't compile the test.
+
+failures:
+    $DIR/comment-in-attr-134221.rs - (line 11)
+    $DIR/comment-in-attr-134221.rs - (line 17)
+    $DIR/comment-in-attr-134221.rs - (line 23)
+
+test result: FAILED. 0 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs
new file mode 100644
index 00000000000..8d85cee19fd
--- /dev/null
+++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.rs
@@ -0,0 +1,29 @@
+//@ edition: 2021
+//@ build-fail
+
+// Make sure we don't ICE when emitting the "lint" drop statement
+// used for tail_expr_drop_order.
+
+#![deny(tail_expr_drop_order)]
+
+struct Drop;
+impl std::ops::Drop for Drop {
+    fn drop(&mut self) {}
+}
+
+async fn func() -> Result<(), Drop> {
+    todo!()
+}
+
+async fn retry_db() -> Result<(), Drop> {
+    loop {
+        match func().await {
+            //~^ ERROR relative drop order changing in Rust 2024
+            //~| WARNING this changes meaning in Rust 2024
+            Ok(()) => return Ok(()),
+            Err(e) => {}
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
new file mode 100644
index 00000000000..37220c40b8b
--- /dev/null
+++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
@@ -0,0 +1,52 @@
+error: relative drop order changing in Rust 2024
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:20:15
+   |
+LL |         match func().await {
+   |               ^^^^^^^-----
+   |               |      |
+   |               |      this value will be stored in a temporary; let us call it `#1`
+   |               |      `#1` will be dropped later as of Edition 2024
+   |               this value will be stored in a temporary; let us call it `#2`
+   |               up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024
+...
+LL |             Err(e) => {}
+   |                 -
+   |                 |
+   |                 `e` calls a custom destructor
+   |                 `e` will be dropped later as of Edition 2024
+LL |         }
+LL |     }
+   |     - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#2` invokes this custom destructor
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
+   |
+LL | / impl std::ops::Drop for Drop {
+LL | |     fn drop(&mut self) {}
+LL | | }
+   | |_^
+note: `#1` invokes this custom destructor
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
+   |
+LL | / impl std::ops::Drop for Drop {
+LL | |     fn drop(&mut self) {}
+LL | | }
+   | |_^
+note: `e` invokes this custom destructor
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:10:1
+   |
+LL | / impl std::ops::Drop for Drop {
+LL | |     fn drop(&mut self) {}
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+note: the lint level is defined here
+  --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:7:9
+   |
+LL | #![deny(tail_expr_drop_order)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+