From 0b87af9d4f7c6faa9e89496609f016dc3e3977e1 Mon Sep 17 00:00:00 2001
From: Mrmaxmeier <Mrmaxmeier@gmail.com>
Date: Sat, 27 Apr 2024 23:14:36 +0200
Subject: [PATCH 01/24] Add `-Z embed-source=yes` to embed source code in DWARF
 debug info

---
 .../src/debuginfo/metadata.rs                 |  9 +++++++
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs   |  2 ++
 compiler/rustc_interface/src/tests.rs         |  1 +
 .../rustc_llvm/llvm-wrapper/RustWrapper.cpp   |  9 +++++--
 compiler/rustc_session/messages.ftl           |  6 +++++
 compiler/rustc_session/src/errors.rs          | 14 +++++++++++
 compiler/rustc_session/src/options.rs         |  2 ++
 compiler/rustc_session/src/session.rs         | 25 +++++++++++++++++--
 .../src/compiler-flags/embed-source.md        | 12 +++++++++
 9 files changed, 76 insertions(+), 4 deletions(-)
 create mode 100644 src/doc/unstable-book/src/compiler-flags/embed-source.md

diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index ad63858861261..701ea62b21a7d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -629,6 +629,9 @@ pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) ->
         };
         let hash_value = hex_encode(source_file.src_hash.hash_bytes());
 
+        let source =
+            cx.sess().opts.unstable_opts.embed_source.then_some(()).and(source_file.src.as_ref());
+
         unsafe {
             llvm::LLVMRustDIBuilderCreateFile(
                 DIB(cx),
@@ -639,6 +642,8 @@ pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) ->
                 hash_kind,
                 hash_value.as_ptr().cast(),
                 hash_value.len(),
+                source.map_or(ptr::null(), |x| x.as_ptr().cast()),
+                source.map_or(0, |x| x.len()),
             )
         }
     }
@@ -659,6 +664,8 @@ pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
             llvm::ChecksumKind::None,
             hash_value.as_ptr().cast(),
             hash_value.len(),
+            ptr::null(),
+            0,
         )
     })
 }
@@ -943,6 +950,8 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
             llvm::ChecksumKind::None,
             ptr::null(),
             0,
+            ptr::null(),
+            0,
         );
 
         let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index c8e0e075eeabc..faa675b66c8a1 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1853,6 +1853,8 @@ extern "C" {
         CSKind: ChecksumKind,
         Checksum: *const c_char,
         ChecksumLen: size_t,
+        Source: *const c_char,
+        SourceLen: size_t,
     ) -> &'a DIFile;
 
     pub fn LLVMRustDIBuilderCreateSubroutineType<'a>(
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ce3b2f77f210a..c4704e38ce6fa 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -773,6 +773,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(direct_access_external_data, Some(true));
     tracked!(dual_proc_macros, true);
     tracked!(dwarf_version, Some(5));
+    tracked!(embed_source, true);
     tracked!(emit_thin_lto, false);
     tracked!(export_executable_symbols, true);
     tracked!(fewer_names, Some(true));
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 4cdd8af1008c0..6e700c31e6763 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -901,14 +901,19 @@ extern "C" LLVMMetadataRef
 LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename,
                             size_t FilenameLen, const char *Directory,
                             size_t DirectoryLen, LLVMRustChecksumKind CSKind,
-                            const char *Checksum, size_t ChecksumLen) {
+                            const char *Checksum, size_t ChecksumLen,
+                            const char *Source, size_t SourceLen) {
 
   std::optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind);
   std::optional<DIFile::ChecksumInfo<StringRef>> CSInfo{};
   if (llvmCSKind)
     CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen});
+  std::optional<StringRef> oSource{};
+  if (Source)
+    oSource = StringRef(Source, SourceLen);
   return wrap(Builder->createFile(StringRef(Filename, FilenameLen),
-                                  StringRef(Directory, DirectoryLen), CSInfo));
+                                  StringRef(Directory, DirectoryLen), CSInfo,
+                                  oSource));
 }
 
 extern "C" LLVMMetadataRef
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index b84280a3ccf3f..afd5360c81194 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -14,6 +14,12 @@ session_crate_name_empty = crate name must not be empty
 
 session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen
 
+session_embed_source_insufficient_dwarf_version = `-Zembed-source=y` requires at least `-Z dwarf-version=5` but DWARF version is {$dwarf_version}
+
+session_embed_source_requires_debug_info = `-Zembed-source=y` requires debug information to be enabled
+
+session_embed_source_requires_llvm_backend = `-Zembed-source=y` is only supported on the LLVM codegen backend
+
 session_expr_parentheses_needed = parentheses are required to parse this as an expression
 
 session_failed_to_create_profiler = failed to create profiler: {$err}
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 5cc54a5855bbe..f708109b87a0c 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -165,6 +165,20 @@ pub(crate) struct UnsupportedDwarfVersion {
     pub(crate) dwarf_version: u32,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_embed_source_insufficient_dwarf_version)]
+pub(crate) struct EmbedSourceInsufficientDwarfVersion {
+    pub(crate) dwarf_version: u32,
+}
+
+#[derive(Diagnostic)]
+#[diag(session_embed_source_requires_debug_info)]
+pub(crate) struct EmbedSourceRequiresDebugInfo;
+
+#[derive(Diagnostic)]
+#[diag(session_embed_source_requires_llvm_backend)]
+pub(crate) struct EmbedSourceRequiresLLVMBackend;
+
 #[derive(Diagnostic)]
 #[diag(session_target_stack_protector_not_supported)]
 pub(crate) struct StackProtectorNotSupportedForTarget<'a> {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index bf54aae1cfeb0..13aac6669fe4f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1708,6 +1708,8 @@ options! {
         them only if an error has not been emitted"),
     ehcont_guard: bool = (false, parse_bool, [TRACKED],
         "generate Windows EHCont Guard tables"),
