From 3b2436c1361e03d52b4d5d9a188ea94909bd245a Mon Sep 17 00:00:00 2001
From: Trevor Spiteri <tspiteri@ieee.org>
Date: Tue, 23 Apr 2024 15:49:00 +0200
Subject: [PATCH 1/8] unroll first iter of checked_ilog loop to save one
 multiplication

---
 library/core/src/num/uint_macros.rs | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index c13763243f031..a76b84e7e5412 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1093,9 +1093,12 @@ macro_rules! uint_impl {
         pub const fn checked_ilog(self, base: Self) -> Option<u32> {
             if self <= 0 || base <= 1 {
                 None
+            } else if self < base {
+                Some(0)
             } else {
-                let mut n = 0;
-                let mut r = 1;
+                // Since base >= self, n >= 1
+                let mut n = 1;
+                let mut r = base;
 
                 // Optimization for 128 bit wide integers.
                 if Self::BITS == 128 {

From 245cc23a2f7d55c22437b2482f057fa44cce0624 Mon Sep 17 00:00:00 2001
From: Trevor Spiteri <tspiteri@ieee.org>
Date: Tue, 23 Apr 2024 18:31:57 +0200
Subject: [PATCH 2/8] add codegen test

The test confirms that when val < base, we do not divide or multiply.
---
 tests/codegen/checked_ilog.rs | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 tests/codegen/checked_ilog.rs

diff --git a/tests/codegen/checked_ilog.rs b/tests/codegen/checked_ilog.rs
new file mode 100644
index 0000000000000..8f3c07119feeb
--- /dev/null
+++ b/tests/codegen/checked_ilog.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+// Ensure that when val < base, we do not divide or multiply.
+
+// CHECK-LABEL: @checked_ilog
+// CHECK-SAME: (i16 noundef %val, i16 noundef %base)
+#[no_mangle]
+pub fn checked_ilog(val: u16, base: u16) -> Option<u32> {
+    // CHECK-NOT: udiv
+    // CHECK-NOT: mul
+    // CHECK: %[[IS_LESS:.+]] = icmp ult i16 %val, %base
+    // CHECK-NEXT: br i1 %[[IS_LESS]], label %[[TRUE:.+]], label %[[FALSE:.+]]
+    // CHECK: [[TRUE]]:
+    // CHECK-NOT: udiv
+    // CHECK-NOT: mul
+    // CHECK: ret { i32, i32 }
+    val.checked_ilog(base)
+}

From a7e7848833d7a5a3f26249603ba3545ab18e7431 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Fri, 31 May 2024 17:02:27 +0200
Subject: [PATCH 3/8] Refactor --print=check-cfg test

---
 tests/run-make/print-check-cfg/rmake.rs | 150 ++++++++++++++----------
 1 file changed, 86 insertions(+), 64 deletions(-)

diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs
index f7f5fcf2340bb..2d52216442653 100644
--- a/tests/run-make/print-check-cfg/rmake.rs
+++ b/tests/run-make/print-check-cfg/rmake.rs
@@ -8,61 +8,70 @@ use std::ops::Deref;
 
 use run_make_support::rustc;
 
+struct CheckCfg {
+    args: &'static [&'static str],
+    contains: Contains,
+}
+
+enum Contains {
+    Some { contains: &'static [&'static str], doesnt_contain: &'static [&'static str] },
+    Only(&'static str),
+}
+
 fn main() {
-    check(
-        /*args*/ &[],
-        /*has_any*/ false,
-        /*has_any_any*/ true,
-        /*contains*/ &[],
-    );
-    check(
-        /*args*/ &["--check-cfg=cfg()"],
-        /*has_any*/ false,
-        /*has_any_any*/ false,
-        /*contains*/ &["unix", "miri"],
-    );
-    check(
-        /*args*/ &["--check-cfg=cfg(any())"],
-        /*has_any*/ true,
-        /*has_any_any*/ false,
-        /*contains*/ &["windows", "test"],
-    );
-    check(
-        /*args*/ &["--check-cfg=cfg(feature)"],
-        /*has_any*/ false,
-        /*has_any_any*/ false,
-        /*contains*/ &["unix", "miri", "feature"],
-    );
-    check(
-        /*args*/ &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#],
-        /*has_any*/ false,
-        /*has_any_any*/ false,
-        /*contains*/ &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""],
-    );
-    check(
-        /*args*/
-        &[
+    check(CheckCfg { args: &[], contains: Contains::Only("any()=any()") });
+    check(CheckCfg {
+        args: &["--check-cfg=cfg()"],
+        contains: Contains::Some {
+            contains: &["unix", "miri"],
+            doesnt_contain: &["any()", "any()=any()"],
+        },
+    });
+    check(CheckCfg {
+        args: &["--check-cfg=cfg(any())"],
+        contains: Contains::Some {
+            contains: &["any()", "unix", r#"target_feature="crt-static""#],
+            doesnt_contain: &["any()=any()"],
+        },
+    });
+    check(CheckCfg {
+        args: &["--check-cfg=cfg(feature)"],
+        contains: Contains::Some {
+            contains: &["unix", "miri", "feature"],
+            doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="],
+        },
+    });
+    check(CheckCfg {
+        args: &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#],
+        contains: Contains::Some {
+            contains: &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""],
+            doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="],
+        },
+    });
+    check(CheckCfg {
+        args: &[
             r#"--check-cfg=cfg(feature, values(any()))"#,
             r#"--check-cfg=cfg(feature, values("tmp"))"#,
         ],
-        /*has_any*/ false,
-        /*has_any_any*/ false,
-        /*contains*/ &["unix", "miri", "feature=any()"],
-    );
-    check(
-        /*args*/
-        &[
+        contains: Contains::Some {
+            contains: &["unix", "miri", "feature=any()"],
+            doesnt_contain: &["any()", "any()=any()", "feature", "feature=", "feature=\"tmp\""],
+        },
+    });
+    check(CheckCfg {
+        args: &[
             r#"--check-cfg=cfg(has_foo, has_bar)"#,
             r#"--check-cfg=cfg(feature, values("tmp"))"#,
             r#"--check-cfg=cfg(feature, values("tmp"))"#,
         ],
-        /*has_any*/ false,
-        /*has_any_any*/ false,
-        /*contains*/ &["has_foo", "has_bar", "feature=\"tmp\""],
-    );
+        contains: Contains::Some {
+            contains: &["has_foo", "has_bar", "feature=\"tmp\""],
+            doesnt_contain: &["any()", "any()=any()", "feature"],
+        },
+    });
 }
 
-fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) {
+fn check(CheckCfg { args, contains }: CheckCfg) {
     let output = rustc()
         .input("lib.rs")
         .arg("-Zunstable-options")
@@ -72,18 +81,11 @@ fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) {
 
     let stdout = String::from_utf8(output.stdout).unwrap();
 
-    let mut found_any = false;
-    let mut found_any_any = false;
     let mut found = HashSet::<String>::new();
-    let mut recorded = HashSet::<String>::new();
 
     for l in stdout.lines() {
         assert!(l == l.trim());
-        if l == "any()" {
-            found_any = true;
-        } else if l == "any()=any()" {
-            found_any_any = true;
-        } else if let Some((left, right)) = l.split_once('=') {
+        if let Some((left, right)) = l.split_once('=') {
             if right != "any()" && right != "" {
                 assert!(right.starts_with("\""));
                 assert!(right.ends_with("\""));
@@ -92,17 +94,37 @@ fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) {
         } else {
             assert!(!l.contains("\""));
         }
-        assert!(recorded.insert(l.to_string()), "{}", &l);
-        if contains.contains(&l) {
-            assert!(found.insert(l.to_string()), "{}", &l);
-        }
+        assert!(found.insert(l.to_string()), "{}", &l);
     }
 
-    let should_found = HashSet::<String>::from_iter(contains.iter().map(|s| s.to_string()));
-    let diff: Vec<_> = should_found.difference(&found).collect();
-
-    assert_eq!(found_any, has_any);
-    assert_eq!(found_any_any, has_any_any);
-    assert_eq!(found_any_any, recorded.len() == 1);
-    assert!(diff.is_empty(), "{:?} != {:?} (~ {:?})", &should_found, &found, &diff);
+    match contains {
+        Contains::Some { contains, doesnt_contain } => {
+            {
+                let should_found =
+                    HashSet::<String>::from_iter(contains.iter().map(|s| s.to_string()));
+                let diff: Vec<_> = should_found.difference(&found).collect();
+                assert!(
+                    diff.is_empty(),
+                    "should found: {:?}, didn't found {:?}",
+                    &should_found,
+                    &diff
+                );
+            }
+            {
+                let should_not_find =
+                    HashSet::<String>::from_iter(doesnt_contain.iter().map(|s| s.to_string()));
+                let diff: Vec<_> = should_not_find.intersection(&found).collect();
+                assert!(
+                    diff.is_empty(),
+                    "should not find {:?}, did found {:?}",
+                    &should_not_find,
+                    &diff
+                );
+            }
+        }
+        Contains::Only(only) => {
+            assert!(found.contains(&only.to_string()), "{:?} != {:?}", &only, &found);
+            assert!(found.len() == 1, "len: {}, instead of 1", found.len());
+        }
+    }
 }

From 95bd2a420415228484e5446d88e3eb2039acdad9 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Thu, 30 May 2024 16:31:59 +0200
Subject: [PATCH 4/8] Add `Cc::output` method

---
 src/tools/run-make-support/src/cc.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs
index 799c36b104999..0012e7b66af35 100644
--- a/src/tools/run-make-support/src/cc.rs
+++ b/src/tools/run-make-support/src/cc.rs
@@ -80,6 +80,13 @@ impl Cc {
         self
     }
 
+    /// Specify path of the output binary.
+    pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg("-o");
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
     /// Get the [`Output`][::std::process::Output] of the finished process.
     pub fn command_output(&mut self) -> ::std::process::Output {
         self.cmd.output().expect("failed to get output of finished process")

From aa0f8f9af1e2927f5b350feebb37884832bcac9b Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Fri, 31 May 2024 10:47:30 +0200
Subject: [PATCH 5/8] Add `dynamic_lib_extension` and `read_dir` functions to
 `run-make-support` library

---
 src/tools/run-make-support/src/lib.rs | 38 ++++++++++++++++++---------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 0cf64db6ac9c0..323fc40e6481e 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -123,12 +123,23 @@ pub fn dynamic_lib_name(name: &str) -> String {
     // ```
     assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
 
+    let extension = dynamic_lib_extension();
     if is_darwin() {
-        format!("lib{name}.dylib")
+        format!("lib{name}.{extension}")
     } else if is_windows() {
-        format!("{name}.dll")
+        format!("{name}.{extension}")
     } else {
-        format!("lib{name}.so")
+        format!("lib{name}.{extension}")
+    }
+}
+
+pub fn dynamic_lib_extension() -> &'static str {
+    if is_darwin() {
+        "dylib"
+    } else if is_windows() {
+        "dll"
+    } else {
+        "so"
     }
 }
 
@@ -249,16 +260,13 @@ pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
     }
 
     let dir2 = dir2.as_ref();
-    for entry in fs::read_dir(dir1).unwrap() {
-        let entry = entry.unwrap();
-        let entry_name = entry.file_name();
-        let path = entry.path();
-
-        if path.is_dir() {
-            recursive_diff(&path, &dir2.join(entry_name));
+    read_dir(dir1, |entry_path| {
+        let entry_name = entry_path.file_name().unwrap();
+        if entry_path.is_dir() {
+            recursive_diff(&entry_path, &dir2.join(entry_name));
         } else {
             let path2 = dir2.join(entry_name);
-            let file1 = read_file(&path);
+            let file1 = read_file(&entry_path);
             let file2 = read_file(&path2);
 
             // We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display.
@@ -267,10 +275,16 @@ pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
             assert!(
                 file1 == file2,
                 "`{}` and `{}` have different content",
-                path.display(),
+                entry_path.display(),
                 path2.display(),
             );
         }
+    });
+}
+
+pub fn read_dir<F: Fn(&Path)>(dir: impl AsRef<Path>, callback: F) {
+    for entry in fs::read_dir(dir).unwrap() {
+        callback(&entry.unwrap().path());
     }
 }
 

From ef4f8e631550f69719008835f565a1ae87fdb54e Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Fri, 31 May 2024 10:47:57 +0200
Subject: [PATCH 6/8] Migrate `run-make/c-link-to-rust-dylib` to `rmake.rs`

---
 .../tidy/src/allowed_run_make_makefiles.txt   |  1 -
 tests/run-make/c-link-to-rust-dylib/Makefile  | 21 ----------
 tests/run-make/c-link-to-rust-dylib/rmake.rs  | 41 +++++++++++++++++++
 3 files changed, 41 insertions(+), 22 deletions(-)
 delete mode 100644 tests/run-make/c-link-to-rust-dylib/Makefile
 create mode 100644 tests/run-make/c-link-to-rust-dylib/rmake.rs

diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 009200aca15de..7ad36b2b9a605 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -6,7 +6,6 @@ run-make/bare-outfile/Makefile
 run-make/branch-protection-check-IBT/Makefile
 run-make/c-dynamic-dylib/Makefile
 run-make/c-dynamic-rlib/Makefile
-run-make/c-link-to-rust-dylib/Makefile
 run-make/c-static-dylib/Makefile
 run-make/c-static-rlib/Makefile
 run-make/c-unwind-abi-catch-lib-panic/Makefile
diff --git a/tests/run-make/c-link-to-rust-dylib/Makefile b/tests/run-make/c-link-to-rust-dylib/Makefile
deleted file mode 100644
index 201f717ece49c..0000000000000
--- a/tests/run-make/c-link-to-rust-dylib/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-# This test checks that C linking with Rust does not encounter any errors, with dynamic libraries.
-# See https://github.com/rust-lang/rust/issues/10434
-
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(TMPDIR)/$(call BIN,bar)
-	$(call RUN,bar)
-	$(call REMOVE_DYLIBS,foo)
-	$(call FAIL,bar)
-
-ifdef IS_MSVC
-$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
-	$(CC) bar.c $(TMPDIR)/foo.dll.lib $(call OUT_EXE,bar)
-else
-$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
-	$(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) -L $(TMPDIR)
-endif
-
-$(call DYLIB,foo): foo.rs
-	$(RUSTC) foo.rs
diff --git a/tests/run-make/c-link-to-rust-dylib/rmake.rs b/tests/run-make/c-link-to-rust-dylib/rmake.rs
new file mode 100644
index 0000000000000..076bf56334d33
--- /dev/null
+++ b/tests/run-make/c-link-to-rust-dylib/rmake.rs
@@ -0,0 +1,41 @@
+// This test checks that C linking with Rust does not encounter any errors, with dynamic libraries.
+// See <https://github.com/rust-lang/rust/issues/10434>.
+
+//@ ignore-cross-compile
+
+use std::fs::remove_file;
+
+use run_make_support::{
+    dynamic_lib_extension, is_msvc, read_dir, run, run_fail, rustc, tmp_dir, Cc,
+};
+
+fn main() {
+    rustc().input("foo.rs").run();
+
+    if is_msvc() {
+        Cc::new().input("bar.c").arg(tmp_dir().join("foo.dll.lib")).out_exe("bar").run();
+    } else {
+        Cc::new()
+            .input("bar.c")
+            .arg("-lfoo")
+            .output(tmp_dir().join("bar"))
+            .library_search_path(tmp_dir())
+            .run();
+    }
+
+    run("bar");
+
+    let expected_extension = dynamic_lib_extension();
+    read_dir(tmp_dir(), |path| {
+        if path.is_file()
+            && path.extension().is_some_and(|ext| ext == expected_extension)
+            && path
+                .file_name()
+                .and_then(|name| name.to_str())
+                .is_some_and(|name| name.starts_with("lib"))
+        {
+            remove_file(path).unwrap();
+        }
+    });
+    run_fail("bar");
+}

From b0d0cc6590925aa5493f3810d0f581bf9c476714 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Thu, 30 May 2024 16:31:59 +0200
Subject: [PATCH 7/8] Add `Cc::output` method

---
 src/tools/run-make-support/src/cc.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs
index 799c36b104999..0012e7b66af35 100644
--- a/src/tools/run-make-support/src/cc.rs
+++ b/src/tools/run-make-support/src/cc.rs
@@ -80,6 +80,13 @@ impl Cc {
         self
     }
 
+    /// Specify path of the output binary.
+    pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg("-o");
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
     /// Get the [`Output`][::std::process::Output] of the finished process.
     pub fn command_output(&mut self) -> ::std::process::Output {
         self.cmd.output().expect("failed to get output of finished process")

From 8742bf375b067096c2d3c6898a311cd0e80fde56 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Thu, 30 May 2024 16:32:12 +0200
Subject: [PATCH 8/8] Migrate `run-make/cdylib` to `rmake.rs`

---
 .../tidy/src/allowed_run_make_makefiles.txt   |  1 -
 tests/run-make/cdylib/Makefile                | 23 ------------
 tests/run-make/cdylib/rmake.rs                | 36 +++++++++++++++++++
 3 files changed, 36 insertions(+), 24 deletions(-)
 delete mode 100644 tests/run-make/cdylib/Makefile
 create mode 100644 tests/run-make/cdylib/rmake.rs

diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 009200aca15de..ebe9d2b7bb0b9 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -14,7 +14,6 @@ run-make/c-unwind-abi-catch-panic/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
 run-make/cdylib-dylib-linkage/Makefile
 run-make/cdylib-fewer-symbols/Makefile
-run-make/cdylib/Makefile
 run-make/codegen-options-parsing/Makefile
 run-make/comment-section/Makefile
 run-make/compiler-lookup-paths-2/Makefile
diff --git a/tests/run-make/cdylib/Makefile b/tests/run-make/cdylib/Makefile
deleted file mode 100644
index 2c6414c32553c..0000000000000
--- a/tests/run-make/cdylib/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-# When the cdylib crate type was added as a variation of dylib, it needed a test to check its function.
-# See https://github.com/rust-lang/rust/pull/33553
-
-# ignore-cross-compile
-include ../tools.mk
-
-all: $(call RUN_BINFILE,foo)
-	$(call RUN,foo)
-	rm $(call DYLIB,foo)
-	$(RUSTC) foo.rs -C lto
-	$(call RUN,foo)
-
-ifdef IS_MSVC
-$(call RUN_BINFILE,foo): $(call DYLIB,foo)
-	$(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.dll.lib $(call OUT_EXE,foo)
-else
-$(call RUN_BINFILE,foo): $(call DYLIB,foo)
-	$(CC) $(CFLAGS) foo.c -lfoo -o $(call RUN_BINFILE,foo) -L $(TMPDIR)
-endif
-
-$(call DYLIB,foo):
-	$(RUSTC) bar.rs
-	$(RUSTC) foo.rs
diff --git a/tests/run-make/cdylib/rmake.rs b/tests/run-make/cdylib/rmake.rs
new file mode 100644
index 0000000000000..fcb4f56621f65
--- /dev/null
+++ b/tests/run-make/cdylib/rmake.rs
@@ -0,0 +1,36 @@
+// This test tries to check that basic cdylib libraries can be compiled and linked successfully
+// with C code, that the cdylib itself can depend on another rlib, and that the library can be built
+// with LTO.
+//
+// - `bar.rs` is a rlib
+// - `foo.rs` is a cdylib that relies on an extern crate `bar` and defines two `extern "C"`
+//   functions:
+//     - `foo()` which calls `bar::bar()`.
+//     - `bar()` which implements basic addition.
+
+//@ ignore-cross-compile
+
+use std::fs::remove_file;
+
+use run_make_support::{cc, dynamic_lib, is_msvc, run, rustc, tmp_dir};
+
+fn main() {
+    rustc().input("bar.rs").run();
+    rustc().input("foo.rs").run();
+
+    if is_msvc() {
+        cc().input("foo.c").arg(tmp_dir().join("foo.dll.lib")).out_exe("foo").run();
+    } else {
+        cc().input("foo.c")
+            .arg("-lfoo")
+            .output(tmp_dir().join("foo"))
+            .library_search_path(tmp_dir())
+            .run();
+    }
+
+    run("foo");
+    remove_file(dynamic_lib("foo")).unwrap();
+
+    rustc().input("foo.rs").arg("-Clto").run();
+    run("foo");
+}