diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 60af462b6b619..34c84c64070d2 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -389,11 +389,10 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
         mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
     ) -> io::Result<()> {
         let mut archive_path = archive_path.to_path_buf();
-        if self.sess.target.llvm_target.contains("-apple-macosx") {
-            if let Some(new_archive_path) = try_extract_macho_fat_archive(self.sess, &archive_path)?
-            {
-                archive_path = new_archive_path
-            }
+        if self.sess.target.llvm_target.contains("-apple-macosx")
+            && let Some(new_archive_path) = try_extract_macho_fat_archive(self.sess, &archive_path)?
+        {
+            archive_path = new_archive_path
         }
 
         if self.src_archives.iter().any(|archive| archive.0 == archive_path) {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 5f85c10636e07..74597f6263d4f 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -151,17 +151,17 @@ pub fn link_binary(
                 sess.dcx().emit_artifact_notification(&out_filename, "link");
             }
 
-            if sess.prof.enabled() {
-                if let Some(artifact_name) = out_filename.file_name() {
-                    // Record size for self-profiling
-                    let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
-
-                    sess.prof.artifact_size(
-                        "linked_artifact",
-                        artifact_name.to_string_lossy(),
-                        file_size,
-                    );
-                }
+            if sess.prof.enabled()
+                && let Some(artifact_name) = out_filename.file_name()
+            {
+                // Record size for self-profiling
+                let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
+
+                sess.prof.artifact_size(
+                    "linked_artifact",
+                    artifact_name.to_string_lossy(),
+                    file_size,
+                );
             }
 
             if output.is_stdout() {
@@ -186,16 +186,12 @@ pub fn link_binary(
 
         let maybe_remove_temps_from_module =
             |preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| {
-                if !preserve_objects {
-                    if let Some(ref obj) = module.object {
-                        ensure_removed(sess.dcx(), obj);
-                    }
+                if !preserve_objects && let Some(ref obj) = module.object {
+                    ensure_removed(sess.dcx(), obj);
                 }
 
-                if !preserve_dwarf_objects {
-                    if let Some(ref dwo_obj) = module.dwarf_object {
-                        ensure_removed(sess.dcx(), dwo_obj);
-                    }
+                if !preserve_dwarf_objects && let Some(ref dwo_obj) = module.dwarf_object {
+                    ensure_removed(sess.dcx(), dwo_obj);
                 }
             };
 
@@ -2116,11 +2112,11 @@ fn add_local_crate_metadata_objects(
     // When linking a dynamic library, we put the metadata into a section of the
     // executable. This metadata is in a separate object file from the main
     // object file, so we link that in here.
-    if crate_type == CrateType::Dylib || crate_type == CrateType::ProcMacro {
-        if let Some(obj) = codegen_results.metadata_module.as_ref().and_then(|m| m.object.as_ref())
-        {
-            cmd.add_object(obj);
-        }
+    if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro)
+        && let Some(m) = &codegen_results.metadata_module
+        && let Some(obj) = &m.object
+    {
+        cmd.add_object(obj);
     }
 }
 
@@ -2540,10 +2536,11 @@ fn add_order_independent_options(
 
     cmd.output_filename(out_filename);
 
-    if crate_type == CrateType::Executable && sess.target.is_like_windows {
-        if let Some(ref s) = codegen_results.crate_info.windows_subsystem {
-            cmd.subsystem(s);
-        }
+    if crate_type == CrateType::Executable
+        && sess.target.is_like_windows
+        && let Some(s) = &codegen_results.crate_info.windows_subsystem
+    {
+        cmd.subsystem(s);
     }
 
     // Try to strip as much out of the generated object by removing unused
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index a8405a2aec98d..e2a59c6efb883 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -111,24 +111,22 @@ pub(crate) fn get_linker<'a>(
     // PATH for the child.
     let mut new_path = sess.get_tools_search_paths(self_contained);
     let mut msvc_changed_path = false;
-    if sess.target.is_like_msvc {
-        if let Some(ref tool) = msvc_tool {
-            cmd.args(tool.args());
-            for (k, v) in tool.env() {
-                if k == "PATH" {
-                    new_path.extend(env::split_paths(v));
-                    msvc_changed_path = true;
-                } else {
-                    cmd.env(k, v);
-                }
+    if sess.target.is_like_msvc
+        && let Some(ref tool) = msvc_tool
+    {
+        cmd.args(tool.args());
+        for (k, v) in tool.env() {
+            if k == "PATH" {
+                new_path.extend(env::split_paths(v));
+                msvc_changed_path = true;
+            } else {
+                cmd.env(k, v);
             }
         }
     }
 
-    if !msvc_changed_path {
-        if let Some(path) = env::var_os("PATH") {
-            new_path.extend(env::split_paths(&path));
-        }
+    if !msvc_changed_path && let Some(path) = env::var_os("PATH") {
+        new_path.extend(env::split_paths(&path));
     }
     cmd.env("PATH", env::join_paths(new_path).unwrap());
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 9cc737d194ce7..2ec203458a358 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -566,16 +566,13 @@ fn produce_final_output_artifacts(
 
     // Produce final compile outputs.
     let copy_gracefully = |from: &Path, to: &OutFileName| match to {
-        OutFileName::Stdout => {
-            if let Err(e) = copy_to_stdout(from) {
-                sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e));
-            }
+        OutFileName::Stdout if let Err(e) = copy_to_stdout(from) => {
+            sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e));
         }
-        OutFileName::Real(path) => {
-            if let Err(e) = fs::copy(from, path) {
-                sess.dcx().emit_err(errors::CopyPath::new(from, path, e));
-            }
+        OutFileName::Real(path) if let Err(e) = fs::copy(from, path) => {
+            sess.dcx().emit_err(errors::CopyPath::new(from, path, e));
         }
+        _ => {}
     };
 
     let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| {
@@ -685,14 +682,12 @@ fn produce_final_output_artifacts(
             needs_crate_object || (user_wants_objects && sess.codegen_units().as_usize() > 1);
 
         for module in compiled_modules.modules.iter() {
-            if let Some(ref path) = module.object {
-                if !keep_numbered_objects {
+            if !keep_numbered_objects {
+                if let Some(ref path) = module.object {
                     ensure_removed(sess.dcx(), path);
                 }
-            }
 
-            if let Some(ref path) = module.dwarf_object {
-                if !keep_numbered_objects {
+                if let Some(ref path) = module.dwarf_object {
                     ensure_removed(sess.dcx(), path);
                 }
             }
@@ -704,12 +699,11 @@ fn produce_final_output_artifacts(
             }
         }
 
-        if !user_wants_bitcode {
-            if let Some(ref allocator_module) = compiled_modules.allocator_module {
-                if let Some(ref path) = allocator_module.bytecode {
-                    ensure_removed(sess.dcx(), path);
-                }
-            }
+        if !user_wants_bitcode
+            && let Some(ref allocator_module) = compiled_modules.allocator_module
+            && let Some(ref path) = allocator_module.bytecode
+        {
+            ensure_removed(sess.dcx(), path);
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 84703a0a15692..18279a4d05fe0 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -555,11 +555,9 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
 
 pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
     let def_key = tcx.def_key(def_id);
-    if qualified {
-        if let Some(parent) = def_key.parent {
-            push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
-            output.push_str("::");
-        }
+    if qualified && let Some(parent) = def_key.parent {
+        push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
+        output.push_str("::");
     }
 
     push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 6d1930a402d37..d184ce3d61dea 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -163,25 +163,25 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         mergeable_succ: bool,
     ) -> MergingSucc {
         let tcx = bx.tcx();
-        if let Some(instance) = instance {
-            if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
-                if destination.is_some() {
-                    let caller_def = fx.instance.def_id();
-                    let e = CompilerBuiltinsCannotCall {
-                        span: tcx.def_span(caller_def),
-                        caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
-                        callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
-                    };
-                    tcx.dcx().emit_err(e);
-                } else {
-                    info!(
-                        "compiler_builtins call to diverging function {:?} replaced with abort",
-                        instance.def_id()
-                    );
-                    bx.abort();
-                    bx.unreachable();
-                    return MergingSucc::False;
-                }
+        if let Some(instance) = instance
+            && is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance)
+        {
+            if destination.is_some() {
+                let caller_def = fx.instance.def_id();
+                let e = CompilerBuiltinsCannotCall {
+                    span: tcx.def_span(caller_def),
+                    caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
+                    callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
+                };
+                tcx.dcx().emit_err(e);
+            } else {
+                info!(
+                    "compiler_builtins call to diverging function {:?} replaced with abort",
+                    instance.def_id()
+                );
+                bx.abort();
+                bx.unreachable();
+                return MergingSucc::False;
             }
         }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 72cfd2bffb5d0..0fe6a17473592 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -837,15 +837,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
         // ZST are passed as operands and require special handling
         // because codegen_place() panics if Local is operand.
-        if let Some(index) = place.as_local() {
-            if let LocalRef::Operand(op) = self.locals[index] {
-                if let ty::Array(_, n) = op.layout.ty.kind() {
-                    let n = n
-                        .try_to_target_usize(bx.tcx())
-                        .expect("expected monomorphic const in codegen");
-                    return bx.cx().const_usize(n);
-                }
-            }
+        if let Some(index) = place.as_local()
+            && let LocalRef::Operand(op) = self.locals[index]
+            && let ty::Array(_, n) = op.layout.ty.kind()
+        {
+            let n = n.try_to_target_usize(bx.tcx()).expect("expected monomorphic const in codegen");
+            return bx.cx().const_usize(n);
         }
         // use common size calculation for non zero-sized types
         let cg_value = self.codegen_place(bx, place.as_ref());
diff --git a/compiler/rustc_error_codes/src/error_codes/E0515.md b/compiler/rustc_error_codes/src/error_codes/E0515.md
index 0f4fbf672239c..87bbe4aea705f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0515.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0515.md
@@ -17,10 +17,13 @@ fn get_dangling_iterator<'a>() -> Iter<'a, i32> {
 }
 ```
 
-Local variables, function parameters and temporaries are all dropped before the
-end of the function body. So a reference to them cannot be returned.
+Local variables, function parameters and temporaries are all dropped before
+the end of the function body. A returned reference (or struct containing a
+reference) to such a dropped value would immediately be invalid. Therefore
+it is not allowed to return such a reference.
 
-Consider returning an owned value instead:
+Consider returning a value that takes ownership of local data instead of
+referencing it:
 
 ```
 use std::vec::IntoIter;
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index a32b42a6fe333..a96caf227f747 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -923,6 +923,28 @@ impl Target {
                     _ => unreachable!(),
                 }
             }
+            "loongarch64" => {
+                // LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname`
+                // about what the intended ABI is.
+                match &*self.llvm_abiname {
+                    "ilp32d" | "lp64d" => {
+                        // Requires d (which implies f), incompatible with nothing.
+                        FeatureConstraints { required: &["d"], incompatible: &[] }
+                    }
+                    "ilp32f" | "lp64f" => {
+                        // Requires f, incompatible with nothing.
+                        FeatureConstraints { required: &["f"], incompatible: &[] }
+                    }
+                    "ilp32s" | "lp64s" => {
+                        // The soft-float ABI does not require any features and is also not
+                        // incompatible with any features. Rust targets explicitly specify the
+                        // LLVM ABI names, which allows for enabling hard-float support even on
+                        // soft-float targets, and ensures that the ABI behavior is as expected.
+                        NOTHING
+                    }
+                    _ => unreachable!(),
+                }
+            }
             _ => NOTHING,
         }
     }
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 6961fa8ea947f..05bd4345ea8dd 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -333,7 +333,7 @@ impl Error for VarError {
 ///
 /// Discussion of this unsafety on Unix may be found in:
 ///
-///  - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188)
+///  - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=188)
 ///  - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
 ///
 /// To pass an environment variable to a child process, you can instead use [`Command::env`].
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 07a56010255de..f81ce8e1a1a1e 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -2018,9 +2018,9 @@ impl ExitCode {
     ///
     /// Note that this has the same caveats as [`process::exit()`][exit], namely that this function
     /// terminates the process immediately, so no destructors on the current stack or any other
-    /// thread's stack will be run. If a clean shutdown is needed, it is recommended to simply
-    /// return this ExitCode from the `main` function, as demonstrated in the [type
-    /// documentation](#examples).
+    /// thread's stack will be run. Also see those docs for some important notes on interop with C
+    /// code. If a clean shutdown is needed, it is recommended to simply return this ExitCode from
+    /// the `main` function, as demonstrated in the [type documentation](#examples).
     ///
     /// # Differences from `process::exit()`
     ///
@@ -2326,6 +2326,33 @@ impl Child {
 ///
 /// process::exit(0x0100);
 /// ```
+///
+/// ### Safe interop with C code
+///
+/// On Unix, this function is currently implemented using the `exit` C function [`exit`][C-exit]. As
+/// of C23, the C standard does not permit multiple threads to call `exit` concurrently. Rust
+/// mitigates this with a lock, but if C code calls `exit`, that can still cause undefined behavior.
+/// Note that returning from `main` is equivalent to calling `exit`.
+///
+/// Therefore, it is undefined behavior to have two concurrent threads perform the following
+/// without synchronization:
+/// - One thread calls Rust's `exit` function or returns from Rust's `main` function
+/// - Another thread calls the C function `exit` or `quick_exit`, or returns from C's `main` function
+///
+/// Note that if a binary contains multiple copies of the Rust runtime (e.g., when combining
+/// multiple `cdylib` or `staticlib`), they each have their own separate lock, so from the
+/// perspective of code running in one of the Rust runtimes, the "outside" Rust code is basically C
+/// code, and concurrent `exit` again causes undefined behavior.
+///
+/// Individual C implementations might provide more guarantees than the standard and permit concurrent
+/// calls to `exit`; consult the documentation of your C implementation for details.
+///
+/// For some of the on-going discussion to make `exit` thread-safe in C, see:
+/// - [Rust issue #126600](https://github.com/rust-lang/rust/issues/126600)
+/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=1845)
+/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=31997)
+///
+/// [C-exit]: https://en.cppreference.com/w/c/program/exit
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "process_exit")]
 pub fn exit(code: i32) -> ! {
diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs
index 1191e335daadd..f83a2f90ed22a 100644
--- a/library/std/src/sys/fs/hermit.rs
+++ b/library/std/src/sys/fs/hermit.rs
@@ -396,7 +396,7 @@ impl File {
     }
 
     pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
-        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+        self.0.read_buf(cursor)
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs
index 3d6b99cd77b54..edd984d920a1b 100644
--- a/library/std/src/sys/pal/hermit/fd.rs
+++ b/library/std/src/sys/pal/hermit/fd.rs
@@ -2,7 +2,7 @@
 
 use super::hermit_abi;
 use crate::cmp;
-use crate::io::{self, IoSlice, IoSliceMut, Read, SeekFrom};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom};
 use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
 use crate::sys::{cvt, unsupported};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -23,6 +23,21 @@ impl FileDesc {
         Ok(result as usize)
     }
 
+    pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
+        // SAFETY: The `read` syscall does not read from the buffer, so it is
+        // safe to use `&mut [MaybeUninit<u8>]`.
+        let result = cvt(unsafe {
+            hermit_abi::read(
+                self.fd.as_raw_fd(),
+                buf.as_mut().as_mut_ptr() as *mut u8,
+                buf.capacity(),
+            )
+        })?;
+        // SAFETY: Exactly `result` bytes have been filled.
+        unsafe { buf.advance_unchecked(result as usize) };
+        Ok(())
+    }
+
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             hermit_abi::readv(
diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs
index 8d133857c596d..08a06e0da9f34 100644
--- a/library/std/src/sys/stdio/unix.rs
+++ b/library/std/src/sys/stdio/unix.rs
@@ -3,9 +3,7 @@ use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
 #[cfg(target_family = "unix")]
 use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
 
-#[cfg(target_family = "unix")]
-use crate::io::BorrowedCursor;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::mem::ManuallyDrop;
 #[cfg(target_os = "hermit")]
 use crate::os::hermit::io::FromRawFd;
@@ -28,7 +26,6 @@ impl io::Read for Stdin {
         unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read(buf) }
     }
 
-    #[cfg(not(target_os = "hermit"))]
     fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
         unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_buf(buf) }
     }
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index 88db853d7c38f..31f9c284d7dd5 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -4,8 +4,8 @@ use rustc_ast_pretty::pprust::PrintState;
 use rustc_ast_pretty::pprust::state::State as Printer;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::ParseSess;
-use rustc_span::Span;
 use rustc_span::symbol::{Ident, Symbol, kw};
+use rustc_span::{FileName, Span};
 
 /// Render a macro matcher in a format suitable for displaying to the user
 /// as part of an item declaration.
@@ -63,7 +63,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
 
     // Create a Parser.
     let psess = ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec());
-    let file_name = source_map.span_to_filename(span);
+    let file_name = FileName::macro_expansion_source_code(&snippet);
     let mut parser =
         match rustc_parse::new_parser_from_source_str(&psess, file_name, snippet.clone()) {
             Ok(parser) => parser,
diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs
new file mode 100644
index 0000000000000..bebbe1fea349d
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_align.rs
@@ -0,0 +1,8 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]'
+#[repr(align(4))]
+pub struct Aligned {
+    a: i8,
+    b: i64,
+}
diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs
new file mode 100644
index 0000000000000..609d33d94de76
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_c.rs
@@ -0,0 +1,18 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]'
+#[repr(C)]
+pub struct ReprCStruct(pub i64);
+
+//@ is "$.index[*][?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]'
+#[repr(C)]
+pub enum ReprCEnum {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]'
+#[repr(C)]
+pub union ReprCUnion {
+    pub left: i64,
+    pub right: u64,
+}
diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs
new file mode 100644
index 0000000000000..662bfef67cb87
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_combination.rs
@@ -0,0 +1,78 @@
+#![no_std]
+
+// Combinations of `#[repr(..)]` attributes.
+
+//@ is "$.index[*][?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]'
+#[repr(C, i8)]
+pub enum ReprCI8 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]'
+#[repr(C)]
+#[repr(i16)]
+pub enum SeparateReprCI16 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]'
+#[repr(usize, C)]
+pub enum ReversedReprCUsize {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]'
+#[repr(C, packed)]
+pub struct ReprCPacked {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]'
+#[repr(C)]
+#[repr(packed(2))]
+pub struct SeparateReprCPacked {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]'
+#[repr(packed(2), C)]
+pub struct ReversedReprCPacked {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]'
+#[repr(C, align(16))]
+pub struct ReprCAlign {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]'
+#[repr(C)]
+#[repr(align(2))]
+pub struct SeparateReprCAlign {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]'
+#[repr(align(2), C)]
+pub struct ReversedReprCAlign {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]'
+#[repr(C, align(16), isize)]
+pub enum AlignedExplicitRepr {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]'
+#[repr(isize, C, align(16))]
+pub enum ReorderedAlignedExplicitRepr {
+    First,
+}
diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs
new file mode 100644
index 0000000000000..2ad57de279887
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_int_enum.rs
@@ -0,0 +1,19 @@
+#![no_std]
+
+//@ is "$.index[*][?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]'
+#[repr(i8)]
+pub enum I8 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]'
+#[repr(i32)]
+pub enum I32 {
+    First,
+}
+
+//@ is "$.index[*][?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]'
+#[repr(usize)]
+pub enum Usize {
+    First,
+}
diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs
new file mode 100644
index 0000000000000..33acc23b7c894
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_packed.rs
@@ -0,0 +1,18 @@
+#![no_std]
+
+// Note the normalization:
+// `#[repr(packed)]` in has the implict "1" in rustdoc JSON.
+
+//@ is "$.index[*][?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]'
+#[repr(packed)]
+pub struct Packed {
+    a: i8,
+    b: i64,
+}
+
+//@ is "$.index[*][?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]'
+#[repr(packed(4))]
+pub struct PackedAligned {
+    a: i8,
+    b: i64,
+}
diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs
new file mode 100644
index 0000000000000..ef6e69f8703b1
--- /dev/null
+++ b/tests/rustdoc-json/attrs/repr_transparent.rs
@@ -0,0 +1,22 @@
+#![no_std]
+
+// Rustdoc JSON currently includes `#[repr(transparent)]`
+// even if the transparency is not part of the public API
+//
+// https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
+
+//@ is "$.index[*][?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct Transparent(pub i64);
+
+//@ is "$.index[*][?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct TransparentNonPub(i64);
+
+//@ is "$.index[*][?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ());
+
+//@ is "$.index[*][?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
+#[repr(transparent)]
+pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ());
diff --git a/tests/rustdoc-ui/remap-path-prefix-macro.rs b/tests/rustdoc-ui/remap-path-prefix-macro.rs
new file mode 100644
index 0000000000000..1be22694b8cdc
--- /dev/null
+++ b/tests/rustdoc-ui/remap-path-prefix-macro.rs
@@ -0,0 +1,9 @@
+// Regression test for "attempted to remap an already remapped filename" ICE in rustdoc
+// when using --remap-path-prefix with macro rendering.
+// <https://github.com/rust-lang/rust/issues/138520>
+
+//@ compile-flags:-Z unstable-options --remap-path-prefix={{src-base}}=remapped_path
+//@ rustc-env:RUST_BACKTRACE=0
+//@ build-pass
+
+macro_rules! f(() => {});