+    embed_source: bool = (false, parse_bool, [TRACKED],
+        "embed source text in DWARF debug sections (default: no)"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
     emit_thin_lto: bool = (true, parse_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index be67baf57f6dc..634f3684b51aa 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -37,8 +37,9 @@ use rustc_target::spec::{
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
 use crate::config::{
-    self, CoverageLevel, CrateType, ErrorOutputType, FunctionReturn, Input, InstrumentCoverage,
-    OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath,
+    self, CoverageLevel, CrateType, DebugInfo, ErrorOutputType, FunctionReturn, Input,
+    InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents,
+    SwitchWithOptPath,
 };
 use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
@@ -1300,6 +1301,26 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             .emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
     }
 
+    if sess.opts.unstable_opts.embed_source {
+        let dwarf_version =
+            sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
+
+        let uses_llvm_backend =
+            matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm"));
+
+        if dwarf_version < 5 {
+            sess.dcx().emit_warn(errors::EmbedSourceInsufficientDwarfVersion { dwarf_version });
+        }
+
+        if sess.opts.debuginfo == DebugInfo::None {
+            sess.dcx().emit_warn(errors::EmbedSourceRequiresDebugInfo);
+        }
+
+        if !uses_llvm_backend {
+            sess.dcx().emit_warn(errors::EmbedSourceRequiresLLVMBackend);
+        }
+    }
+
     if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
         sess.dcx().emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
     }
diff --git a/src/doc/unstable-book/src/compiler-flags/embed-source.md b/src/doc/unstable-book/src/compiler-flags/embed-source.md
new file mode 100644
index 0000000000000..01a11e3779712
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/embed-source.md
@@ -0,0 +1,12 @@
+# `embed-source`
+
+This flag controls whether the compiler embeds the program source code text into
+the object debug information section. It takes one of the following values:
+
+* `y`, `yes`, `on` or `true`: put source code in debug info.
+* `n`, `no`, `off`, `false` or no value: omit source code from debug info (the default).
+
+This flag is ignored in configurations that don't emit DWARF debug information
+and is ignored on non-LLVM backends. `-Z embed-source` requires DWARFv5. Use
+`-Z dwarf-version=5` to control the compiler's DWARF target version and `-g` to
+enable debug info generation.

From 608901b9c07d7d2f3e2803378c4f0cc07c61bc36 Mon Sep 17 00:00:00 2001
From: Mrmaxmeier <Mrmaxmeier@gmail.com>
Date: Tue, 16 Jul 2024 20:50:28 +0200
Subject: [PATCH 02/24] Add run-make test for -Zembed-source=yes

---
 tests/run-make/embed-source-dwarf/main.rs  |  2 +
 tests/run-make/embed-source-dwarf/rmake.rs | 70 ++++++++++++++++++++++
 2 files changed, 72 insertions(+)
 create mode 100644 tests/run-make/embed-source-dwarf/main.rs
 create mode 100644 tests/run-make/embed-source-dwarf/rmake.rs

diff --git a/tests/run-make/embed-source-dwarf/main.rs b/tests/run-make/embed-source-dwarf/main.rs
new file mode 100644
index 0000000000000..c80af84f41415
--- /dev/null
+++ b/tests/run-make/embed-source-dwarf/main.rs
@@ -0,0 +1,2 @@
+// hello
+fn main() {}
diff --git a/tests/run-make/embed-source-dwarf/rmake.rs b/tests/run-make/embed-source-dwarf/rmake.rs
new file mode 100644
index 0000000000000..06d550121b0de
--- /dev/null
+++ b/tests/run-make/embed-source-dwarf/rmake.rs
@@ -0,0 +1,70 @@
+//@ ignore-windows
+//@ ignore-apple
+
+// LLVM 17's embed-source implementation requires that source code is attached
+// for all files in the output DWARF debug info. This restriction was lifted in
+// LLVM 18 (87e22bdd2bd6d77d782f9d64b3e3ae5bdcd5080d).
+//@ min-llvm-version: 18
+
+// This test should be replaced with one in tests/debuginfo once we can easily
+// tell via GDB or LLDB if debuginfo contains source code. Cheap tricks in LLDB
+// like setting an invalid source map path don't appear to work, maybe this'll
+// become easier once GDB supports DWARFv6?
+
+use std::collections::HashMap;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian};
+use object::{Object, ObjectSection};
+use run_make_support::{gimli, object, rfs, rustc};
+
+fn main() {
+    let output = PathBuf::from("embed-source-main");
+    rustc()
+        .input("main.rs")
+        .output(&output)
+        .arg("-g")
+        .arg("-Zembed-source=yes")
+        .arg("-Zdwarf-version=5")
+        .run();
+    let output = rfs::read(output);
+    let obj = object::File::parse(output.as_slice()).unwrap();
+    let endian = if obj.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big };
+    let dwarf = gimli::Dwarf::load(|section| -> Result<_, ()> {
+        let data = obj.section_by_name(section.name()).map(|s| s.uncompressed_data().unwrap());
+        Ok(EndianRcSlice::new(Rc::from(data.unwrap_or_default().as_ref()), endian))
+    })
+    .unwrap();
+
+    let mut sources = HashMap::new();
+
+    let mut iter = dwarf.units();
+    while let Some(header) = iter.next().unwrap() {
+        let unit = dwarf.unit(header).unwrap();
+        let unit = unit.unit_ref(&dwarf);
+
+        if let Some(program) = &unit.line_program {
+            let header = program.header();
+            for file in header.file_names() {
+                if let Some(source) = file.source() {
+                    let path = unit
+                        .attr_string(file.path_name())
+                        .unwrap()
+                        .to_string_lossy()
+                        .unwrap()
+                        .to_string();
+                    let source =
+                        unit.attr_string(source).unwrap().to_string_lossy().unwrap().to_string();
+                    if !source.is_empty() {
+                        sources.insert(path, source);
+                    }
+                }
+            }
+        }
+    }
+
+    dbg!(&sources);
+    assert_eq!(sources.len(), 1);
+    assert_eq!(sources.get("main.rs").unwrap(), "// hello\nfn main() {}\n");
+}

From 6899f5a8e12986ee16e028f1597963d0de668aca Mon Sep 17 00:00:00 2001
From: Mrmaxmeier <Mrmaxmeier@gmail.com>
Date: Tue, 6 Aug 2024 20:31:12 +0200
Subject: [PATCH 03/24] -Zembed-source: Don't try to warn about incompatible
 codegen backends

---
 compiler/rustc_session/messages.ftl   | 2 --
 compiler/rustc_session/src/errors.rs  | 4 ----
 compiler/rustc_session/src/session.rs | 7 -------
 3 files changed, 13 deletions(-)

diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index afd5360c81194..01c371ee49884 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -18,8 +18,6 @@ session_embed_source_insufficient_dwarf_version = `-Zembed-source=y` requires at
 
 session_embed_source_requires_debug_info = `-Zembed-source=y` requires debug information to be enabled
 
-session_embed_source_requires_llvm_backend = `-Zembed-source=y` is only supported on the LLVM codegen backend
-
 session_expr_parentheses_needed = parentheses are required to parse this as an expression
 
 session_failed_to_create_profiler = failed to create profiler: {$err}
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index f708109b87a0c..15bbd4ff7bf4b 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -175,10 +175,6 @@ pub(crate) struct EmbedSourceInsufficientDwarfVersion {
 #[diag(session_embed_source_requires_debug_info)]
 pub(crate) struct EmbedSourceRequiresDebugInfo;
 
-#[derive(Diagnostic)]
-#[diag(session_embed_source_requires_llvm_backend)]
-pub(crate) struct EmbedSourceRequiresLLVMBackend;
-
 #[derive(Diagnostic)]
 #[diag(session_target_stack_protector_not_supported)]
 pub(crate) struct StackProtectorNotSupportedForTarget<'a> {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 634f3684b51aa..e2ef144e732a4 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1305,9 +1305,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         let dwarf_version =
             sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
 
-        let uses_llvm_backend =
-            matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm"));
-
         if dwarf_version < 5 {
             sess.dcx().emit_warn(errors::EmbedSourceInsufficientDwarfVersion { dwarf_version });
         }
@@ -1315,10 +1312,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         if sess.opts.debuginfo == DebugInfo::None {
             sess.dcx().emit_warn(errors::EmbedSourceRequiresDebugInfo);
         }
-
-        if !uses_llvm_backend {
-            sess.dcx().emit_warn(errors::EmbedSourceRequiresLLVMBackend);
-        }
     }
 
     if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {

From 12e638978814d84e4e09b172f784d5f16759d8e1 Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Thu, 15 Aug 2024 16:22:01 -0400
Subject: [PATCH 04/24] bootstrap: improve error recovery flags to curl

alternative to #128459

fixes #110178
---
 src/bootstrap/bootstrap.py         |  8 +++++++-
 src/bootstrap/src/core/download.rs | 31 ++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 4e8e0fd2532f1..5ea4b4882a975 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -79,6 +79,8 @@ def get(base, url, path, checksums, verbose=False):
                 eprint("removing", temp_path)
             os.unlink(temp_path)
 
+def curl_version():
+    return float(re.match(bytes("^curl ([0-9]+\\.[0-9]+)", "utf8"), require(["curl", "-V"]))[1])
 
 def download(path, url, probably_big, verbose):
     for _ in range(4):
@@ -107,11 +109,15 @@ def _download(path, url, probably_big, verbose, exception):
         # If curl is not present on Win32, we should not sys.exit
         #   but raise `CalledProcessError` or `OSError` instead
         require(["curl", "--version"], exception=platform_is_win32())
-        run(["curl", option,
+        extra_flags = []
+        if curl_version() > 7.70:
+            extra_flags = [ "--retry-all-errors" ]
+        run(["curl", option] + extra_flags + [
             "-L", # Follow redirect.
             "-y", "30", "-Y", "10",    # timeout if speed is < 10 bytes/sec for > 30 seconds
             "--connect-timeout", "30",  # timeout if cannot connect within 30 seconds
             "-o", path,
+            "--continue-at", "-",
             "--retry", "3", "-SRf", url],
             verbose=verbose,
             exception=True, # Will raise RuntimeError on failure
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 4d1aea3cd956a..ed7637e8ee097 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -21,6 +21,31 @@ fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> {
     config.try_run(cmd)
 }
 
+fn extract_curl_version(out: &[u8]) -> f32 {
+    let out = &out[5..];
+    let Some(i) = out.iter().position(|&x| x == b' ') else { return 0.0 };
+    let out = &out[..i];
+    let Some(k) = out.iter().rev().position(|&x| x == b'.') else { return 0.0 };
+    let out = &out[..out.len()-k-1];
+    std::str::from_utf8(out).unwrap().parse().unwrap_or(0.0)
+}
+
+#[test]
+fn test_extract_curl_version() {
+    assert_eq!(extract_curl_version(b"\
+        curl 8.4.0 (x86_64-pc-linux-gnu) libcurl/8.4.0 \
+        OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.4 \
+        libssh2/1.11.0 nghttp2/1.57.0"), 8.4);
+}
+
+fn curl_version() -> f32 {
+    let mut curl = Command::new("curl");
+    curl.arg("-V");
+    let Ok(out) = curl.output() else { return 0.0 };
+    let out = out.stdout;
+    extract_curl_version(&out)
+}
+
 /// Generic helpers that are useful anywhere in bootstrap.
 impl Config {
     pub fn is_verbose(&self) -> bool {
@@ -219,6 +244,8 @@ impl Config {
             "30", // timeout if cannot connect within 30 seconds
             "-o",
             tempfile.to_str().unwrap(),
+            "--continue-at",
+            "-",
             "--retry",
             "3",
             "-SRf",
@@ -229,6 +256,10 @@ impl Config {
         } else {
             curl.arg("--progress-bar");
         }
+        // --retry-all-errors was added in 7.71.0, don't use it if curl is old.
+        if dbg!(curl_version()) > 7.70 {
+            curl.arg("--retry-all-errors");
+        }
         curl.arg(url);
         if !self.check_run(&mut curl) {
             if self.build.contains("windows-msvc") {

From b3ec296f3d918efdbe4db02dbd7fbc7fea1641a1 Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Fri, 16 Aug 2024 23:25:18 -0400
Subject: [PATCH 05/24] autoformat and remove unit test

---
 src/bootstrap/src/core/download.rs | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index ed7637e8ee097..2bde05501fcfc 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -26,18 +26,10 @@ fn extract_curl_version(out: &[u8]) -> f32 {
     let Some(i) = out.iter().position(|&x| x == b' ') else { return 0.0 };
     let out = &out[..i];
     let Some(k) = out.iter().rev().position(|&x| x == b'.') else { return 0.0 };
-    let out = &out[..out.len()-k-1];
+    let out = &out[..out.len() - k - 1];
     std::str::from_utf8(out).unwrap().parse().unwrap_or(0.0)
 }
 
-#[test]
-fn test_extract_curl_version() {
-    assert_eq!(extract_curl_version(b"\
-        curl 8.4.0 (x86_64-pc-linux-gnu) libcurl/8.4.0 \
-        OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.4 \
-        libssh2/1.11.0 nghttp2/1.57.0"), 8.4);
-}
-
 fn curl_version() -> f32 {
     let mut curl = Command::new("curl");
     curl.arg("-V");

From 803cbaf5fb5021eafaa60578ed33d708370ba3c0 Mon Sep 17 00:00:00 2001
From: Rezwan ahmed sami <samiahmed0f0@gmail.com>
Date: Sun, 18 Aug 2024 01:11:18 +0600
Subject: [PATCH 06/24] Add f16 and f128 to
 tests/ui/consts/const-float-bits-conv.rs

---
 tests/ui/consts/const-float-bits-conv.rs | 65 +++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs
index 45e8ea570ed73..2c4df96562a9d 100644
--- a/tests/ui/consts/const-float-bits-conv.rs
+++ b/tests/ui/consts/const-float-bits-conv.rs
@@ -3,8 +3,9 @@
 
 #![feature(const_float_bits_conv)]
 #![feature(const_float_classify)]
+#![feature(f16)]
+#![feature(f128)]
 #![allow(unused_macro_rules)]
-
 // Don't promote
 const fn nop<T>(x: T) -> T { x }
 
@@ -28,6 +29,36 @@ fn has_broken_floats() -> bool {
     std::env::var("TARGET").is_ok_and(|v| v.contains("i586"))
 }
 
+fn f16(){
+    const_assert!((1f16).to_bits(), 0x3c00);
+    const_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00);
+    const_assert!((12.5f16).to_bits(), 0x4a40);
+    const_assert!(u16::from_le_bytes(12.5f16.to_le_bytes()), 0x4a40);
+    const_assert!((1337f16).to_bits(), 0x6539);
+    const_assert!(u16::from_ne_bytes(1337f16.to_ne_bytes()), 0x6539);
+    const_assert!((-14.25f16).to_bits(), 0xcb20);
+    const_assert!(f16::from_bits(0x3c00), 1.0);
+    const_assert!(f16::from_be_bytes(0x3c00u16.to_be_bytes()), 1.0);
+    const_assert!(f16::from_bits(0x4a40), 12.5);
+    const_assert!(f16::from_le_bytes(0x4a40u16.to_le_bytes()), 12.5);
+    const_assert!(f16::from_bits(0x5be0), 252.0);
+    const_assert!(f16::from_ne_bytes(0x5be0u16.to_ne_bytes()), 252.0);
+    const_assert!(f16::from_bits(0xcb20), -14.25);
+
+    // Check that NaNs roundtrip their bits regardless of signalingness
+    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+    // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply!
+    const QUIET_NAN: u16 = f16::NAN.to_bits() ^ 0x0155;
+    const SIGNALING_NAN: u16 = f16::NAN.to_bits() ^ 0x02AA;
+
+    const_assert!(f16::from_bits(QUIET_NAN).is_nan());
+    const_assert!(f16::from_bits(SIGNALING_NAN).is_nan());
+    const_assert!(f16::from_bits(QUIET_NAN).to_bits(), QUIET_NAN);
+    if !has_broken_floats() {
+        const_assert!(f16::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN);
+    }
+}
+
 fn f32() {
     const_assert!((1f32).to_bits(), 0x3f800000);
     const_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000);
@@ -88,7 +119,39 @@ fn f64() {
     }
 }
 
+fn f128() {
+    const_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000);
+    const_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000);
+    const_assert!((12.5f128).to_bits(), 0x40029000000000000000000000000000);
+    const_assert!(u128::from_le_bytes(12.5f128.to_le_bytes()), 0x40029000000000000000000000000000);
+    const_assert!((1337f128).to_bits(), 0x40094e40000000000000000000000000);
+    const_assert!(u128::from_ne_bytes(1337f128.to_ne_bytes()), 0x40094e40000000000000000000000000);
+    const_assert!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000);
+    const_assert!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0);
+    const_assert!(f128::from_be_bytes(0x3fff0000000000000000000000000000u128.to_be_bytes()), 1.0);
+    const_assert!(f128::from_bits(0x40029000000000000000000000000000), 12.5);
+    const_assert!(f128::from_le_bytes(0x40029000000000000000000000000000u128.to_le_bytes()), 12.5);
+    const_assert!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0);
+    assert_eq!(f128::from_ne_bytes(0x40094e40000000000000000000000000u128.to_ne_bytes()), 1337.0);
+    const_assert!(f128::from_bits(0xc002c800000000000000000000000000), -14.25);
+
+    // Check that NaNs roundtrip their bits regardless of signalingness
+    // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+    // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply!
+    const QUIET_NAN: u128 = f128::NAN.to_bits() | 0x0000_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA;
+    const SIGNALING_NAN: u128 = f128::NAN.to_bits() ^ 0x0000_5555_5555_5555_5555_5555_5555_5555;
+
+    const_assert!(f128::from_bits(QUIET_NAN).is_nan());
+    const_assert!(f128::from_bits(SIGNALING_NAN).is_nan());
+    const_assert!(f128::from_bits(QUIET_NAN).to_bits(), QUIET_NAN);
+    if !has_broken_floats() {
+        const_assert!(f128::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN);
+    }
+}
+
 fn main() {
+    f16();
     f32();
     f64();
+    f128();
 }

From 9f39427228d09d7a06b9dd55a4f52b4b9ac15817 Mon Sep 17 00:00:00 2001
From: Rezwan ahmed sami <samiahmed0f0@gmail.com>
Date: Sun, 18 Aug 2024 11:12:40 +0600
Subject: [PATCH 07/24] Added #[cfg(target_arch = x86_64)] to f16 and f128

---
 tests/ui/consts/const-float-bits-conv.rs | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs
index 2c4df96562a9d..3a526c54dc376 100644
--- a/tests/ui/consts/const-float-bits-conv.rs
+++ b/tests/ui/consts/const-float-bits-conv.rs
@@ -29,6 +29,7 @@ fn has_broken_floats() -> bool {
     std::env::var("TARGET").is_ok_and(|v| v.contains("i586"))
 }
 
+#[cfg(target_arch = "x86_64")]
 fn f16(){
     const_assert!((1f16).to_bits(), 0x3c00);
     const_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00);
@@ -119,6 +120,7 @@ fn f64() {
     }
 }
 
+#[cfg(target_arch = "x86_64")]
 fn f128() {
     const_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000);
     const_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000);
@@ -150,8 +152,11 @@ fn f128() {
 }
 
 fn main() {
-    f16();
+    #[cfg(target_arch = "x86_64")]
+    {
+        f16();
+        f128();
+    }
     f32();
     f64();
-    f128();
 }

From f62b9e0179434218040f42ee58bb99c1bf27c6d7 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Tue, 30 Jul 2024 20:27:17 +0300
Subject: [PATCH 08/24] rustc: Simplify getting sysroot library directory

---
 compiler/rustc_codegen_ssa/src/back/link.rs | 27 +++++++++------------
 compiler/rustc_session/src/filesearch.rs    | 16 +-----------
 compiler/rustc_session/src/session.rs       | 16 ++----------
 3 files changed, 14 insertions(+), 45 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 7bad9d33e7d31..ca439460adc11 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1317,11 +1317,9 @@ fn link_sanitizer_runtime(
     name: &str,
 ) {
     fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
-        let session_tlib =
-            filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
-        let path = session_tlib.join(filename);
+        let path = sess.target_tlib_path.dir.join(filename);
         if path.exists() {
-            return session_tlib;
+            return sess.target_tlib_path.dir.clone();
         } else {
             let default_sysroot =
                 filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
@@ -1612,19 +1610,18 @@ fn print_native_static_libs(
 }
 
 fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf {
-    let fs = sess.target_filesearch(PathKind::Native);
-    let file_path = fs.get_lib_path().join(name);
+    let file_path = sess.target_tlib_path.dir.join(name);
     if file_path.exists() {
         return file_path;
     }
     // Special directory with objects used only in self-contained linkage mode
     if self_contained {
-        let file_path = fs.get_self_contained_lib_path().join(name);
+        let file_path = sess.target_tlib_path.dir.join("self-contained").join(name);
         if file_path.exists() {
             return file_path;
         }
     }
-    for search_path in fs.search_paths() {
+    for search_path in sess.target_filesearch(PathKind::Native).search_paths() {
         let file_path = search_path.dir.join(name);
         if file_path.exists() {
             return file_path;
@@ -2131,7 +2128,7 @@ fn add_library_search_dirs(
             | LinkSelfContainedComponents::UNWIND
             | LinkSelfContainedComponents::MINGW,
     ) {
-        let lib_path = sess.target_filesearch(PathKind::Native).get_self_contained_lib_path();
+        let lib_path = sess.target_tlib_path.dir.join("self-contained");
         cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
     }
 
@@ -2146,8 +2143,7 @@ fn add_library_search_dirs(
         || sess.target.os == "fuchsia"
         || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
     {
-        let lib_path = sess.target_filesearch(PathKind::Native).get_lib_path();
-        cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+        cmd.include_path(&fix_windows_verbatim_for_gcc(&sess.target_tlib_path.dir));
     }
 
     // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
@@ -2859,15 +2855,14 @@ fn add_upstream_native_libraries(
 //
 // The returned path will always have `fix_windows_verbatim_for_gcc()` applied to it.
 fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf {
-    let sysroot_lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
+    let sysroot_lib_path = &sess.target_tlib_path.dir;
     let canonical_sysroot_lib_path =
-        { try_canonicalize(&sysroot_lib_path).unwrap_or_else(|_| sysroot_lib_path.clone()) };
+        { try_canonicalize(sysroot_lib_path).unwrap_or_else(|_| sysroot_lib_path.clone()) };
 
     let canonical_lib_dir = try_canonicalize(lib_dir).unwrap_or_else(|_| lib_dir.to_path_buf());
     if canonical_lib_dir == canonical_sysroot_lib_path {
-        // This path, returned by `target_filesearch().get_lib_path()`, has
-        // already had `fix_windows_verbatim_for_gcc()` applied if needed.
-        sysroot_lib_path
+        // This path already had `fix_windows_verbatim_for_gcc()` applied if needed.
+        sysroot_lib_path.clone()
     } else {
         fix_windows_verbatim_for_gcc(lib_dir)
     }
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 63ca5fefd9faf..d78f4a78de732 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -5,14 +5,11 @@ use std::{env, fs};
 
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use smallvec::{smallvec, SmallVec};
-use tracing::debug;
 
 use crate::search_paths::{PathKind, SearchPath};
 
 #[derive(Clone)]
 pub struct FileSearch<'a> {
-    sysroot: &'a Path,
-    triple: &'a str,
     cli_search_paths: &'a [SearchPath],
     tlib_path: &'a SearchPath,
     kind: PathKind,
@@ -32,23 +29,12 @@ impl<'a> FileSearch<'a> {
             .chain(std::iter::once(self.tlib_path))
     }
 
-    pub fn get_lib_path(&self) -> PathBuf {
-        make_target_lib_path(self.sysroot, self.triple)
-    }
-
-    pub fn get_self_contained_lib_path(&self) -> PathBuf {
-        self.get_lib_path().join("self-contained")
-    }
-
     pub fn new(
-        sysroot: &'a Path,
-        triple: &'a str,
         cli_search_paths: &'a [SearchPath],
         tlib_path: &'a SearchPath,
         kind: PathKind,
     ) -> FileSearch<'a> {
-        debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
-        FileSearch { sysroot, triple, cli_search_paths, tlib_path, kind }
+        FileSearch { cli_search_paths, tlib_path, kind }
     }
 }
 
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 693867c3853da..b073950a750b4 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -439,22 +439,10 @@ impl Session {
     }
 
     pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
-        filesearch::FileSearch::new(
-            &self.sysroot,
-            self.opts.target_triple.triple(),
-            &self.opts.search_paths,
-            &self.target_tlib_path,
-            kind,
-        )
+        filesearch::FileSearch::new(&self.opts.search_paths, &self.target_tlib_path, kind)
     }
     pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
-        filesearch::FileSearch::new(
-            &self.sysroot,
-            config::host_triple(),
-            &self.opts.search_paths,
-            &self.host_tlib_path,
-            kind,
-        )
+        filesearch::FileSearch::new(&self.opts.search_paths, &self.host_tlib_path, kind)
     }
 
     /// Returns a list of directories where target-specific tool binaries are located. Some fallback

From d1b41f3747ecb01b717bd50918513227de36f3cb Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Thu, 22 Aug 2024 19:04:34 -0400
Subject: [PATCH 09/24] remove dbg!()

---
 src/bootstrap/src/core/download.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 2bde05501fcfc..201addaec2fc5 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -249,7 +249,7 @@ impl Config {
             curl.arg("--progress-bar");
         }
         // --retry-all-errors was added in 7.71.0, don't use it if curl is old.
-        if dbg!(curl_version()) > 7.70 {
+        if curl_version() > 7.70 {
             curl.arg("--retry-all-errors");
         }
         curl.arg(url);

From cee7f18d64bd461d3e36d2ea63b0d1867c680af5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sat, 10 Aug 2024 15:02:13 +0000
Subject: [PATCH 10/24] compiletest: implement `needs-lvm-zstd` directive

---
 src/tools/compiletest/src/command-list.rs |   1 +
 src/tools/compiletest/src/header.rs       | 101 ++++++++++++++++++++++
 src/tools/compiletest/src/header/needs.rs |  10 ++-
 3 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
index 7f8080235c870..a559d6f81a240 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/command-list.rs
@@ -141,6 +141,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "needs-force-clang-based-tests",
     "needs-git-hash",
     "needs-llvm-components",
+    "needs-llvm-zstd",
     "needs-profiler-support",
     "needs-relocation-model-pic",
     "needs-run-enabled",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 1fc24301c85e6..933913eb47c34 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1203,6 +1203,107 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> {
     None
 }
 
+/// For tests using the `needs-llvm-zstd` directive:
+/// - for local LLVM builds, try to find the static zstd library in the llvm-config system libs.
+/// - for `download-ci-llvm`, see if `lld` was built with zstd support.
+pub fn llvm_has_libzstd(config: &Config) -> bool {
+    // Strategy 1: works for local builds but not with `download-ci-llvm`.
+    //
+    // We check whether `llvm-config` returns the zstd library. Bootstrap's `llvm.libzstd` will only
+    // ask to statically link it when building LLVM, so we only check if the list of system libs
+    // contains a path to that static lib, and that it exists.
+    //
+    // See compiler/rustc_llvm/build.rs for more details and similar expectations.
+    fn is_zstd_in_config(llvm_bin_dir: &Path) -> Option<()> {
+        let llvm_config_path = llvm_bin_dir.join("llvm-config");
+        let output = Command::new(llvm_config_path).arg("--system-libs").output().ok()?;
+        assert!(output.status.success(), "running llvm-config --system-libs failed");
+
+        let libs = String::from_utf8(output.stdout).ok()?;
+        for lib in libs.split_whitespace() {
+            if lib.ends_with("libzstd.a") && Path::new(lib).exists() {
+                return Some(());
+            }
+        }
+
+        None
+    }
+
+    // Strategy 2: `download-ci-llvm`'s `llvm-config --system-libs` will not return any libs to
+    // use.
+    //
+    // The CI artifacts also don't contain the bootstrap config used to build them: otherwise we
+    // could have looked at the `llvm.libzstd` config.
+    //
+    // We infer whether `LLVM_ENABLE_ZSTD` was used to build LLVM as a byproduct of testing whether
+    // `lld` supports it. If not, an error will be emitted: "LLVM was not built with
+    // LLVM_ENABLE_ZSTD or did not find zstd at build time".
+    #[cfg(unix)]
+    fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> {
+        let lld_path = llvm_bin_dir.join("lld");
+        if lld_path.exists() {
+            // We can't call `lld` as-is, it expects to be invoked by a compiler driver using a
+            // different name. Prepare a temporary symlink to do that.
+            let lld_symlink_path = llvm_bin_dir.join("ld.lld");
+            if !lld_symlink_path.exists() {
+                std::os::unix::fs::symlink(lld_path, &lld_symlink_path).ok()?;
+            }
+
+            // Run `lld` with a zstd flag. We expect this command to always error here, we don't
+            // want to link actual files and don't pass any.
+            let output = Command::new(&lld_symlink_path)
+                .arg("--compress-debug-sections=zstd")
+                .output()
+                .ok()?;
+            assert!(!output.status.success());
+
+            // Look for a specific error caused by LLVM not being built with zstd support. We could
+            // also look for the "no input files" message, indicating the zstd flag was accepted.
+            let stderr = String::from_utf8(output.stderr).ok()?;
+            let zstd_available = !stderr.contains("LLVM was not built with LLVM_ENABLE_ZSTD");
+
+            // We don't particularly need to clean the link up (so the previous commands could fail
+            // in theory but won't in practice), but we can try.
+            std::fs::remove_file(lld_symlink_path).ok()?;
+
+            if zstd_available {
+                return Some(());
+            }
+        }
+
+        None
+    }
+
+    #[cfg(not(unix))]
+    fn is_lld_built_with_zstd(_llvm_bin_dir: &Path) -> Option<()> {
+        None
+    }
+
+    if let Some(llvm_bin_dir) = &config.llvm_bin_dir {
+        // Strategy 1: for local LLVM builds.
+        if is_zstd_in_config(llvm_bin_dir).is_some() {
+            return true;
+        }
+
+        // Strategy 2: for LLVM artifacts built on CI via `download-ci-llvm`.
+        //
+        // It doesn't work for cases where the artifacts don't contain the linker, but it's
+        // best-effort: CI has `llvm.libzstd` and `lld` enabled on the x64 linux artifacts, so it
+        // will at least work there.
+        //
+        // If this can be improved and expanded to less common cases in the future, it should.
+        if config.target == "x86_64-unknown-linux-gnu"
+            && config.host == config.target
+            && is_lld_built_with_zstd(llvm_bin_dir).is_some()
+        {
+            return true;
+        }
+    }
+
+    // Otherwise, all hope is lost.
+    false
+}
+
 /// Takes a directive of the form "<version1> [- <version2>]",
 /// returns the numeric representation of <version1> and <version2> as
 /// tuple: (<version1> as u32, <version2> as u32)
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 8f935d5b74441..e04abea0bf987 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -1,5 +1,5 @@
 use crate::common::{Config, Sanitizer};
-use crate::header::IgnoreDecision;
+use crate::header::{llvm_has_libzstd, IgnoreDecision};
 
 pub(super) fn handle_needs(
     cache: &CachedNeedsConditions,
@@ -144,6 +144,11 @@ pub(super) fn handle_needs(
             condition: cache.symlinks,
             ignore_reason: "ignored if symlinks are unavailable",
         },
+        Need {
+            name: "needs-llvm-zstd",
+            condition: cache.llvm_zstd,
+            ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression",
+        },
     ];
 
     let (name, comment) = match ln.split_once([':', ' ']) {
@@ -210,6 +215,8 @@ pub(super) struct CachedNeedsConditions {
     rust_lld: bool,
     dlltool: bool,
     symlinks: bool,
+    /// Whether LLVM built with zstd, for the `needs-llvm-zstd` directive.
+    llvm_zstd: bool,
 }
 
 impl CachedNeedsConditions {
@@ -253,6 +260,7 @@ impl CachedNeedsConditions {
                 .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
                 .exists(),
 
+            llvm_zstd: llvm_has_libzstd(&config),
             dlltool: find_dlltool(&config),
             symlinks: has_symlinks(),
         }

From 16b444d63a27388cb5c639c15d628606317b7ad0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sat, 10 Aug 2024 15:09:20 +0000
Subject: [PATCH 11/24] mark `rust-lld-compress-debug-sections` test as needing
 zstd

also make it fail if there's a compression issue
---
 .../rust-lld-compress-debug-sections/rmake.rs  | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/tests/run-make/rust-lld-compress-debug-sections/rmake.rs b/tests/run-make/rust-lld-compress-debug-sections/rmake.rs
index ea4997fab8099..9889659046ea7 100644
--- a/tests/run-make/rust-lld-compress-debug-sections/rmake.rs
+++ b/tests/run-make/rust-lld-compress-debug-sections/rmake.rs
@@ -1,12 +1,13 @@
 // Checks the `compress-debug-sections` option on rust-lld.
 
 //@ needs-rust-lld
+//@ needs-llvm-zstd
 //@ only-linux
 //@ ignore-cross-compile
 
 // FIXME: This test isn't comprehensive and isn't covering all possible combinations.
 
-use run_make_support::{assert_contains, llvm_readobj, run_in_tmpdir, rustc};
+use run_make_support::{llvm_readobj, run_in_tmpdir, rustc};
 
 fn check_compression(compression: &str, to_find: &str) {
     run_in_tmpdir(|| {
@@ -17,19 +18,8 @@ fn check_compression(compression: &str, to_find: &str) {
             .arg("-Cdebuginfo=full")
             .link_arg(&format!("-Wl,--compress-debug-sections={compression}"))
             .input("main.rs")
-            .run_unchecked();
-        let stderr = out.stderr_utf8();
-        if stderr.is_empty() {
-            llvm_readobj().arg("-t").arg("main").run().assert_stdout_contains(to_find);
-        } else {
-            assert_contains(
-                stderr,
-                format!(
-                    "LLVM was not built with LLVM_ENABLE_{to_find} \
-                     or did not find {compression} at build time"
-                ),
-            );
-        }
+            .run();
+        llvm_readobj().arg("-t").arg("main").run().assert_stdout_contains(to_find);
     });
 }
 

From 8b5118ca17bb11f76ac7bdf96b3cf91293f5be8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sat, 10 Aug 2024 15:52:58 +0000
Subject: [PATCH 12/24] make `compressed-debuginfo` test about zlib only

zlib is seemingly always enabled, so we can test it unconditionally
---
 tests/run-make/compressed-debuginfo/rmake.rs | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/tests/run-make/compressed-debuginfo/rmake.rs b/tests/run-make/compressed-debuginfo/rmake.rs
index 5ba1a1852d51b..362b2e2e1e449 100644
--- a/tests/run-make/compressed-debuginfo/rmake.rs
+++ b/tests/run-make/compressed-debuginfo/rmake.rs
@@ -1,11 +1,9 @@
-// Checks the `debuginfo-compression` option.
+// Checks the always enabled `debuginfo-compression` option: zlib.
 
 //@ only-linux
 //@ ignore-cross-compile
 
-// FIXME: This test isn't comprehensive and isn't covering all possible combinations.
-
-use run_make_support::{assert_contains, llvm_readobj, run_in_tmpdir, rustc};
+use run_make_support::{llvm_readobj, run_in_tmpdir, rustc};
 
 fn check_compression(compression: &str, to_find: &str) {
     run_in_tmpdir(|| {
@@ -17,19 +15,10 @@ fn check_compression(compression: &str, to_find: &str) {
             .arg(&format!("-Zdebuginfo-compression={compression}"))
             .input("foo.rs")
             .run();
-        let stderr = out.stderr_utf8();
-        if stderr.is_empty() {
-            llvm_readobj().arg("-t").arg("foo.o").run().assert_stdout_contains(to_find);
-        } else {
-            assert_contains(
-                stderr,
-                format!("unknown debuginfo compression algorithm {compression}"),
-            );
-        }
+        llvm_readobj().arg("-t").arg("foo.o").run().assert_stdout_contains(to_find);
     });
 }
 
 fn main() {
     check_compression("zlib", "ZLIB");
-    check_compression("zstd", "ZSTD");
 }

From de40866abb3dc046ede122bfae81bf84ce08ba77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sat, 10 Aug 2024 16:22:04 +0000
Subject: [PATCH 13/24] prepare test for expanding scope

---
 .../main.rs                                                       | 0
 .../rmake.rs                                                      | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename tests/run-make/{rust-lld-compress-debug-sections => compressed-debuginfo-zstd}/main.rs (100%)
 rename tests/run-make/{rust-lld-compress-debug-sections => compressed-debuginfo-zstd}/rmake.rs (100%)

diff --git a/tests/run-make/rust-lld-compress-debug-sections/main.rs b/tests/run-make/compressed-debuginfo-zstd/main.rs
similarity index 100%
rename from tests/run-make/rust-lld-compress-debug-sections/main.rs
rename to tests/run-make/compressed-debuginfo-zstd/main.rs
diff --git a/tests/run-make/rust-lld-compress-debug-sections/rmake.rs b/tests/run-make/compressed-debuginfo-zstd/rmake.rs
similarity index 100%
rename from tests/run-make/rust-lld-compress-debug-sections/rmake.rs
rename to tests/run-make/compressed-debuginfo-zstd/rmake.rs

From 9d24aa898d575f5b7a74f72aa5fe8efcacd39d1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sat, 10 Aug 2024 16:59:00 +0000
Subject: [PATCH 14/24] expand zstd debuginfo compression test

it now checks zlib and zstd, via rustc and rust-lld
---
 .../compressed-debuginfo-zstd/rmake.rs        | 33 +++++++++++++------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/tests/run-make/compressed-debuginfo-zstd/rmake.rs b/tests/run-make/compressed-debuginfo-zstd/rmake.rs
index 9889659046ea7..8356373e949aa 100644
--- a/tests/run-make/compressed-debuginfo-zstd/rmake.rs
+++ b/tests/run-make/compressed-debuginfo-zstd/rmake.rs
@@ -1,24 +1,37 @@
-// Checks the `compress-debug-sections` option on rust-lld.
+// Checks debuginfo compression both for the always-enabled zlib, and when the optional zstd is
+// enabled:
+// - via rustc's `debuginfo-compression`,
+// - and via rust-lld's `compress-debug-sections`
 
-//@ needs-rust-lld
-//@ needs-llvm-zstd
+//@ needs-llvm-zstd: we want LLVM/LLD to be built with zstd support
+//@ needs-rust-lld: the system linker will most likely not support zstd
 //@ only-linux
 //@ ignore-cross-compile
 
-// FIXME: This test isn't comprehensive and isn't covering all possible combinations.
-
-use run_make_support::{llvm_readobj, run_in_tmpdir, rustc};
+use run_make_support::{llvm_readobj, run_in_tmpdir, Rustc};
 
 fn check_compression(compression: &str, to_find: &str) {
+    // check compressed debug sections via rustc flag
+    prepare_and_check(to_find, |rustc| {
+        rustc.arg(&format!("-Zdebuginfo-compression={compression}"))
+    });
+
+    // check compressed debug sections via rust-lld flag
+    prepare_and_check(to_find, |rustc| {
+        rustc.link_arg(&format!("-Wl,--compress-debug-sections={compression}"))
+    });
+}
+
+fn prepare_and_check<F: FnOnce(&mut Rustc) -> &mut Rustc>(to_find: &str, prepare_rustc: F) {
     run_in_tmpdir(|| {
-        let out = rustc()
+        let mut rustc = Rustc::new();
+        rustc
             .arg("-Zlinker-features=+lld")
             .arg("-Clink-self-contained=+linker")
             .arg("-Zunstable-options")
             .arg("-Cdebuginfo=full")
-            .link_arg(&format!("-Wl,--compress-debug-sections={compression}"))
-            .input("main.rs")
-            .run();
+            .input("main.rs");
+        prepare_rustc(&mut rustc).run();
         llvm_readobj().arg("-t").arg("main").run().assert_stdout_contains(to_find);
     });
 }

From 182edede6085202dc748e538253a68d7aeff4781 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sat, 10 Aug 2024 22:25:22 +0000
Subject: [PATCH 15/24] move and rename zstd script

move it where it's used, and name it like the other scripts
---
 src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile      | 6 +++---
 .../zstd.sh => host-x86_64/dist-x86_64-linux/build-zstd.sh} | 0
 2 files changed, 3 insertions(+), 3 deletions(-)
 rename src/ci/docker/{scripts/zstd.sh => host-x86_64/dist-x86_64-linux/build-zstd.sh} (100%)

diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 61e9694f1e2ae..e857f38e68a85 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -62,9 +62,9 @@ COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
-# rustc's LLVM needs zstd.
-COPY scripts/zstd.sh /tmp/
-RUN ./zstd.sh
+# Build zstd to enable `llvm.libzstd`.
+COPY host-x86_64/dist-x86_64-linux/build-zstd.sh /tmp/
+RUN ./build-zstd.sh
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
diff --git a/src/ci/docker/scripts/zstd.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-zstd.sh
similarity index 100%
rename from src/ci/docker/scripts/zstd.sh
rename to src/ci/docker/host-x86_64/dist-x86_64-linux/build-zstd.sh

From 595052921f22c8184fe233e93b233a5db0a06936 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sun, 11 Aug 2024 15:02:13 +0000
Subject: [PATCH 16/24] strip whitespace for ignored tests reason comments

---
 src/tools/compiletest/src/header/needs.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index e04abea0bf987..72b1b9c6d480a 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -174,7 +174,7 @@ pub(super) fn handle_needs(
             } else {
                 return IgnoreDecision::Ignore {
                     reason: if let Some(comment) = comment {
-                        format!("{} ({comment})", need.ignore_reason)
+                        format!("{} ({})", need.ignore_reason, comment.trim())
                     } else {
                         need.ignore_reason.into()
                     },

From 9d29bf9a6be3f740a92b200d527c7ee9e819a75e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Sun, 11 Aug 2024 19:05:30 +0000
Subject: [PATCH 17/24] enable `llvm.libzstd` on test x64 linux builder

---
 src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
index 19683317126ab..83c2aa8cfb3b7 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile
@@ -28,5 +28,6 @@ ENV RUST_CONFIGURE_ARGS \
  --build=x86_64-unknown-linux-gnu \
  --enable-sanitizers \
  --enable-profiler \
- --enable-compiler-docs
+ --enable-compiler-docs \
+ --set llvm.libzstd=true
 ENV SCRIPT python3 ../x.py --stage 2 test

From 0452bf4981071b5eee30d7eed4a613072ec27acf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9my=20Rakic?= <remy.rakic+github@gmail.com>
Date: Tue, 20 Aug 2024 14:04:44 +0000
Subject: [PATCH 18/24] allow `llvm.libzstd` with `download-ci-llvm = true`

but warn about it
---
 src/bootstrap/src/core/config/config.rs | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index ce23b7735f8bd..bdfee55d8d183 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1885,6 +1885,22 @@ impl Config {
                     warn("link-shared");
                 }
 
+                // FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow,
+                // use the `builder-config` present in tarballs since #128822 to compare the local
+                // config to the ones used to build the LLVM artifacts on CI, and only notify users
+                // if they've chosen a different value.
+
+                if libzstd.is_some() {
+                    println!(
+                        "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \
+                        like almost all `llvm.*` options, will be ignored and set by the LLVM CI \
+                        artifacts builder config."
+                    );
+                    println!(
+                        "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false."
+                    );
+                }
+
                 // None of the LLVM options, except assertions, are supported
                 // when using downloaded LLVM. We could just ignore these but
                 // that's potentially confusing, so force them to not be
@@ -1894,7 +1910,6 @@ impl Config {
                 check_ci_llvm!(optimize_toml);
                 check_ci_llvm!(thin_lto);
                 check_ci_llvm!(release_debuginfo);
-                check_ci_llvm!(libzstd);
                 check_ci_llvm!(targets);
                 check_ci_llvm!(experimental_targets);
                 check_ci_llvm!(clang_cl);

From 5f2cedc5dc4ed5653069a83f1ed98b46f0c33c7c Mon Sep 17 00:00:00 2001
From: onur-ozkan <work@onurozkan.dev>
Date: Fri, 23 Aug 2024 12:08:41 +0300
Subject: [PATCH 19/24] handle stage0 cargo and rustc separately

This change allows setting either `build.cargo` or `build.rustc` without requiring
both to be set simultaneously, which was not possible previously.

To try it, set `build.rustc` without setting `build.cargo`, and try to bootstrap on clean build.

Signed-off-by: onur-ozkan <work@onurozkan.dev>
---
 src/bootstrap/bootstrap.py | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 4e8e0fd2532f1..0490d31fa584d 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -533,9 +533,13 @@ def download_toolchain(self):
         bin_root = self.bin_root()
 
         key = self.stage0_compiler.date
-        if self.rustc().startswith(bin_root) and \
-                (not os.path.exists(self.rustc()) or
-                 self.program_out_of_date(self.rustc_stamp(), key)):
+        is_outdated = self.program_out_of_date(self.rustc_stamp(), key)
+        need_rustc = self.rustc().startswith(bin_root) and (not os.path.exists(self.rustc()) \
+            or is_outdated)
+        need_cargo = self.cargo().startswith(bin_root) and (not os.path.exists(self.cargo()) \
+            or is_outdated)
+
+        if need_rustc or need_cargo:
             if os.path.exists(bin_root):
                 # HACK: On Windows, we can't delete rust-analyzer-proc-macro-server while it's
                 # running. Kill it.
@@ -556,7 +560,6 @@ def download_toolchain(self):
                     run_powershell([script])
                 shutil.rmtree(bin_root)
 
-            key = self.stage0_compiler.date
             cache_dst = (self.get_toml('bootstrap-cache-path', 'build') or
                 os.path.join(self.build_dir, "cache"))
 
@@ -568,11 +571,16 @@ def download_toolchain(self):
 
             toolchain_suffix = "{}-{}{}".format(rustc_channel, self.build, tarball_suffix)
 
-            tarballs_to_download = [
-                ("rust-std-{}".format(toolchain_suffix), "rust-std-{}".format(self.build)),
-                ("rustc-{}".format(toolchain_suffix), "rustc"),
-                ("cargo-{}".format(toolchain_suffix), "cargo"),
-            ]
+            tarballs_to_download = []
+
+            if need_rustc:
+                tarballs_to_download.append(
+                    ("rust-std-{}".format(toolchain_suffix), "rust-std-{}".format(self.build))
+                )
+                tarballs_to_download.append(("rustc-{}".format(toolchain_suffix), "rustc"))
+
+            if need_cargo:
+                tarballs_to_download.append(("cargo-{}".format(toolchain_suffix), "cargo"))
 
             tarballs_download_info = [
                 DownloadInfo(

From 69ca95bf7f5462eb7ade2de18d1f0d79b2c21cfd Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Fri, 23 Aug 2024 11:48:04 -0400
Subject: [PATCH 20/24] use tuples for semver, not floats

---
 src/bootstrap/bootstrap.py         |  7 +++++--
 src/bootstrap/src/core/download.rs | 18 +++++++++++-------
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5ea4b4882a975..c19134b4594fb 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -80,7 +80,10 @@ def get(base, url, path, checksums, verbose=False):
             os.unlink(temp_path)
 
 def curl_version():
-    return float(re.match(bytes("^curl ([0-9]+\\.[0-9]+)", "utf8"), require(["curl", "-V"]))[1])
+    m = re.match(bytes("^curl ([0-9]+)\\.([0-9]+)", "utf8"), require(["curl", "-V"]))
+    if m is None:
+        return (0, 0)
+    return (int(m[1]), int(m[2]))
 
 def download(path, url, probably_big, verbose):
     for _ in range(4):
@@ -110,7 +113,7 @@ def _download(path, url, probably_big, verbose, exception):
         #   but raise `CalledProcessError` or `OSError` instead
         require(["curl", "--version"], exception=platform_is_win32())
         extra_flags = []
-        if curl_version() > 7.70:
+        if curl_version() > (7, 70):
             extra_flags = [ "--retry-all-errors" ]
         run(["curl", option] + extra_flags + [
             "-L", # Follow redirect.
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 201addaec2fc5..fd6f17130ee91 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -21,19 +21,23 @@ fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> {
     config.try_run(cmd)
 }
 
-fn extract_curl_version(out: &[u8]) -> f32 {
+fn extract_curl_version(out: &[u8]) -> (u16, u16) {
     let out = &out[5..];
-    let Some(i) = out.iter().position(|&x| x == b' ') else { return 0.0 };
+    let Some(i) = out.iter().position(|&x| x == b' ') else { return (0, 0) };
     let out = &out[..i];
-    let Some(k) = out.iter().rev().position(|&x| x == b'.') else { return 0.0 };
+    let Some(k) = out.iter().rev().position(|&x| x == b'.') else { return (0, 0) };
     let out = &out[..out.len() - k - 1];
-    std::str::from_utf8(out).unwrap().parse().unwrap_or(0.0)
+    let Ok(s) = std::str::from_utf8(out) else { return (0, 0) };
+    let parts = s.split('.').collect::<Vec<_>>();
+    let [s_major, s_minor] = &parts[..] else { return (0, 0) };
+    let (Ok(major), Ok(minor)) = (s_major.parse(), s_minor.parse()) else { return (0, 0) };
+    (major, minor)
 }
 
-fn curl_version() -> f32 {
+fn curl_version() -> (u16, u16) {
     let mut curl = Command::new("curl");
     curl.arg("-V");
-    let Ok(out) = curl.output() else { return 0.0 };
+    let Ok(out) = curl.output() else { return (0, 0) };
     let out = out.stdout;
     extract_curl_version(&out)
 }
@@ -249,7 +253,7 @@ impl Config {
             curl.arg("--progress-bar");
         }
         // --retry-all-errors was added in 7.71.0, don't use it if curl is old.
-        if curl_version() > 7.70 {
+        if curl_version() > (7, 70) {
             curl.arg("--retry-all-errors");
         }
         curl.arg(url);

From 9ccd7abefeba2bde9e3366b5bb3985375fb0b8e6 Mon Sep 17 00:00:00 2001
From: Jubilee Young <workingjubilee@gmail.com>
Date: Wed, 21 Aug 2024 22:32:03 -0700
Subject: [PATCH 21/24] library: Move unstable API of new_uninit to new
 features

- `new_zeroed` variants move to `new_zeroed_alloc`
- the `write` fn moves to `box_uninit_write`

The remainder will be stabilized in upcoming patches, as
it was decided to only stabilize `uninit*` and `assume_init`.
---
 compiler/rustc_index/src/lib.rs |  1 +
 library/alloc/src/boxed.rs      |  9 ++++++---
 library/alloc/src/rc.rs         |  6 ++++--
 library/alloc/src/sync.rs       | 10 ++++++----
 library/std/src/lib.rs          |  1 +
 5 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index b5e4f02a8d15c..b9d2a43206b1e 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -2,6 +2,7 @@
 #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
 #![cfg_attr(feature = "nightly", allow(internal_features))]
 #![cfg_attr(feature = "nightly", feature(extend_one, new_uninit, step_trait, test))]
+#![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))]
 // tidy-alphabetical-end
 
 pub mod bit_set;
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 7de412595993a..c8e8d2a22ca48 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -293,6 +293,7 @@ impl<T> Box<T> {
     ///
     /// ```
     /// #![feature(new_uninit)]
+    /// #![feature(new_zeroed_alloc)]
     ///
     /// let zero = Box::<u32>::new_zeroed();
     /// let zero = unsafe { zero.assume_init() };
@@ -303,7 +304,7 @@ impl<T> Box<T> {
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
     #[inline]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "new_zeroed_alloc", issue = "129396")]
     #[must_use]
     pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
         Self::new_zeroed_in(Global)
@@ -684,6 +685,7 @@ impl<T> Box<[T]> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(new_zeroed_alloc)]
     /// #![feature(new_uninit)]
     ///
     /// let values = Box::<[u32]>::new_zeroed_slice(3);
@@ -694,7 +696,7 @@ impl<T> Box<[T]> {
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "new_zeroed_alloc", issue = "129396")]
     #[must_use]
     pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
         unsafe { RawVec::with_capacity_zeroed(len).into_box(len) }
@@ -955,6 +957,7 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(box_uninit_write)]
     /// #![feature(new_uninit)]
     ///
     /// let big_box = Box::<[usize; 1024]>::new_uninit();
@@ -972,7 +975,7 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
     ///     assert_eq!(*x, i);
     /// }
     /// ```
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "box_uninit_write", issue = "129397")]
     #[inline]
     pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
         unsafe {
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index bdee06154faec..f153aa6d3be9a 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -539,6 +539,7 @@ impl<T> Rc<T> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(new_zeroed_alloc)]
     /// #![feature(new_uninit)]
     ///
     /// use std::rc::Rc;
@@ -551,7 +552,7 @@ impl<T> Rc<T> {
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "new_zeroed_alloc", issue = "129396")]
     #[must_use]
     pub fn new_zeroed() -> Rc<mem::MaybeUninit<T>> {
         unsafe {
@@ -1000,6 +1001,7 @@ impl<T> Rc<[T]> {
     ///
     /// ```
     /// #![feature(new_uninit)]
+    /// #![feature(new_zeroed_alloc)]
     ///
     /// use std::rc::Rc;
     ///
@@ -1011,7 +1013,7 @@ impl<T> Rc<[T]> {
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "new_zeroed_alloc", issue = "129396")]
     #[must_use]
     pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
         unsafe {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 2c0d19b0ada09..4a3522f1a641b 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -542,6 +542,7 @@ impl<T> Arc<T> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(new_zeroed_alloc)]
     /// #![feature(new_uninit)]
     ///
     /// use std::sync::Arc;
@@ -555,7 +556,7 @@ impl<T> Arc<T> {
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
     #[inline]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "new_zeroed_alloc", issue = "129396")]
     #[must_use]
     pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> {
         unsafe {
@@ -1134,6 +1135,7 @@ impl<T> Arc<[T]> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(new_zeroed_alloc)]
     /// #![feature(new_uninit)]
     ///
     /// use std::sync::Arc;
@@ -1147,7 +1149,7 @@ impl<T> Arc<[T]> {
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
     #[inline]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "new_zeroed_alloc", issue = "129396")]
     #[must_use]
     pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
         unsafe {
@@ -1191,7 +1193,7 @@ impl<T, A: Allocator> Arc<[T], A> {
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
     #[cfg(not(no_global_oom_handling))]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn new_uninit_slice_in(len: usize, alloc: A) -> Arc<[mem::MaybeUninit<T>], A> {
         unsafe { Arc::from_ptr_in(Arc::allocate_for_slice_in(len, &alloc), alloc) }
@@ -1220,7 +1222,7 @@ impl<T, A: Allocator> Arc<[T], A> {
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
-    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Arc<[mem::MaybeUninit<T>], A> {
         unsafe {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 2530a37638757..f65e9bc8d8b5a 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -363,6 +363,7 @@
 #![feature(get_mut_unchecked)]
 #![feature(map_try_insert)]
 #![feature(new_uninit)]
+#![feature(new_zeroed_alloc)]
 #![feature(slice_concat_trait)]
 #![feature(thin_box)]
 #![feature(try_reserve_kind)]

From 90b4e17a1f6604db7f55b45b8b70c2db0afcec14 Mon Sep 17 00:00:00 2001
From: Miguel Ojeda <ojeda@kernel.org>
Date: Fri, 23 Aug 2024 09:28:30 +0200
Subject: [PATCH 22/24] CI: rfl: move to temporary commit

Link: https://github.com/rust-lang/rust/pull/129416
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 src/ci/docker/scripts/rfl-build.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh
index d690aac27fae6..389abb2fdd38c 100755
--- a/src/ci/docker/scripts/rfl-build.sh
+++ b/src/ci/docker/scripts/rfl-build.sh
@@ -2,7 +2,7 @@
 
 set -euo pipefail
 
-LINUX_VERSION=v6.11-rc1
+LINUX_VERSION=4c7864e81d8bbd51036dacf92fb0a400e13aaeee
 
 # Build rustc, rustdoc and cargo
 ../x.py build --stage 1 library rustdoc
@@ -28,7 +28,7 @@ rm -rf linux || true
 # Download Linux at a specific commit
 mkdir -p linux
 git -C linux init
-git -C linux remote add origin https://github.com/torvalds/linux.git
+git -C linux remote add origin https://github.com/Rust-for-Linux/linux.git
 git -C linux fetch --depth 1 origin ${LINUX_VERSION}
 git -C linux checkout FETCH_HEAD
 

From c36b5634cfde381fda497f71602158ce2c27ae5e Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 24 Aug 2024 18:34:28 +0200
Subject: [PATCH 23/24] Update minifier to 0.3.1

---
 Cargo.lock                | 7 +++++--
 src/librustdoc/Cargo.toml | 2 +-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index f2e2baea8e47c..724d7a0ed5512 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2230,9 +2230,12 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95bbbf96b9ac3482c2a25450b67a15ed851319bc5fabf3b40742ea9066e84282"
+checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437"
+dependencies = [
+ "clap",
+]
 
 [[package]]
 name = "minimal-lexical"
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index b3fccbf6456e0..34332de80b365 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -12,7 +12,7 @@ rinja = { version = "0.3", default-features = false, features = ["config"] }
 base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
-minifier = "0.3.0"
+minifier = "0.3.1"
 pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }

From 56adf87213b22ef848fb8afd3b8180c0455456d7 Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Sat, 24 Aug 2024 12:41:40 -0400
Subject: [PATCH 24/24] rewrite extract_curl_version again

---
 src/bootstrap/src/core/download.rs | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index fd6f17130ee91..b5c55854eff58 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -21,23 +21,20 @@ fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> {
     config.try_run(cmd)
 }
 
-fn extract_curl_version(out: &[u8]) -> (u16, u16) {
-    let out = &out[5..];
-    let Some(i) = out.iter().position(|&x| x == b' ') else { return (0, 0) };
-    let out = &out[..i];
-    let Some(k) = out.iter().rev().position(|&x| x == b'.') else { return (0, 0) };
-    let out = &out[..out.len() - k - 1];
-    let Ok(s) = std::str::from_utf8(out) else { return (0, 0) };
-    let parts = s.split('.').collect::<Vec<_>>();
-    let [s_major, s_minor] = &parts[..] else { return (0, 0) };
-    let (Ok(major), Ok(minor)) = (s_major.parse(), s_minor.parse()) else { return (0, 0) };
-    (major, minor)
+fn extract_curl_version(out: &[u8]) -> semver::Version {
+    let out = String::from_utf8_lossy(out);
+    // The output should look like this: "curl <major>.<minor>.<patch> ..."
+    out.lines()
+        .next()
+        .and_then(|line| line.split(" ").nth(1))
+        .and_then(|version| semver::Version::parse(version).ok())
+        .unwrap_or(semver::Version::new(1, 0, 0))
 }
 
-fn curl_version() -> (u16, u16) {
+fn curl_version() -> semver::Version {
     let mut curl = Command::new("curl");
     curl.arg("-V");
-    let Ok(out) = curl.output() else { return (0, 0) };
+    let Ok(out) = curl.output() else { return semver::Version::new(1, 0, 0) };
     let out = out.stdout;
     extract_curl_version(&out)
 }
@@ -253,7 +250,7 @@ impl Config {
             curl.arg("--progress-bar");
         }
         // --retry-all-errors was added in 7.71.0, don't use it if curl is old.
-        if curl_version() > (7, 70) {
+        if curl_version() >= semver::Version::new(7, 71, 0) {
             curl.arg("--retry-all-errors");
         }
         curl.arg(url);