From 43b7e28601b7ea0c1d77e6df5f5af97cd55531ff Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Mon, 13 Jan 2025 10:53:58 -0500
Subject: [PATCH 01/11] Merge commit '59a81c2ca1edc88ad3ac4b27a8e03977ffb8e73a'
 into subtree-update_cg_gcc_2025_01_12

---
 .github/workflows/ci.yml                      |   7 +-
 .github/workflows/failures.yml                |   7 +-
 .github/workflows/gcc12.yml                   |   3 -
 .github/workflows/m68k.yml                    |   5 +-
 .github/workflows/release.yml                 |  10 +-
 .github/workflows/stdarch.yml                 |   5 +-
 Cargo.lock                                    | 154 +++++++++-
 Cargo.toml                                    |   5 +-
 build_system/src/test.rs                      |  86 ++++--
 example/mini_core.rs                          |   8 +
 libgccjit.version                             |   2 +-
 ...022-core-Disable-not-compiling-tests.patch |  13 +-
 ...0001-core-Disable-portable-simd-test.patch |   3 +-
 rust-toolchain                                |   2 +-
 src/allocator.rs                              |  26 +-
 src/back/lto.rs                               |  37 ++-
 src/back/write.rs                             | 157 +++++++---
 src/base.rs                                   |  48 ++-
 src/builder.rs                                |  72 +++--
 src/callee.rs                                 | 143 ++++-----
 src/common.rs                                 |   6 +-
 src/consts.rs                                 |   3 +-
 src/context.rs                                |   1 +
 src/errors.rs                                 |   4 -
 src/gcc_util.rs                               |  44 ++-
 src/int.rs                                    |   4 +-
 src/intrinsic/llvm.rs                         |   2 +-
 src/intrinsic/mod.rs                          |  21 +-
 src/intrinsic/simd.rs                         |   3 +-
 src/lib.rs                                    |  38 +--
 tests/failing-non-lto-tests.txt               |  11 -
 tests/failing-ui-tests.txt                    |  32 +-
 tests/failing-ui-tests12.txt                  |   1 -
 tests/hello-world/Cargo.lock                  |  14 +
 tests/hello-world/Cargo.toml                  |   8 +
 tests/hello-world/mylib/Cargo.lock            |   5 +
 tests/hello-world/mylib/Cargo.toml            |   9 +
 tests/hello-world/mylib/src/lib.rs            |   7 +
 tests/hello-world/src/main.rs                 |   4 +-
 tests/lang_tests_common.rs                    |  24 +-
 tests/run/array.rs                            | 206 +------------
 tests/run/closure.rs                          | 184 +----------
 tests/run/condition.rs                        | 288 +-----------------
 tests/run/fun_ptr.rs                          | 196 +-----------
 tests/run/operations.rs                       |   4 +-
 tests/run/ptr_cast.rs                         | 196 +-----------
 tests/run/return-tuple.rs                     |  28 +-
 tests/run/slice.rs                            | 101 +-----
 tests/run/volatile2.rs                        | 113 +++++++
 49 files changed, 828 insertions(+), 1522 deletions(-)
 delete mode 100644 tests/failing-non-lto-tests.txt
 create mode 100644 tests/hello-world/Cargo.lock
 create mode 100644 tests/hello-world/mylib/Cargo.lock
 create mode 100644 tests/hello-world/mylib/Cargo.toml
 create mode 100644 tests/hello-world/mylib/src/lib.rs
 create mode 100644 tests/run/volatile2.rs

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 704d7b9c2fd6a..73ec6b84a155e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -22,7 +22,6 @@ jobs:
           - { gcc: "gcc-13.deb" }
           - { gcc: "gcc-13-without-int128.deb" }
         commands: [
-          "--mini-tests",
           "--std-tests",
           # FIXME: re-enable asm tests when GCC can emit in the right syntax.
           # "--asm-tests",
@@ -79,6 +78,7 @@ jobs:
       run: |
         ./y.sh prepare --only-libcore
         ./y.sh build --sysroot
+        ./y.sh test --mini-tests
         cargo test
 
     - name: Run y.sh cargo build
@@ -87,7 +87,7 @@ jobs:
 
     - name: Clean
       run: |
-        ./y.sh clean all      
+        ./y.sh clean all
 
     - name: Prepare dependencies
       run: |
@@ -95,9 +95,6 @@ jobs:
         git config --global user.name "User"
         ./y.sh prepare
 
-    - name: Add more failing tests because the sysroot is not compiled with LTO
-      run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     - name: Run tests
       run: |
         ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}
diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml
index 2c1ed9ad42948..f33d9fcc58257 100644
--- a/.github/workflows/failures.yml
+++ b/.github/workflows/failures.yml
@@ -90,15 +90,12 @@ jobs:
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       run: ./y.sh prepare
 
-    - name: Add more failing tests because the sysroot is not compiled with LTO
-      run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     - name: Run tests
       # TODO: re-enable those tests for libgccjit 12.
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       id: tests
       run: |
-        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} | tee output_log
+        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --clean --build-sysroot --test-failing-rustc ${{ matrix.libgccjit_version.extra }} 2>&1 | tee output_log
         rg --text "test result" output_log >> $GITHUB_STEP_SUMMARY
 
     - name: Run failing ui pattern tests for ICE
@@ -106,7 +103,7 @@ jobs:
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       id: ui-tests
       run: |
-        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --test-failing-ui-pattern-tests ${{ matrix.libgccjit_version.extra }} | tee output_log_ui
+        ${{ matrix.libgccjit_version.env_extra }} ./y.sh test --release --test-failing-ui-pattern-tests ${{ matrix.libgccjit_version.extra }} 2>&1 | tee output_log_ui
         if grep -q "the compiler unexpectedly panicked" output_log_ui; then
           echo "Error: 'the compiler unexpectedly panicked' found in output logs. CI Error!!"
           exit 1
diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml
index 7dcad21a02e1d..4c2ce91e86eef 100644
--- a/.github/workflows/gcc12.yml
+++ b/.github/workflows/gcc12.yml
@@ -82,9 +82,6 @@ jobs:
     #- name: Add more failing tests for GCC 12
       #run: cat tests/failing-ui-tests12.txt >> tests/failing-ui-tests.txt
 
-    #- name: Add more failing tests because the sysroot is not compiled with LTO
-      #run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     #- name: Run tests
       #run: |
         #./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features
diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml
index 1c864e04413f6..07bb372b3606d 100644
--- a/.github/workflows/m68k.yml
+++ b/.github/workflows/m68k.yml
@@ -23,7 +23,6 @@ jobs:
       fail-fast: false
       matrix:
         commands: [
-          "--mini-tests",
           "--std-tests",
           # TODO(antoyo): fix those on m68k.
           #"--test-libcore",
@@ -93,6 +92,7 @@ jobs:
       run: |
         ./y.sh prepare --only-libcore --cross
         ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu
+        ./y.sh test --mini-tests
         CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test
         ./y.sh clean all
 
@@ -102,9 +102,6 @@ jobs:
         git config --global user.name "User"
         ./y.sh prepare --cross
 
-    - name: Add more failing tests because the sysroot is not compiled with LTO
-      run: cat tests/failing-non-lto-tests.txt >> tests/failing-ui-tests.txt
-
     - name: Run tests
       run: |
         ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d5c06a836db94..60e0943c87dac 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -13,7 +13,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-22.04
 
     strategy:
       fail-fast: false
@@ -54,6 +54,7 @@ jobs:
       run: |
         ./y.sh prepare --only-libcore
         EMBED_LTO_BITCODE=1 ./y.sh build --sysroot --release --release-sysroot
+        ./y.sh test --mini-tests
         cargo test
         ./y.sh clean all
 
@@ -70,4 +71,9 @@ jobs:
       run: |
         # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros.
         echo -n 'lto = "fat"' >> build_system/build_sysroot/Cargo.toml
-        EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }}
+        EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }}
+
+    - name: Run y.sh cargo build
+      run: |
+        EMBED_LTO_BITCODE=1 CHANNEL="release" ./y.sh cargo build --release --manifest-path tests/hello-world/Cargo.toml
+        # TODO: grep the asm output for "call my_func" and fail if it is found.
diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml
index d8818eefa96d8..d5ae6144496f1 100644
--- a/.github/workflows/stdarch.yml
+++ b/.github/workflows/stdarch.yml
@@ -73,10 +73,6 @@ jobs:
         echo "LD_LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV
         echo "LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV
 
-    - name: Build (part 2)
-      run: |
-        cargo test
-
     - name: Clean
       if: ${{ !matrix.cargo_runner }}
       run: |
@@ -92,6 +88,7 @@ jobs:
       if: ${{ !matrix.cargo_runner }}
       run: |
         ./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore
+        cargo test
 
     - name: Run stdarch tests
       if: ${{ !matrix.cargo_runner }}
diff --git a/Cargo.lock b/Cargo.lock
index 6b06e7d7f278a..636e75b94a3f2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "aho-corasick"
@@ -11,12 +11,40 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
 [[package]]
 name = "boml"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5"
 
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "errno"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
 [[package]]
 name = "fm"
 version = "0.2.2"
@@ -28,18 +56,18 @@ dependencies = [
 
 [[package]]
 name = "gccjit"
-version = "2.2.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bb376e98c82d9284c3a17fc1d6bf9bc921055418950238d7a553c27a7e1f6ab"
+checksum = "72fd91f4adbf02b53cfc73c97bc33c5f253009043f30c56a5ec08dd5c8094dc8"
 dependencies = [
  "gccjit_sys",
 ]
 
 [[package]]
 name = "gccjit_sys"
-version = "0.3.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93b4b1be553b5df790bf25ca2a1d6add81727dc29f8d5c8742468ed306d621d1"
+checksum = "0fb7b8f48a75e2cfe78c3d9a980b32771c34ffd12d196021ab3f98c49fbd2f0d"
 dependencies = [
  "libc",
 ]
@@ -77,9 +105,15 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.150"
+version = "0.2.168"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
+checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "memchr"
@@ -97,6 +131,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
 [[package]]
 name = "regex"
 version = "1.8.4"
@@ -121,6 +161,20 @@ dependencies = [
  "boml",
  "gccjit",
  "lang_tester",
+ "tempfile",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
 ]
 
 [[package]]
@@ -132,6 +186,19 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "tempfile"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys",
+]
+
 [[package]]
 name = "termcolor"
 version = "1.2.0"
@@ -205,3 +272,76 @@ name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/Cargo.toml b/Cargo.toml
index 4828b7ddb1686..63d37358561e6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,15 +22,16 @@ master = ["gccjit/master"]
 default = ["master"]
 
 [dependencies]
-gccjit = "2.2"
+gccjit = "2.4"
 #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" }
 
 # Local copy.
 #gccjit = { path = "../gccjit.rs" }
 
 [dev-dependencies]
-lang_tester = "0.8.0"
 boml = "0.3.1"
+lang_tester = "0.8.0"
+tempfile = "3.7.1"
 
 [profile.dev]
 # By compiling dependencies with optimizations, performing tests gets much faster.
diff --git a/build_system/src/test.rs b/build_system/src/test.rs
index c69e240c01de4..7cc7336612c79 100644
--- a/build_system/src/test.rs
+++ b/build_system/src/test.rs
@@ -93,6 +93,7 @@ struct TestArg {
     sysroot_panic_abort: bool,
     config_info: ConfigInfo,
     sysroot_features: Vec<String>,
+    keep_lto_tests: bool,
 }
 
 impl TestArg {
@@ -128,6 +129,9 @@ impl TestArg {
                 "--sysroot-panic-abort" => {
                     test_arg.sysroot_panic_abort = true;
                 }
+                "--keep-lto-tests" => {
+                    test_arg.keep_lto_tests = true;
+                }
                 "--sysroot-features" => match args.next() {
                     Some(feature) if !feature.is_empty() => {
                         test_arg.sysroot_features.push(feature);
@@ -194,7 +198,7 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> {
 }
 
 fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
-    let _ = std::fs::remove_dir_all(&args.config_info.cargo_target_dir);
+    let _ = remove_dir_all(&args.config_info.cargo_target_dir);
     let path = Path::new(&args.config_info.cargo_target_dir).join("gccjit");
     create_dir(&path)
 }
@@ -641,7 +645,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
         //failing test is fixed upstream.
         //"https://github.com/marshallpierce/rust-base64", // FIXME: one test is OOM-killed.
         // TODO: ignore the base64 test that is OOM-killed.
-        "https://github.com/time-rs/time",
+        //"https://github.com/time-rs/time", // FIXME: one test fails (https://github.com/time-rs/time/issues/719).
         "https://github.com/rust-lang/log",
         "https://github.com/bitflags/bitflags",
         //"https://github.com/serde-rs/serde", // FIXME: one test fails.
@@ -835,8 +839,7 @@ fn valid_ui_error_pattern_test(file: &str) -> bool {
     .any(|to_ignore| file.ends_with(to_ignore))
 }
 
-#[rustfmt::skip]
-fn contains_ui_error_patterns(file_path: &Path) -> Result<bool, String> {
+fn contains_ui_error_patterns(file_path: &Path, keep_lto_tests: bool) -> Result<bool, String> {
     // Tests generating errors.
     let file = File::open(file_path)
         .map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?;
@@ -849,22 +852,38 @@ fn contains_ui_error_patterns(file_path: &Path) -> Result<bool, String> {
             "//@ error-pattern:",
             "//@ build-fail",
             "//@ run-fail",
+            "//@ known-bug",
             "-Cllvm-args",
             "//~",
             "thread",
         ]
-            .iter()
-            .any(|check| line.contains(check))
+        .iter()
+        .any(|check| line.contains(check))
+        {
+            return Ok(true);
+        }
+
+        if !keep_lto_tests
+            && (line.contains("-Clto")
+                || line.contains("-C lto")
+                || line.contains("compile-flags: -Clinker-plugin-lto"))
+            && !line.contains("-Clto=thin")
         {
             return Ok(true);
         }
+
         if line.contains("//[") && line.contains("]~") {
             return Ok(true);
         }
     }
-    if file_path.display().to_string().contains("ambiguous-4-extern.rs") {
+    let file_path = file_path.display().to_string();
+    if file_path.contains("ambiguous-4-extern.rs") {
         eprintln!("nothing found for {file_path:?}");
     }
+    // The files in this directory contain errors.
+    if file_path.contains("/error-emitter/") {
+        return Ok(true);
+    }
     Ok(false)
 }
 
@@ -903,7 +922,7 @@ where
                 rust_path.join("tests/ui"),
                 &mut |_dir| Ok(()),
                 &mut |file_path| {
-                    if contains_ui_error_patterns(file_path)? {
+                    if contains_ui_error_patterns(file_path, args.keep_lto_tests)? {
                         Ok(())
                     } else {
                         remove_file(file_path).map_err(|e| e.to_string())
@@ -928,7 +947,7 @@ where
                     .iter()
                     .any(|name| *name == dir_name)
                     {
-                        std::fs::remove_dir_all(dir).map_err(|error| {
+                        remove_dir_all(dir).map_err(|error| {
                             format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
                         })?;
                     }
@@ -940,27 +959,42 @@ where
 
             // These two functions are used to remove files that are known to not be working currently
             // with the GCC backend to reduce noise.
-            fn dir_handling(dir: &Path) -> Result<(), String> {
-                if dir.file_name().map(|name| name == "auxiliary").unwrap_or(true) {
-                    return Ok(());
-                }
+            fn dir_handling(keep_lto_tests: bool) -> impl Fn(&Path) -> Result<(), String> {
+                move |dir| {
+                    if dir.file_name().map(|name| name == "auxiliary").unwrap_or(true) {
+                        return Ok(());
+                    }
 
-                walk_dir(dir, &mut dir_handling, &mut file_handling, false)
-            }
-            fn file_handling(file_path: &Path) -> Result<(), String> {
-                if !file_path.extension().map(|extension| extension == "rs").unwrap_or(false) {
-                    return Ok(());
+                    walk_dir(
+                        dir,
+                        &mut dir_handling(keep_lto_tests),
+                        &mut file_handling(keep_lto_tests),
+                        false,
+                    )
                 }
-                let path_str = file_path.display().to_string().replace("\\", "/");
-                if valid_ui_error_pattern_test(&path_str) {
-                    return Ok(());
-                } else if contains_ui_error_patterns(file_path)? {
-                    return remove_file(&file_path);
+            }
+
+            fn file_handling(keep_lto_tests: bool) -> impl Fn(&Path) -> Result<(), String> {
+                move |file_path| {
+                    if !file_path.extension().map(|extension| extension == "rs").unwrap_or(false) {
+                        return Ok(());
+                    }
+                    let path_str = file_path.display().to_string().replace("\\", "/");
+                    if valid_ui_error_pattern_test(&path_str) {
+                        return Ok(());
+                    } else if contains_ui_error_patterns(file_path, keep_lto_tests)? {
+                        return remove_file(&file_path);
+                    }
+                    Ok(())
                 }
-                Ok(())
             }
 
-            walk_dir(rust_path.join("tests/ui"), &mut dir_handling, &mut file_handling, false)?;
+            walk_dir(
+                rust_path.join("tests/ui"),
+                &mut dir_handling(args.keep_lto_tests),
+                &mut file_handling(args.keep_lto_tests),
+                false,
+            )?;
         }
         let nb_parts = args.nb_parts.unwrap_or(0);
         if nb_parts > 0 {
@@ -1173,7 +1207,7 @@ fn remove_files_callback<'a>(
                     files.split('\n').map(|line| line.trim()).filter(|line| !line.is_empty())
                 {
                     let path = rust_path.join(file);
-                    if let Err(e) = std::fs::remove_dir_all(&path) {
+                    if let Err(e) = remove_dir_all(&path) {
                         println!("Failed to remove directory `{}`: {}", path.display(), e);
                     }
                 }
diff --git a/example/mini_core.rs b/example/mini_core.rs
index cdd151613df84..bd7a4612a92cc 100644
--- a/example/mini_core.rs
+++ b/example/mini_core.rs
@@ -170,6 +170,14 @@ impl Add for usize {
     }
 }
 
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
 #[lang = "sub"]
 pub trait Sub<RHS = Self> {
     type Output;
diff --git a/libgccjit.version b/libgccjit.version
index b9bbbd324c3b9..ff58accec1d4c 100644
--- a/libgccjit.version
+++ b/libgccjit.version
@@ -1 +1 @@
-e744a9459d33864067214741daf5c5bc2a7b88c6
+45648c2edd4ecd862d9f08196d3d6c6ccba79f07
diff --git a/patches/0022-core-Disable-not-compiling-tests.patch b/patches/0022-core-Disable-not-compiling-tests.patch
index b2ab05691ecbf..70e3e2ba7fee1 100644
--- a/patches/0022-core-Disable-not-compiling-tests.patch
+++ b/patches/0022-core-Disable-not-compiling-tests.patch
@@ -1,7 +1,7 @@
-From 18793c6109890493ceb3ff36549849a36e3d8022 Mon Sep 17 00:00:00 2001
+From af0e237f056fa838c77463381a19b0dc993c0a35 Mon Sep 17 00:00:00 2001
 From: None <none@example.com>
 Date: Sun, 1 Sep 2024 11:42:17 -0400
-Subject: [PATCH] [core] Disable not compiling tests
+Subject: [PATCH] Disable not compiling tests
 
 ---
  library/core/tests/Cargo.toml | 14 ++++++++++++++
@@ -30,14 +30,15 @@ index 0000000..ca326ac
 +rand = { version = "0.8.5", default-features = false }
 +rand_xorshift = { version = "0.3.0", default-features = false }
 diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
-index 1e336bf..5800ebb 100644
+index a4a7946..ecfe43f 100644
 --- a/library/core/tests/lib.rs
 +++ b/library/core/tests/lib.rs
 @@ -1,4 +1,5 @@
  // tidy-alphabetical-start
 +#![cfg(test)]
- #![cfg_attr(bootstrap, feature(offset_of_nested))]
  #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
  #![cfg_attr(test, feature(cfg_match))]
---
-2.46.0
+ #![feature(alloc_layout_extra)]
+-- 
+2.47.1
+
diff --git a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
index 01461987ffb14..9ef5e0e4f4672 100644
--- a/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
+++ b/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
@@ -27,5 +27,4 @@ index b71786c..cf484d5 100644
  mod slice;
  mod str;
  mod str_lossy;
--- 
-2.45.2
+-- 2.45.2
diff --git a/rust-toolchain b/rust-toolchain
index dca3b0c22e4e5..940b3de9f7453 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-08-11"
+channel = "nightly-2025-01-12"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/src/allocator.rs b/src/allocator.rs
index f13a75648aea8..416f3231a13c4 100644
--- a/src/allocator.rs
+++ b/src/allocator.rs
@@ -1,6 +1,6 @@
-#[cfg(feature = "master")]
-use gccjit::FnAttribute;
 use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type};
+#[cfg(feature = "master")]
+use gccjit::{FnAttribute, VarAttribute};
 use rustc_ast::expand::allocator::{
     ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
     alloc_error_handler_name, default_fn_name, global_fn_name,
@@ -10,6 +10,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::config::OomStrategy;
 
 use crate::GccContext;
+#[cfg(feature = "master")]
+use crate::base::symbol_visibility_to_gcc;
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
@@ -70,12 +72,20 @@ pub(crate) unsafe fn codegen(
 
     let name = OomStrategy::SYMBOL.to_string();
     let global = context.new_global(None, GlobalKind::Exported, i8, name);
+    #[cfg(feature = "master")]
+    global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
+        tcx.sess.default_visibility(),
+    )));
     let value = tcx.sess.opts.unstable_opts.oom.should_panic();
     let value = context.new_rvalue_from_int(i8, value as i32);
     global.global_set_initializer_rvalue(value);
 
     let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
     let global = context.new_global(None, GlobalKind::Exported, i8, name);
+    #[cfg(feature = "master")]
+    global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
+        tcx.sess.default_visibility(),
+    )));
     let value = context.new_rvalue_from_int(i8, 0);
     global.global_set_initializer_rvalue(value);
 }
@@ -105,15 +115,9 @@ fn create_wrapper_function(
     );
 
     #[cfg(feature = "master")]
-    match tcx.sess.default_visibility() {
-        rustc_target::spec::SymbolVisibility::Hidden => {
-            func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden))
-        }
-        rustc_target::spec::SymbolVisibility::Protected => {
-            func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Protected))
-        }
-        rustc_target::spec::SymbolVisibility::Interposable => {}
-    }
+    func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc(
+        tcx.sess.default_visibility(),
+    )));
 
     if tcx.sess.must_emit_unwind_tables() {
         // TODO(antoyo): emit unwind tables.
diff --git a/src/back/lto.rs b/src/back/lto.rs
index f7173d4d2ffce..e419bd1809900 100644
--- a/src/back/lto.rs
+++ b/src/back/lto.rs
@@ -35,16 +35,13 @@ use rustc_middle::bug;
 use rustc_middle::dep_graph::WorkProduct;
 use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
 use rustc_session::config::{CrateType, Lto};
+use rustc_target::spec::RelocModel;
 use tempfile::{TempDir, tempdir};
 
 use crate::back::write::save_temp_bitcode;
 use crate::errors::{DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib};
 use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
 
-/// We keep track of the computed LTO cache keys from the previous
-/// session to determine which CGUs we can reuse.
-//pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
-
 pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
     match crate_type {
         CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
@@ -54,7 +51,7 @@ pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
 
 struct LtoData {
     // TODO(antoyo): use symbols_below_threshold.
-    //symbols_below_threshold: Vec<CString>,
+    //symbols_below_threshold: Vec<String>,
     upstream_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     tmp_path: TempDir,
 }
@@ -83,7 +80,7 @@ fn prepare_lto(
 
     let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| {
         if info.level.is_below_threshold(export_threshold) || info.used {
-            Some(CString::new(name.as_str()).unwrap())
+            Some(name.clone())
         } else {
             None
         }
@@ -91,7 +88,7 @@ fn prepare_lto(
     let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
     let mut symbols_below_threshold = {
         let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold");
-        exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<CString>>()
+        exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<String>>()
     };
     info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
 
@@ -159,11 +156,7 @@ fn prepare_lto(
         }
     }
 
-    Ok(LtoData {
-        //symbols_below_threshold,
-        upstream_modules,
-        tmp_path,
-    })
+    Ok(LtoData { upstream_modules, tmp_path })
 }
 
 fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> {
@@ -191,7 +184,7 @@ pub(crate) fn run_fat(
         cached_modules,
         lto_data.upstream_modules,
         lto_data.tmp_path,
-        //&symbols_below_threshold,
+        //&lto_data.symbols_below_threshold,
     )
 }
 
@@ -202,7 +195,7 @@ fn fat_lto(
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
     mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     tmp_path: TempDir,
-    //symbols_below_threshold: &[*const libc::c_char],
+    //symbols_below_threshold: &[String],
 ) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
     let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module");
     info!("going for a fat lto");
@@ -327,6 +320,7 @@ fn fat_lto(
             ptr as *const *const libc::c_char,
             symbols_below_threshold.len() as libc::size_t,
         );*/
+
         save_temp_bitcode(cgcx, &module, "lto.after-restriction");
         //}
     }
@@ -363,8 +357,6 @@ pub(crate) fn run_thin(
     let dcx = cgcx.create_dcx();
     let dcx = dcx.handle();
     let lto_data = prepare_lto(cgcx, dcx)?;
-    /*let symbols_below_threshold =
-    symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
     if cgcx.opts.cg.linker_plugin_lto.enabled() {
         unreachable!(
             "We should never reach this case if the LTO step \
@@ -377,7 +369,8 @@ pub(crate) fn run_thin(
         modules,
         lto_data.upstream_modules,
         lto_data.tmp_path,
-        cached_modules, /*, &symbols_below_threshold*/
+        cached_modules,
+        //&lto_data.symbols_below_threshold,
     )
 }
 
@@ -428,7 +421,7 @@ fn thin_lto(
     serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     tmp_path: TempDir,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
-    //symbols_below_threshold: &[*const libc::c_char],
+    //_symbols_below_threshold: &[String],
 ) -> Result<(Vec<LtoModuleCodegen<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> {
     let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis");
     info!("going for that thin, thin LTO");
@@ -640,7 +633,13 @@ pub unsafe fn optimize_thin_module(
         }
     };
     let module = ModuleCodegen {
-        module_llvm: GccContext { context, should_combine_object_files, temp_dir: None },
+        module_llvm: GccContext {
+            context,
+            should_combine_object_files,
+            // TODO(antoyo): use the correct relocation model here.
+            relocation_model: RelocModel::Pic,
+            temp_dir: None,
+        },
         name: thin_module.name().to_string(),
         kind: ModuleKind::Regular,
     };
diff --git a/src/back/write.rs b/src/back/write.rs
index 802968979c722..51c5ba73e32bc 100644
--- a/src/back/write.rs
+++ b/src/back/write.rs
@@ -1,6 +1,6 @@
 use std::{env, fs};
 
-use gccjit::OutputKind;
+use gccjit::{Context, OutputKind};
 use rustc_codegen_ssa::back::link::ensure_removed;
 use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
@@ -10,6 +10,7 @@ use rustc_session::config::OutputType;
 use rustc_span::fatal_error::FatalError;
 use rustc_target::spec::SplitDebuginfo;
 
+use crate::base::add_pic_option;
 use crate::errors::CopyBitcode;
 use crate::{GccCodegenBackend, GccContext};
 
@@ -31,51 +32,87 @@ pub(crate) unsafe fn codegen(
 
         // NOTE: Only generate object files with GIMPLE when this environment variable is set for
         // now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit).
-        // TODO: remove this environment variable.
+        // TODO(antoyo): remove this environment variable.
         let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1");
 
         let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
         let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
 
-        if config.bitcode_needed() && fat_lto {
-            let _timer = cgcx
-                .prof
-                .generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
-
-            // TODO(antoyo)
-            /*if let Some(bitcode_filename) = bc_out.file_name() {
-                cgcx.prof.artifact_size(
-                    "llvm_bitcode",
-                    bitcode_filename.to_string_lossy(),
-                    data.len() as u64,
-                );
-            }*/
-
-            if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
+        if config.bitcode_needed() {
+            if fat_lto {
                 let _timer = cgcx
                     .prof
-                    .generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name);
-                context.add_command_line_option("-flto=auto");
-                context.add_command_line_option("-flto-partition=one");
-                // TODO: remove since we don't want fat objects when it is for Bitcode only.
-                context.add_command_line_option("-ffat-lto-objects");
-                context
-                    .compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
-            }
+                    .generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name);
 
-            if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
-                let _timer = cgcx
-                    .prof
-                    .generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name);
-                // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
-                //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
-
-                context.add_command_line_option("-flto=auto");
-                context.add_command_line_option("-flto-partition=one");
-                context.add_command_line_option("-ffat-lto-objects");
-                // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
-                context
-                    .compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str"));
+                // TODO(antoyo)
+                /*if let Some(bitcode_filename) = bc_out.file_name() {
+                    cgcx.prof.artifact_size(
+                        "llvm_bitcode",
+                        bitcode_filename.to_string_lossy(),
+                        data.len() as u64,
+                    );
+                }*/
+
+                if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_emit_bitcode",
+                        &*module.name,
+                    );
+                    context.add_command_line_option("-flto=auto");
+                    context.add_command_line_option("-flto-partition=one");
+                    // TODO(antoyo): remove since we don't want fat objects when it is for Bitcode only.
+                    context.add_command_line_option("-ffat-lto-objects");
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
+
+                if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_embed_bitcode",
+                        &*module.name,
+                    );
+                    // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
+                    //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
+
+                    context.add_command_line_option("-flto=auto");
+                    context.add_command_line_option("-flto-partition=one");
+                    context.add_command_line_option("-ffat-lto-objects");
+                    // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
+            } else {
+                if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_emit_bitcode",
+                        &*module.name,
+                    );
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
+
+                if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
+                    // TODO(antoyo): we might want to emit to emit an error here, saying to set the
+                    // environment variable EMBED_LTO_BITCODE.
+                    let _timer = cgcx.prof.generic_activity_with_arg(
+                        "GCC_module_codegen_embed_bitcode",
+                        &*module.name,
+                    );
+                    // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes?
+                    //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
+
+                    // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument).
+                    context.compile_to_file(
+                        OutputKind::ObjectFile,
+                        bc_out.to_str().expect("path to str"),
+                    );
+                }
             }
         }
 
@@ -123,6 +160,8 @@ pub(crate) unsafe fn codegen(
 
                         // NOTE: without -fuse-linker-plugin, we get the following error:
                         // lto1: internal compiler error: decompressed stream: Destination buffer is too small
+                        // TODO(antoyo): since we do not do LTO when the linker is invoked anymore, perhaps
+                        // the following flag is not necessary anymore.
                         context.add_driver_option("-fuse-linker-plugin");
                     }
 
@@ -131,11 +170,43 @@ pub(crate) unsafe fn codegen(
                     // /usr/bin/ld: cannot find -lgcc_s: No such file or directory
                     context.add_driver_option("-nostdlib");
 
-                    // NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o.
-                    context.compile_to_file(
-                        OutputKind::Executable,
-                        obj_out.to_str().expect("path to str"),
-                    );
+                    let path = obj_out.to_str().expect("path to str");
+
+                    if fat_lto {
+                        let lto_path = format!("{}.lto", path);
+                        // FIXME(antoyo): The LTO frontend generates the following warning:
+                        // ../build_sysroot/sysroot_src/library/core/src/num/dec2flt/lemire.rs:150:15: warning: type of ā€˜_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E’ does not match original declaration [-Wlto-type-mismatch]
+                        // 150 |     let (lo5, hi5) = POWER_OF_FIVE_128[index];
+                        //     |               ^
+                        // lto1: note: ā€˜_ZN4core3num7dec2flt5table17POWER_OF_FIVE_12817ha449a68fb31379e4E’ was previously declared here
+                        //
+                        // This option is to mute it to make the UI tests pass with LTO enabled.
+                        context.add_driver_option("-Wno-lto-type-mismatch");
+                        // NOTE: this doesn't actually generate an executable. With the above
+                        // flags, it combines the .o files together in another .o.
+                        context.compile_to_file(OutputKind::Executable, &lto_path);
+
+                        let context = Context::default();
+                        if cgcx.target_arch == "x86" || cgcx.target_arch == "x86_64" {
+                            // NOTE: it seems we need to use add_driver_option instead of
+                            // add_command_line_option here because we use the LTO frontend via gcc.
+                            context.add_driver_option("-masm=intel");
+                        }
+
+                        // NOTE: these two options are needed to invoke LTO to produce an object file.
+                        // We need to initiate a second compilation because the arguments "-x lto"
+                        // needs to be at the very beginning.
+                        context.add_driver_option("-x");
+                        context.add_driver_option("lto");
+                        add_pic_option(&context, module.module_llvm.relocation_model);
+                        context.add_driver_option(lto_path);
+
+                        context.compile_to_file(OutputKind::ObjectFile, path);
+                    } else {
+                        // NOTE: this doesn't actually generate an executable. With the above
+                        // flags, it combines the .o files together in another .o.
+                        context.compile_to_file(OutputKind::Executable, path);
+                    }
                 } else {
                     context.compile_to_file(
                         OutputKind::ObjectFile,
diff --git a/src/base.rs b/src/base.rs
index 18aa32754e1d9..c9701fb9885c1 100644
--- a/src/base.rs
+++ b/src/base.rs
@@ -3,7 +3,7 @@ use std::env;
 use std::sync::Arc;
 use std::time::Instant;
 
-use gccjit::{CType, FunctionType, GlobalKind};
+use gccjit::{CType, Context, FunctionType, GlobalKind};
 use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
 use rustc_codegen_ssa::mono_item::MonoItemExt;
 use rustc_codegen_ssa::traits::DebugInfoCodegenMethods;
@@ -15,21 +15,32 @@ use rustc_middle::mir::mono::Visibility;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::DebugInfo;
 use rustc_span::Symbol;
-use rustc_target::spec::PanicStrategy;
+#[cfg(feature = "master")]
+use rustc_target::spec::SymbolVisibility;
+use rustc_target::spec::{PanicStrategy, RelocModel};
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
 use crate::{GccContext, LockedTargetInfo, SyncContext, gcc_util, new_context};
 
 #[cfg(feature = "master")]
-pub fn visibility_to_gcc(linkage: Visibility) -> gccjit::Visibility {
-    match linkage {
+pub fn visibility_to_gcc(visibility: Visibility) -> gccjit::Visibility {
+    match visibility {
         Visibility::Default => gccjit::Visibility::Default,
         Visibility::Hidden => gccjit::Visibility::Hidden,
         Visibility::Protected => gccjit::Visibility::Protected,
     }
 }
 
+#[cfg(feature = "master")]
+pub fn symbol_visibility_to_gcc(visibility: SymbolVisibility) -> gccjit::Visibility {
+    match visibility {
+        SymbolVisibility::Hidden => gccjit::Visibility::Hidden,
+        SymbolVisibility::Protected => gccjit::Visibility::Protected,
+        SymbolVisibility::Interposable => gccjit::Visibility::Default,
+    }
+}
+
 pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
     match linkage {
         Linkage::External => GlobalKind::Imported,
@@ -140,9 +151,7 @@ pub fn compile_codegen_unit(
             });
         }
 
-        if tcx.sess.relocation_model() == rustc_target::spec::RelocModel::Static {
-            context.add_command_line_option("-fno-pie");
-        }
+        add_pic_option(&context, tcx.sess.relocation_model());
 
         let target_cpu = gcc_util::target_cpu(tcx.sess);
         if target_cpu != "generic" {
@@ -199,12 +208,13 @@ pub fn compile_codegen_unit(
             let f32_type_supported = target_info.supports_target_dependent_type(CType::Float32);
             let f64_type_supported = target_info.supports_target_dependent_type(CType::Float64);
             let f128_type_supported = target_info.supports_target_dependent_type(CType::Float128);
+            let u128_type_supported = target_info.supports_target_dependent_type(CType::UInt128t);
             // TODO: improve this to avoid passing that many arguments.
             let cx = CodegenCx::new(
                 &context,
                 cgu,
                 tcx,
-                target_info.supports_128bit_int(),
+                u128_type_supported,
                 f16_type_supported,
                 f32_type_supported,
                 f64_type_supported,
@@ -235,6 +245,7 @@ pub fn compile_codegen_unit(
             name: cgu_name.to_string(),
             module_llvm: GccContext {
                 context: Arc::new(SyncContext::new(context)),
+                relocation_model: tcx.sess.relocation_model(),
                 should_combine_object_files: false,
                 temp_dir: None,
             },
@@ -244,3 +255,24 @@ pub fn compile_codegen_unit(
 
     (module, cost)
 }
+
+pub fn add_pic_option<'gcc>(context: &Context<'gcc>, relocation_model: RelocModel) {
+    match relocation_model {
+        rustc_target::spec::RelocModel::Static => {
+            context.add_command_line_option("-fno-pie");
+            context.add_driver_option("-fno-pie");
+        }
+        rustc_target::spec::RelocModel::Pic => {
+            context.add_command_line_option("-fPIC");
+            // NOTE: we use both add_command_line_option and add_driver_option because the usage in
+            // this module (compile_codegen_unit) requires add_command_line_option while the usage
+            // in the back::write module (codegen) requires add_driver_option.
+            context.add_driver_option("-fPIC");
+        }
+        rustc_target::spec::RelocModel::Pie => {
+            context.add_command_line_option("-fPIE");
+            context.add_driver_option("-fPIE");
+        }
+        model => eprintln!("Unsupported relocation model: {:?}", model),
+    }
+}
diff --git a/src/builder.rs b/src/builder.rs
index 9a142326ad196..89e5cf1b8c6b6 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -1102,18 +1102,24 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         val: RValue<'gcc>,
         ptr: RValue<'gcc>,
         align: Align,
-        _flags: MemFlags,
+        flags: MemFlags,
     ) -> RValue<'gcc> {
         let ptr = self.check_store(val, ptr);
         let destination = ptr.dereference(self.location);
         // NOTE: libgccjit does not support specifying the alignment on the assignment, so we cast
         // to type so it gets the proper alignment.
         let destination_type = destination.to_rvalue().get_type().unqualified();
-        let aligned_type = destination_type.get_aligned(align.bytes()).make_pointer();
-        let aligned_destination = self.cx.context.new_bitcast(self.location, ptr, aligned_type);
-        let aligned_destination = aligned_destination.dereference(self.location);
-        self.llbb().add_assignment(self.location, aligned_destination, val);
-        // TODO(antoyo): handle align and flags.
+        let align = if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() };
+        let mut modified_destination_type = destination_type.get_aligned(align);
+        if flags.contains(MemFlags::VOLATILE) {
+            modified_destination_type = modified_destination_type.make_volatile();
+        }
+
+        let modified_ptr =
+            self.cx.context.new_cast(self.location, ptr, modified_destination_type.make_pointer());
+        let modified_destination = modified_ptr.dereference(self.location);
+        self.llbb().add_assignment(self.location, modified_destination, val);
+        // TODO(antoyo): handle `MemFlags::NONTEMPORAL`.
         // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
         // When adding support for NONTEMPORAL, make sure to not just emit MOVNT on x86; see the
         // LLVM backend for details.
@@ -1236,13 +1242,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
-        let usize_value = self.cx.const_bitcast(value, self.cx.type_isize());
+        let usize_value = self.cx.context.new_cast(None, value, self.cx.type_isize());
         self.intcast(usize_value, dest_ty, false)
     }
 
     fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
         let usize_value = self.intcast(value, self.cx.type_isize(), false);
-        self.cx.const_bitcast(usize_value, dest_ty)
+        self.cx.context.new_cast(None, usize_value, dest_ty)
     }
 
     fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
@@ -1901,6 +1907,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         v2: RValue<'gcc>,
         mask: RValue<'gcc>,
     ) -> RValue<'gcc> {
+        // NOTE: if the `mask` is a constant value, the following code will copy it in many places,
+        // which will make GCC create a lot (+4000) local variables in some cases.
+        // So we assign it to an explicit local variable once to avoid this.
+        let func = self.current_func();
+        let mask_var = func.new_local(self.location, mask.get_type(), "mask");
+        let block = self.block;
+        block.add_assignment(self.location, mask_var, mask);
+        let mask = mask_var.to_rvalue();
+
         // TODO(antoyo): use a recursive unqualified() here.
         let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");
         let element_type = vector_type.get_element_type();
@@ -1917,18 +1932,35 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             self.int_type
         };
 
-        let vector_type =
-            mask.get_type().dyncast_vector().expect("simd_shuffle mask should be of vector type");
-        let mask_num_units = vector_type.get_num_units();
-        let mut mask_elements = vec![];
-        for i in 0..mask_num_units {
-            let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
-            mask_elements.push(self.context.new_cast(
-                self.location,
-                self.extract_element(mask, index).to_rvalue(),
-                mask_element_type,
-            ));
-        }
+        // NOTE: this condition is needed because we call shuffle_vector in the implementation of
+        // simd_gather.
+        let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() {
+            let mask_num_units = vector_type.get_num_units();
+            let mut mask_elements = vec![];
+            for i in 0..mask_num_units {
+                let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
+                mask_elements.push(self.context.new_cast(
+                    self.location,
+                    self.extract_element(mask, index).to_rvalue(),
+                    mask_element_type,
+                ));
+            }
+            mask_elements
+        } else {
+            let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
+            let mask_num_units = struct_type.get_field_count();
+            let mut mask_elements = vec![];
+            for i in 0..mask_num_units {
+                let field = struct_type.get_field(i as i32);
+                mask_elements.push(self.context.new_cast(
+                    self.location,
+                    mask.access_field(self.location, field).to_rvalue(),
+                    mask_element_type,
+                ));
+            }
+            mask_elements
+        };
+        let mask_num_units = mask_elements.len();
 
         // NOTE: the mask needs to be the same length as the input vectors, so add the missing
         // elements in the mask if needed.
diff --git a/src/callee.rs b/src/callee.rs
index 65972a03e8355..c133ae4fcdd2a 100644
--- a/src/callee.rs
+++ b/src/callee.rs
@@ -72,95 +72,74 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
 
         attributes::from_fn_attrs(cx, func, instance);
 
-        let instance_def_id = instance.def_id();
-
-        // TODO(antoyo): set linkage and attributes.
-
-        // Apply an appropriate linkage/visibility value to our item that we
-        // just declared.
-        //
-        // This is sort of subtle. Inside our codegen unit we started off
-        // compilation by predefining all our own `MonoItem` instances. That
-        // is, everything we're codegenning ourselves is already defined. That
-        // means that anything we're actually codegenning in this codegen unit
-        // will have hit the above branch in `get_declared_value`. As a result,
-        // we're guaranteed here that we're declaring a symbol that won't get
-        // defined, or in other words we're referencing a value from another
-        // codegen unit or even another crate.
-        //
-        // So because this is a foreign value we blanket apply an external
-        // linkage directive because it's coming from a different object file.
-        // The visibility here is where it gets tricky. This symbol could be
-        // referencing some foreign crate or foreign library (an `extern`
-        // block) in which case we want to leave the default visibility. We may
-        // also, though, have multiple codegen units. It could be a
-        // monomorphization, in which case its expected visibility depends on
-        // whether we are sharing generics or not. The important thing here is
-        // that the visibility we apply to the declaration is the same one that
-        // has been applied to the definition (wherever that definition may be).
-        let is_generic = instance.args.non_erasable_generics().next().is_some();
-
-        if is_generic {
-            // This is a monomorphization. Its expected visibility depends
-            // on whether we are in share-generics mode.
-
-            if cx.tcx.sess.opts.share_generics() {
-                // We are in share_generics mode.
-
-                if let Some(instance_def_id) = instance_def_id.as_local() {
-                    // This is a definition from the current crate. If the
-                    // definition is unreachable for downstream crates or
-                    // the current crate does not re-export generics, the
-                    // definition of the instance will have been declared
-                    // as `hidden`.
-                    if cx.tcx.is_unreachable_local_definition(instance_def_id)
+        #[cfg(feature = "master")]
+        {
+            let instance_def_id = instance.def_id();
+
+            // TODO(antoyo): set linkage and attributes.
+
+            // Apply an appropriate linkage/visibility value to our item that we
+            // just declared.
+            //
+            // This is sort of subtle. Inside our codegen unit we started off
+            // compilation by predefining all our own `MonoItem` instances. That
+            // is, everything we're codegenning ourselves is already defined. That
+            // means that anything we're actually codegenning in this codegen unit
+            // will have hit the above branch in `get_declared_value`. As a result,
+            // we're guaranteed here that we're declaring a symbol that won't get
+            // defined, or in other words we're referencing a value from another
+            // codegen unit or even another crate.
+            //
+            // So because this is a foreign value we blanket apply an external
+            // linkage directive because it's coming from a different object file.
+            // The visibility here is where it gets tricky. This symbol could be
+            // referencing some foreign crate or foreign library (an `extern`
+            // block) in which case we want to leave the default visibility. We may
+            // also, though, have multiple codegen units. It could be a
+            // monomorphization, in which case its expected visibility depends on
+            // whether we are sharing generics or not. The important thing here is
+            // that the visibility we apply to the declaration is the same one that
+            // has been applied to the definition (wherever that definition may be).
+            let is_generic = instance.args.non_erasable_generics().next().is_some();
+
+            let is_hidden = if is_generic {
+                // This is a monomorphization of a generic function.
+                if !(cx.tcx.sess.opts.share_generics()
+                    || tcx.codegen_fn_attrs(instance_def_id).inline
+                        == rustc_attr_parsing::InlineAttr::Never)
+                {
+                    // When not sharing generics, all instances are in the same
+                    // crate and have hidden visibility.
+                    true
+                } else if let Some(instance_def_id) = instance_def_id.as_local() {
+                    // This is a monomorphization of a generic function
+                    // defined in the current crate. It is hidden if:
+                    // - the definition is unreachable for downstream
+                    //   crates, or
+                    // - the current crate does not re-export generics
+                    //   (because the crate is a C library or executable)
+                    cx.tcx.is_unreachable_local_definition(instance_def_id)
                         || !cx.tcx.local_crate_exports_generics()
-                    {
-                        #[cfg(feature = "master")]
-                        func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                    }
                 } else {
                     // This is a monomorphization of a generic function
-                    // defined in an upstream crate.
-                    if instance.upstream_monomorphization(tcx).is_some() {
-                        // This is instantiated in another crate. It cannot
-                        // be `hidden`.
-                    } else {
-                        // This is a local instantiation of an upstream definition.
-                        // If the current crate does not re-export it
-                        // (because it is a C library or an executable), it
-                        // will have been declared `hidden`.
-                        if !cx.tcx.local_crate_exports_generics() {
-                            #[cfg(feature = "master")]
-                            func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                        }
-                    }
+                    // defined in an upstream crate. It is hidden if:
+                    // - it is instantiated in this crate, and
+                    // - the current crate does not re-export generics
+                    instance.upstream_monomorphization(tcx).is_none()
+                        && !cx.tcx.local_crate_exports_generics()
                 }
             } else {
-                // When not sharing generics, all instances are in the same
-                // crate and have hidden visibility
-                #[cfg(feature = "master")]
+                // This is a non-generic function. It is hidden if:
+                // - it is instantiated in the local crate, and
+                //   - it is defined an upstream crate (non-local), or
+                //   - it is not reachable
+                cx.tcx.is_codegened_item(instance_def_id)
+                    && (!instance_def_id.is_local()
+                        || !cx.tcx.is_reachable_non_generic(instance_def_id))
+            };
+            if is_hidden {
                 func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
             }
-        } else {
-            // This is a non-generic function
-            if cx.tcx.is_codegened_item(instance_def_id) {
-                // This is a function that is instantiated in the local crate
-
-                if instance_def_id.is_local() {
-                    // This is function that is defined in the local crate.
-                    // If it is not reachable, it is hidden.
-                    if !cx.tcx.is_reachable_non_generic(instance_def_id) {
-                        #[cfg(feature = "master")]
-                        func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                    }
-                } else {
-                    // This is a function from an upstream crate that has
-                    // been instantiated here. These are always hidden.
-                    #[cfg(feature = "master")]
-                    func.add_attribute(FnAttribute::Visibility(Visibility::Hidden));
-                }
-            }
         }
 
         func
diff --git a/src/common.rs b/src/common.rs
index 0d3e7083d56ad..f43743fc2a41b 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -240,14 +240,14 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
                     }
                 };
                 let ptr_type = base_addr.get_type();
-                let base_addr = self.const_bitcast(base_addr, self.usize_type);
+                let base_addr = self.context.new_cast(None, base_addr, self.usize_type);
                 let offset =
                     self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
-                let ptr = self.const_bitcast(base_addr + offset, ptr_type);
+                let ptr = self.context.new_cast(None, base_addr + offset, ptr_type);
                 if !matches!(layout.primitive(), Pointer(_)) {
                     self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
                 } else {
-                    self.const_bitcast(ptr, ty)
+                    self.context.new_cast(None, ptr, ty)
                 }
             }
         }
diff --git a/src/consts.rs b/src/consts.rs
index 6dc2f4ed66881..1631ecfeecf3f 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -252,7 +252,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
             let global = self.declare_global(
                 sym,
                 gcc_type,
-                GlobalKind::Exported,
+                GlobalKind::Imported,
                 is_tls,
                 fn_attrs.link_section,
             );
@@ -404,7 +404,6 @@ fn check_and_apply_linkage<'gcc, 'tcx>(
         // TODO(antoyo): set linkage.
         let value = cx.const_ptrcast(global1.get_address(None), gcc_type);
         global2.global_set_initializer_rvalue(value);
-        // TODO(antoyo): use global_set_initializer() when it will work.
         global2
     } else {
         // Generate an external declaration.
diff --git a/src/context.rs b/src/context.rs
index f67dcf0cb116d..c81c53359fd18 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -386,6 +386,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
 impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
     type Value = RValue<'gcc>;
     type Metadata = RValue<'gcc>;
+    // TODO(antoyo): change to Function<'gcc>.
     type Function = RValue<'gcc>;
 
     type BasicBlock = Block<'gcc>;
diff --git a/src/errors.rs b/src/errors.rs
index c896246866b9c..1b59b9ac169ab 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -40,10 +40,6 @@ pub(crate) enum PossibleFeature<'a> {
     None,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_gcc_lto_not_supported)]
-pub(crate) struct LTONotSupported;
-
 #[derive(Diagnostic)]
 #[diag(codegen_gcc_unwinding_inline_asm)]
 pub(crate) struct UnwindingInlineAsm {
diff --git a/src/gcc_util.rs b/src/gcc_util.rs
index 1994a2a3c5373..560aff43d6538 100644
--- a/src/gcc_util.rs
+++ b/src/gcc_util.rs
@@ -66,16 +66,14 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
             // We do the equivalent above in `target_features_cfg`.
             // See <https://github.com/rust-lang/rust/issues/134792>.
             all_rust_features.push((false, feature));
-        } else if !feature.is_empty() {
-            if diagnostics {
-                sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
-            }
+        } else if !feature.is_empty() && diagnostics {
+            sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
         }
     }
     // Remove features that are meant for rustc, not codegen.
-    all_rust_features.retain(|(_, feature)| {
+    all_rust_features.retain(|&(_, feature)| {
         // Retain if it is not a rustc feature
-        !RUSTC_SPECIFIC_FEATURES.contains(feature)
+        !RUSTC_SPECIFIC_FEATURES.contains(&feature)
     });
 
     // Check feature validity.
@@ -103,7 +101,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
                     };
                     sess.dcx().emit_warn(unknown_feature);
                 }
-                Some((_, stability, _)) => {
+                Some(&(_, stability, _)) => {
                     if let Err(reason) = stability.toggle_allowed() {
                         sess.dcx().emit_warn(ForbiddenCTargetFeature {
                             feature,
@@ -165,29 +163,25 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     );
 
     // Translate this into GCC features.
-    let feats = all_rust_features
-        .iter()
-        .filter_map(|&(enable, feature)| {
+    let feats =
+        all_rust_features.iter().flat_map(|&(enable, feature)| {
             let enable_disable = if enable { '+' } else { '-' };
             // We run through `to_gcc_features` when
             // passing requests down to GCC. This means that all in-language
             // features also work on the command line instead of having two
             // different names when the GCC name and the Rust name differ.
-            Some(
-                to_gcc_features(sess, feature)
-                    .iter()
-                    .flat_map(|feat| to_gcc_features(sess, feat).into_iter())
-                    .map(|feature| {
-                        if enable_disable == '-' {
-                            format!("-{}", feature)
-                        } else {
-                            feature.to_string()
-                        }
-                    })
-                    .collect::<Vec<_>>(),
-            )
-        })
-        .flatten();
+            to_gcc_features(sess, feature)
+                .iter()
+                .flat_map(|feat| to_gcc_features(sess, feat).into_iter())
+                .map(|feature| {
+                    if enable_disable == '-' {
+                        format!("-{}", feature)
+                    } else {
+                        feature.to_string()
+                    }
+                })
+                .collect::<Vec<_>>()
+        });
     features.extend(feats);
 
     if diagnostics {
diff --git a/src/int.rs b/src/int.rs
index 02b760dc7334c..7b9d1feb8d710 100644
--- a/src/int.rs
+++ b/src/int.rs
@@ -90,7 +90,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                     }
                 }
             }
-        } else if a_type.is_vector() && a_type.is_vector() {
+        } else if a_type.is_vector() && b_type.is_vector() {
             a >> b
         } else if a_native && !b_native {
             self.gcc_lshr(a, self.gcc_int_cast(b, a_type))
@@ -660,7 +660,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                     }
                 }
             }
-        } else if a_type.is_vector() && a_type.is_vector() {
+        } else if a_type.is_vector() && b_type.is_vector() {
             a << b
         } else if a_native && !b_native {
             self.gcc_shl(a, self.gcc_int_cast(b, a_type))
diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs
index 0a448ded6b1ae..231307def291f 100644
--- a/src/intrinsic/llvm.rs
+++ b/src/intrinsic/llvm.rs
@@ -421,7 +421,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
             | "__builtin_ia32_xsaveopt64" => {
                 let new_args = args.to_vec();
                 let thirty_two = builder.context.new_rvalue_from_int(new_args[1].get_type(), 32);
-                let arg2 = new_args[1] << thirty_two | new_args[2];
+                let arg2 = (new_args[1] << thirty_two) | new_args[2];
                 let arg2_type = gcc_func.get_param_type(1);
                 let arg2 = builder.context.new_cast(None, arg2, arg2_type);
                 args = vec![new_args[0], arg2].into();
diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs
index 78ec9741f5781..11f9604c6d260 100644
--- a/src/intrinsic/mod.rs
+++ b/src/intrinsic/mod.rs
@@ -13,15 +13,16 @@ use rustc_codegen_ssa::common::IntPredicate;
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
+use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
+#[cfg(feature = "master")]
+use rustc_codegen_ssa::traits::MiscCodegenMethods;
 use rustc_codegen_ssa::traits::{
     ArgAbiBuilderMethods, BuilderMethods, ConstCodegenMethods, IntrinsicCallBuilderMethods,
 };
-#[cfg(feature = "master")]
-use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, MiscCodegenMethods};
 use rustc_middle::bug;
-use rustc_middle::ty::layout::LayoutOf;
 #[cfg(feature = "master")]
-use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{Span, Symbol, sym};
 use rustc_target::abi::HasDataLayout;
@@ -139,6 +140,18 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                 )
             }
+            sym::fmaf16 => {
+                // TODO(antoyo): use the correct builtin for f16.
+                let func = self.cx.context.get_builtin_function("fmaf");
+                let args: Vec<_> = args
+                    .iter()
+                    .map(|arg| {
+                        self.cx.context.new_cast(self.location, arg.immediate(), self.cx.type_f32())
+                    })
+                    .collect();
+                let result = self.cx.context.new_call(self.location, func, &args);
+                self.cx.context.new_cast(self.location, result, self.cx.type_f16())
+            }
             sym::is_val_statically_known => {
                 let a = args[0].immediate();
                 let builtin = self.context.get_builtin_function("__builtin_constant_p");
diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs
index 79d1a06dd467f..1be452e5d05de 100644
--- a/src/intrinsic/simd.rs
+++ b/src/intrinsic/simd.rs
@@ -379,7 +379,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         // Make sure this is actually a SIMD vector.
         let idx_ty = args[2].layout.ty;
         let n: u64 = if idx_ty.is_simd()
-            && matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
+            && matches!(*idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
         {
             idx_ty.simd_size_and_type(bx.cx.tcx).0
         } else {
@@ -829,6 +829,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             | sym::simd_flog
             | sym::simd_floor
             | sym::simd_fma
+            | sym::simd_relaxed_fma
             | sym::simd_fpow
             | sym::simd_fpowi
             | sym::simd_fsin
diff --git a/src/lib.rs b/src/lib.rs
index 7329080ce1f71..f6ad0c79de545 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -27,6 +27,8 @@
 // Some "regular" crates we want to share with rustc
 extern crate object;
 extern crate smallvec;
+// FIXME(antoyo): clippy bug: remove the #[allow] when it's fixed.
+#[allow(unused_extern_crates)]
 extern crate tempfile;
 #[macro_use]
 extern crate tracing;
@@ -88,7 +90,6 @@ use std::sync::atomic::Ordering;
 use std::sync::{Arc, Mutex};
 
 use back::lto::{ThinBuffer, ThinData};
-use errors::LTONotSupported;
 use gccjit::{CType, Context, OptimizationLevel};
 #[cfg(feature = "master")]
 use gccjit::{TargetInfo, Version};
@@ -109,9 +110,10 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::Providers;
 use rustc_session::Session;
-use rustc_session::config::{Lto, OptLevel, OutputFilenames};
+use rustc_session::config::{OptLevel, OutputFilenames};
 use rustc_span::Symbol;
 use rustc_span::fatal_error::FatalError;
+use rustc_target::spec::RelocModel;
 use tempfile::TempDir;
 
 use crate::back::lto::ModuleBuffer;
@@ -141,11 +143,15 @@ impl TargetInfo {
         false
     }
 
-    fn supports_128bit_int(&self) -> bool {
-        self.supports_128bit_integers.load(Ordering::SeqCst)
-    }
-
-    fn supports_target_dependent_type(&self, _typ: CType) -> bool {
+    fn supports_target_dependent_type(&self, typ: CType) -> bool {
+        match typ {
+            CType::UInt128t | CType::Int128t => {
+                if self.supports_128bit_integers.load(Ordering::SeqCst) {
+                    return true;
+                }
+            }
+            _ => (),
+        }
         false
     }
 }
@@ -166,10 +172,6 @@ impl LockedTargetInfo {
         self.info.lock().expect("lock").cpu_supports(feature)
     }
 
-    fn supports_128bit_int(&self) -> bool {
-        self.info.lock().expect("lock").supports_128bit_int()
-    }
-
     fn supports_target_dependent_type(&self, typ: CType) -> bool {
         self.info.lock().expect("lock").supports_target_dependent_type(typ)
     }
@@ -202,10 +204,6 @@ impl CodegenBackend for GccCodegenBackend {
         #[cfg(feature = "master")]
         gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
 
-        if sess.lto() == Lto::Thin {
-            sess.dcx().emit_warn(LTONotSupported {});
-        }
-
         #[cfg(not(feature = "master"))]
         {
             let temp_dir = TempDir::new().expect("cannot create temporary directory");
@@ -297,6 +295,7 @@ impl ExtraBackendMethods for GccCodegenBackend {
     ) -> Self::Module {
         let mut mods = GccContext {
             context: Arc::new(SyncContext::new(new_context(tcx))),
+            relocation_model: tcx.sess.relocation_model(),
             should_combine_object_files: false,
             temp_dir: None,
         };
@@ -328,6 +327,9 @@ impl ExtraBackendMethods for GccCodegenBackend {
 
 pub struct GccContext {
     context: Arc<SyncContext>,
+    /// This field is needed in order to be able to set the flag -fPIC when necessary when doing
+    /// LTO.
+    relocation_model: RelocModel,
     should_combine_object_files: bool,
     // Temporary directory used by LTO. We keep it here so that it's not removed before linking.
     temp_dir: Option<TempDir>,
@@ -492,10 +494,10 @@ fn target_features_cfg(
     sess.target
         .rust_target_features()
         .iter()
-        .filter(|(_, gate, _)| gate.in_cfg())
-        .filter_map(|(feature, gate, _)| {
+        .filter(|&&(_, gate, _)| gate.in_cfg())
+        .filter_map(|&(feature, gate, _)| {
             if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
-                Some(*feature)
+                Some(feature)
             } else {
                 None
             }
diff --git a/tests/failing-non-lto-tests.txt b/tests/failing-non-lto-tests.txt
deleted file mode 100644
index 384dfdc26fb51..0000000000000
--- a/tests/failing-non-lto-tests.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-tests/ui/issues/issue-44056.rs
-tests/ui/lto/fat-lto.rs
-tests/ui/lto/debuginfo-lto.rs
-tests/ui/lto/lto-many-codegen-units.rs
-tests/ui/lto/issue-100772.rs
-tests/ui/lto/lto-rustc-loads-linker-plugin.rs
-tests/ui/panic-runtime/lto-unwind.rs
-tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs
-tests/ui/sepcomp/sepcomp-lib-lto.rs
-tests/ui/lto/lto-opt-level-s.rs
-tests/ui/lto/lto-opt-level-z.rs
diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt
index 457072b1a5bcb..082958bfe1f85 100644
--- a/tests/failing-ui-tests.txt
+++ b/tests/failing-ui-tests.txt
@@ -69,20 +69,22 @@ tests/ui/mir/mir_heavy_promoted.rs
 tests/ui/consts/const_cmp_type_id.rs
 tests/ui/consts/issue-73976-monomorphic.rs
 tests/ui/consts/issue-94675.rs
-tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.rs
-tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
+tests/ui/traits/const-traits/const-drop-fail.rs
+tests/ui/traits/const-traits/const-drop.rs
 tests/ui/runtime/on-broken-pipe/child-processes.rs
-tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs
-tests/ui/sanitizer/cfi-async-closures.rs
-tests/ui/sanitizer/cfi-closures.rs
-tests/ui/sanitizer/cfi-complex-receiver.rs
-tests/ui/sanitizer/cfi-coroutine.rs
-tests/ui/sanitizer/cfi-drop-in-place.rs
-tests/ui/sanitizer/cfi-drop-no-principal.rs
-tests/ui/sanitizer/cfi-fn-ptr.rs
-tests/ui/sanitizer/cfi-self-ref.rs
-tests/ui/sanitizer/cfi-supertraits.rs
-tests/ui/sanitizer/cfi-virtual-auto.rs
+tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs
+tests/ui/sanitizer/cfi/async-closures.rs
+tests/ui/sanitizer/cfi/closures.rs
+tests/ui/sanitizer/cfi/complex-receiver.rs
+tests/ui/sanitizer/cfi/coroutine.rs
+tests/ui/sanitizer/cfi/drop-in-place.rs
+tests/ui/sanitizer/cfi/drop-no-principal.rs
+tests/ui/sanitizer/cfi/fn-ptr.rs
+tests/ui/sanitizer/cfi/self-ref.rs
+tests/ui/sanitizer/cfi/supertraits.rs
+tests/ui/sanitizer/cfi/virtual-auto.rs
+tests/ui/sanitizer/cfi/sized-associated-ty.rs
+tests/ui/sanitizer/cfi/can-reveal-opaques.rs
 tests/ui/sanitizer/kcfi-mangling.rs
 tests/ui/statics/const_generics.rs
 tests/ui/backtrace/dylib-dep.rs
@@ -91,6 +93,7 @@ tests/ui/delegation/fn-header.rs
 tests/ui/consts/zst_no_llvm_alloc.rs
 tests/ui/consts/const-eval/parse_ints.rs
 tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
+tests/ui/simd/intrinsic/generic-as.rs
 tests/ui/backtrace/backtrace.rs
 tests/ui/lifetimes/tail-expr-lock-poisoning.rs
 tests/ui/runtime/rt-explody-panic-payloads.rs
@@ -118,5 +121,4 @@ tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs
 tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
 tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
 tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
-tests/ui/sanitizer/cfi-sized-associated-ty.rs
-tests/ui/sanitizer/cfi-can-reveal-opaques.rs
+tests/ui/simd/simd-bitmask-notpow2.rs
diff --git a/tests/failing-ui-tests12.txt b/tests/failing-ui-tests12.txt
index 1d9bdaa552c6b..b10d4bc82aa8d 100644
--- a/tests/failing-ui-tests12.txt
+++ b/tests/failing-ui-tests12.txt
@@ -11,7 +11,6 @@ tests/ui/simd/array-type.rs
 tests/ui/simd/intrinsic/float-minmax-pass.rs
 tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
 tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs
-tests/ui/simd/intrinsic/generic-as.rs
 tests/ui/simd/intrinsic/generic-cast-pass.rs
 tests/ui/simd/intrinsic/generic-cast-pointer-width.rs
 tests/ui/simd/intrinsic/generic-comparison-pass.rs
diff --git a/tests/hello-world/Cargo.lock b/tests/hello-world/Cargo.lock
new file mode 100644
index 0000000000000..fe252db442539
--- /dev/null
+++ b/tests/hello-world/Cargo.lock
@@ -0,0 +1,14 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "hello_world"
+version = "0.0.0"
+dependencies = [
+ "mylib",
+]
+
+[[package]]
+name = "mylib"
+version = "0.1.0"
diff --git a/tests/hello-world/Cargo.toml b/tests/hello-world/Cargo.toml
index 0b8cdc63fbe84..c6e22f642f673 100644
--- a/tests/hello-world/Cargo.toml
+++ b/tests/hello-world/Cargo.toml
@@ -1,4 +1,12 @@
 [package]
 name = "hello_world"
+edition = "2024"
 
 [dependencies]
+mylib = { path = "mylib" }
+
+[profile.dev]
+lto = "thin"
+
+[profile.release]
+lto = "fat"
diff --git a/tests/hello-world/mylib/Cargo.lock b/tests/hello-world/mylib/Cargo.lock
new file mode 100644
index 0000000000000..c8a0bfc635474
--- /dev/null
+++ b/tests/hello-world/mylib/Cargo.lock
@@ -0,0 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "mylib"
+version = "0.1.0"
diff --git a/tests/hello-world/mylib/Cargo.toml b/tests/hello-world/mylib/Cargo.toml
new file mode 100644
index 0000000000000..d15f62bfb6dca
--- /dev/null
+++ b/tests/hello-world/mylib/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "mylib"
+version = "0.1.0"
+authors = ["Antoni Boucher <bouanto@zoho.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/tests/hello-world/mylib/src/lib.rs b/tests/hello-world/mylib/src/lib.rs
new file mode 100644
index 0000000000000..8d3d111bd1993
--- /dev/null
+++ b/tests/hello-world/mylib/src/lib.rs
@@ -0,0 +1,7 @@
+pub fn my_func(a: i32, b: i32) -> i32 {
+    let mut res = a;
+    for i in a..b {
+        res += i;
+    }
+    res
+}
diff --git a/tests/hello-world/src/main.rs b/tests/hello-world/src/main.rs
index e7a11a969c037..71c78d364ac88 100644
--- a/tests/hello-world/src/main.rs
+++ b/tests/hello-world/src/main.rs
@@ -1,3 +1,5 @@
+use mylib::my_func;
+
 fn main() {
-    println!("Hello, world!");
+    println!("{}", my_func(5, 10));
 }
diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs
index aecea37ab5a91..fafb7be55ceb0 100644
--- a/tests/lang_tests_common.rs
+++ b/tests/lang_tests_common.rs
@@ -22,14 +22,20 @@ pub fn main_inner(profile: Profile) {
     let tempdir = TempDir::new().expect("temp dir");
     let current_dir = current_dir().expect("current dir");
     let current_dir = current_dir.to_str().expect("current dir").to_string();
-    let toml = Toml::parse(include_str!("../config.toml")).expect("Failed to parse `config.toml`");
-    let gcc_path = if let Ok(gcc_path) = toml.get_string("gcc-path") {
-        PathBuf::from(gcc_path.to_string())
-    } else {
-        // then we try to retrieve it from the `target` folder.
-        let commit = include_str!("../libgccjit.version").trim();
-        Path::new("build/libgccjit").join(commit)
-    };
+
+    let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
+
+    let gcc_path = std::fs::read_to_string(manifest_dir.join("config.toml"))
+        .ok()
+        .and_then(|v| {
+            let toml = Toml::parse(&v).expect("Failed to parse `config.toml`");
+            toml.get_string("gcc-path").map(PathBuf::from).ok()
+        })
+        .unwrap_or_else(|| {
+            // then we try to retrieve it from the `target` folder.
+            let commit = include_str!("../libgccjit.version").trim();
+            Path::new("build/libgccjit").join(commit)
+        });
 
     let gcc_path = Path::new(&gcc_path)
         .canonicalize()
@@ -83,6 +89,8 @@ pub fn main_inner(profile: Profile) {
                 &format!("{}/build/build_sysroot/sysroot/", current_dir),
                 "-C",
                 "link-arg=-lc",
+                "--extern",
+                "mini_core=target/out/libmini_core.rlib",
                 "-o",
                 exe.to_str().expect("to_str"),
                 path.to_str().expect("to_str"),
diff --git a/tests/run/array.rs b/tests/run/array.rs
index d8de9f28d4cb9..c3c08c29c6dba 100644
--- a/tests/run/array.rs
+++ b/tests/run/array.rs
@@ -7,38 +7,12 @@
 //     5
 //     10
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
+#![feature(no_core, start)]
 
 #![no_std]
 #![no_core]
 
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for usize {}
-impl Copy for i32 {}
-impl Copy for u8 {}
-impl Copy for i8 {}
-impl Copy for i16 {}
-impl<T: ?Sized> Copy for *mut T {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
+extern crate mini_core;
 
 mod libc {
     #[link(name = "c")]
@@ -48,182 +22,6 @@ mod libc {
     }
 }
 
-#[lang = "index"]
-pub trait Index<Idx: ?Sized> {
-    type Output: ?Sized;
-    fn index(&self, index: Idx) -> &Self::Output;
-}
-
-impl<T> Index<usize> for [T; 3] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-impl<T> Index<usize> for [T] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-#[lang = "drop_in_place"]
-#[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-    // Code here does not matter - this is replaced by the
-    // real drop glue by the compiler.
-    drop_in_place(to_drop);
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
-    unsafe {
-        libc::puts("Panicking\0" as *const str as *const u8);
-        intrinsics::abort();
-    }
-}
-
-#[lang = "panic_location"]
-struct PanicLocation {
-    file: &'static str,
-    line: u32,
-    column: u32,
-}
-
-#[lang = "panic_bounds_check"]
-#[track_caller]
-#[no_mangle]
-fn panic_bounds_check(index: usize, len: usize) -> ! {
-    unsafe {
-        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
-        intrinsics::abort();
-    }
-}
-
-mod intrinsics {
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
-    type Output;
-
-    fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i32 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for usize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for isize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-#[lang = "sub"]
-pub trait Sub<RHS = Self> {
-    type Output;
-
-    fn sub(self, rhs: RHS) -> Self::Output;
-}
-
-impl Sub for usize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for isize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for u8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for i8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for i16 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-#[track_caller]
-#[lang = "panic_const_add_overflow"]
-pub fn panic_const_add_overflow() -> ! {
-    panic("attempt to add with overflow");
-}
-
-#[track_caller]
-#[lang = "panic_const_sub_overflow"]
-pub fn panic_const_sub_overflow() -> ! {
-    panic("attempt to subtract with overflow");
-}
-
-/*
- * Code
- */
-
 static mut ONE: usize = 1;
 
 fn make_array() -> [u8; 3] {
diff --git a/tests/run/closure.rs b/tests/run/closure.rs
index b0d0ca4ee8dfa..46c47bc54ed01 100644
--- a/tests/run/closure.rs
+++ b/tests/run/closure.rs
@@ -8,200 +8,20 @@
 //     Int argument: 2
 //     Both args: 11
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics,
-    unboxed_closures, rustc_attrs)]
-#![allow(internal_features)]
+#![feature(no_core, start)]
 
 #![no_std]
 #![no_core]
 
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for usize {}
-impl Copy for i32 {}
-impl Copy for u32 {}
-impl Copy for u8 {}
-impl Copy for i8 {}
-impl<T: ?Sized> Copy for *mut T {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
+extern crate mini_core;
 
 mod libc {
     #[link(name = "c")]
     extern "C" {
-        pub fn puts(s: *const u8) -> i32;
         pub fn printf(format: *const i8, ...) -> i32;
     }
 }
 
-#[lang = "index"]
-pub trait Index<Idx: ?Sized> {
-    type Output: ?Sized;
-    fn index(&self, index: Idx) -> &Self::Output;
-}
-
-impl<T> Index<usize> for [T; 3] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-impl<T> Index<usize> for [T] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-#[lang = "drop_in_place"]
-#[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-    // Code here does not matter - this is replaced by the
-    // real drop glue by the compiler.
-    drop_in_place(to_drop);
-}
-
-#[lang = "panic_location"]
-struct PanicLocation {
-    file: &'static str,
-    line: u32,
-    column: u32,
-}
-
-#[lang = "panic_bounds_check"]
-#[track_caller]
-#[no_mangle]
-fn panic_bounds_check(index: usize, len: usize) -> ! {
-    unsafe {
-        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
-        intrinsics::abort();
-    }
-}
-
-mod intrinsics {
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
-}
-
-#[lang = "tuple_trait"]
-pub trait Tuple {}
-
-#[lang = "unsize"]
-pub trait Unsize<T: ?Sized> {}
-
-#[lang = "coerce_unsized"]
-pub trait CoerceUnsized<T> {}
-
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
-
-#[lang = "fn_once"]
-#[rustc_paren_sugar]
-pub trait FnOnce<Args: Tuple> {
-    #[lang = "fn_once_output"]
-    type Output;
-
-    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-}
-
-#[lang = "fn_mut"]
-#[rustc_paren_sugar]
-pub trait FnMut<Args: Tuple>: FnOnce<Args> {
-    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
-    type Output;
-
-    fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i32 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for usize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for isize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
-    unsafe {
-        libc::puts("Panicking\0" as *const str as *const u8);
-        intrinsics::abort();
-    }
-}
-
-#[track_caller]
-#[lang = "panic_const_add_overflow"]
-pub fn panic_const_add_overflow() -> ! {
-    panic("attempt to add with overflow");
-}
-
-/*
- * Code
- */
-
 #[start]
 fn main(mut argc: isize, _argv: *const *const u8) -> isize {
     let string = "Arg: %d\n\0";
diff --git a/tests/run/condition.rs b/tests/run/condition.rs
index 770b18a89e3e0..039ef94eaa717 100644
--- a/tests/run/condition.rs
+++ b/tests/run/condition.rs
@@ -5,304 +5,20 @@
 //   stdout: true
 //     1
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
+#![feature(no_core, start)]
 
 #![no_std]
 #![no_core]
 
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for usize {}
-impl Copy for u64 {}
-impl Copy for i32 {}
-impl Copy for u32 {}
-impl Copy for bool {}
-impl Copy for u16 {}
-impl Copy for i16 {}
-impl Copy for char {}
-impl Copy for i8 {}
-impl Copy for u8 {}
-impl<T: ?Sized> Copy for *mut T {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
+extern crate mini_core;
 
 mod libc {
     #[link(name = "c")]
     extern "C" {
         pub fn printf(format: *const i8, ...) -> i32;
-        pub fn puts(s: *const u8) -> i32;
-    }
-}
-
-#[lang = "index"]
-pub trait Index<Idx: ?Sized> {
-    type Output: ?Sized;
-    fn index(&self, index: Idx) -> &Self::Output;
-}
-
-impl<T> Index<usize> for [T; 3] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-impl<T> Index<usize> for [T] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-#[lang = "drop_in_place"]
-#[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-    // Code here does not matter - this is replaced by the
-    // real drop glue by the compiler.
-    drop_in_place(to_drop);
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
-    unsafe {
-        libc::puts("Panicking\0" as *const str as *const u8);
-        intrinsics::abort();
-    }
-}
-
-#[lang = "panic_location"]
-struct PanicLocation {
-    file: &'static str,
-    line: u32,
-    column: u32,
-}
-
-#[lang = "panic_bounds_check"]
-#[track_caller]
-#[no_mangle]
-fn panic_bounds_check(index: usize, len: usize) -> ! {
-    unsafe {
-        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
-        intrinsics::abort();
-    }
-}
-
-mod intrinsics {
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
-    type Output;
-
-    fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i32 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for usize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for isize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-#[lang = "sub"]
-pub trait Sub<RHS = Self> {
-    type Output;
-
-    fn sub(self, rhs: RHS) -> Self::Output;
-}
-
-impl Sub for usize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for isize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for u8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for i8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
     }
 }
 
-impl Sub for i16 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-#[lang = "eq"]
-pub trait PartialEq<Rhs: ?Sized = Self> {
-    fn eq(&self, other: &Rhs) -> bool;
-    fn ne(&self, other: &Rhs) -> bool;
-}
-
-impl PartialEq for u8 {
-    fn eq(&self, other: &u8) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &u8) -> bool {
-        (*self) != (*other)
-    }
-}
-
-impl PartialEq for u16 {
-    fn eq(&self, other: &u16) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &u16) -> bool {
-        (*self) != (*other)
-    }
-}
-
-impl PartialEq for u32 {
-    fn eq(&self, other: &u32) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &u32) -> bool {
-        (*self) != (*other)
-    }
-}
-
-
-impl PartialEq for u64 {
-    fn eq(&self, other: &u64) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &u64) -> bool {
-        (*self) != (*other)
-    }
-}
-
-impl PartialEq for usize {
-    fn eq(&self, other: &usize) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &usize) -> bool {
-        (*self) != (*other)
-    }
-}
-
-impl PartialEq for i8 {
-    fn eq(&self, other: &i8) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &i8) -> bool {
-        (*self) != (*other)
-    }
-}
-
-impl PartialEq for i32 {
-    fn eq(&self, other: &i32) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &i32) -> bool {
-        (*self) != (*other)
-    }
-}
-
-impl PartialEq for isize {
-    fn eq(&self, other: &isize) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &isize) -> bool {
-        (*self) != (*other)
-    }
-}
-
-impl PartialEq for char {
-    fn eq(&self, other: &char) -> bool {
-        (*self) == (*other)
-    }
-    fn ne(&self, other: &char) -> bool {
-        (*self) != (*other)
-    }
-}
-
-/*
- * Code
- */
-
 #[start]
 fn main(argc: isize, _argv: *const *const u8) -> isize {
     unsafe {
diff --git a/tests/run/fun_ptr.rs b/tests/run/fun_ptr.rs
index 523544ee6bbbb..ed1bf72bb2754 100644
--- a/tests/run/fun_ptr.rs
+++ b/tests/run/fun_ptr.rs
@@ -4,212 +4,20 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
+#![feature(no_core, start)]
 
 #![no_std]
 #![no_core]
 
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for usize {}
-impl Copy for i32 {}
-impl Copy for u8 {}
-impl Copy for i8 {}
-impl Copy for i16 {}
-impl<T: ?Sized> Copy for *mut T {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
+extern crate mini_core;
 
 mod libc {
     #[link(name = "c")]
     extern "C" {
         pub fn printf(format: *const i8, ...) -> i32;
-        pub fn puts(s: *const u8) -> i32;
-    }
-}
-
-#[lang = "index"]
-pub trait Index<Idx: ?Sized> {
-    type Output: ?Sized;
-    fn index(&self, index: Idx) -> &Self::Output;
-}
-
-impl<T> Index<usize> for [T; 3] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-impl<T> Index<usize> for [T] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-#[lang = "drop_in_place"]
-#[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-    // Code here does not matter - this is replaced by the
-    // real drop glue by the compiler.
-    drop_in_place(to_drop);
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
-    unsafe {
-        libc::puts("Panicking\0" as *const str as *const u8);
-        intrinsics::abort();
-    }
-}
-
-#[lang = "panic_location"]
-struct PanicLocation {
-    file: &'static str,
-    line: u32,
-    column: u32,
-}
-
-#[lang = "panic_bounds_check"]
-#[track_caller]
-#[no_mangle]
-fn panic_bounds_check(index: usize, len: usize) -> ! {
-    unsafe {
-        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
-        intrinsics::abort();
-    }
-}
-
-mod intrinsics {
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
-    type Output;
-
-    fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i32 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for usize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for isize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-#[lang = "sub"]
-pub trait Sub<RHS = Self> {
-    type Output;
-
-    fn sub(self, rhs: RHS) -> Self::Output;
-}
-
-impl Sub for usize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for isize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for u8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
     }
 }
 
-impl Sub for i8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for i16 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-
-/*
- * Code
- */
-
 fn i16_as_i8(a: i16) -> i8 {
     a as i8
 }
diff --git a/tests/run/operations.rs b/tests/run/operations.rs
index 2e3c021d5f772..0e44fc580b8c4 100644
--- a/tests/run/operations.rs
+++ b/tests/run/operations.rs
@@ -38,8 +38,8 @@ pub trait Deref {
     fn deref(&self) -> &Self::Target;
 }
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
diff --git a/tests/run/ptr_cast.rs b/tests/run/ptr_cast.rs
index c7510d16449ef..2b8812ad51c5e 100644
--- a/tests/run/ptr_cast.rs
+++ b/tests/run/ptr_cast.rs
@@ -4,212 +4,20 @@
 //   status: 0
 //   stdout: 1
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
+#![feature(no_core, start)]
 
 #![no_std]
 #![no_core]
 
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for usize {}
-impl Copy for i32 {}
-impl Copy for u8 {}
-impl Copy for i8 {}
-impl Copy for i16 {}
-impl<T: ?Sized> Copy for *mut T {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
+extern crate mini_core;
 
 mod libc {
     #[link(name = "c")]
     extern "C" {
         pub fn printf(format: *const i8, ...) -> i32;
-        pub fn puts(s: *const u8) -> i32;
-    }
-}
-
-#[lang = "index"]
-pub trait Index<Idx: ?Sized> {
-    type Output: ?Sized;
-    fn index(&self, index: Idx) -> &Self::Output;
-}
-
-impl<T> Index<usize> for [T; 3] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-impl<T> Index<usize> for [T] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-#[lang = "drop_in_place"]
-#[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-    // Code here does not matter - this is replaced by the
-    // real drop glue by the compiler.
-    drop_in_place(to_drop);
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
-    unsafe {
-        libc::puts("Panicking\0" as *const str as *const u8);
-        intrinsics::abort();
-    }
-}
-
-#[lang = "panic_location"]
-struct PanicLocation {
-    file: &'static str,
-    line: u32,
-    column: u32,
-}
-
-#[lang = "panic_bounds_check"]
-#[track_caller]
-#[no_mangle]
-fn panic_bounds_check(index: usize, len: usize) -> ! {
-    unsafe {
-        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
-        intrinsics::abort();
-    }
-}
-
-mod intrinsics {
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
-    type Output;
-
-    fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i8 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for i32 {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for usize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-impl Add for isize {
-    type Output = Self;
-
-    fn add(self, rhs: Self) -> Self {
-        self + rhs
-    }
-}
-
-#[lang = "sub"]
-pub trait Sub<RHS = Self> {
-    type Output;
-
-    fn sub(self, rhs: RHS) -> Self::Output;
-}
-
-impl Sub for usize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for isize {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for u8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
     }
 }
 
-impl Sub for i8 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-impl Sub for i16 {
-    type Output = Self;
-
-    fn sub(self, rhs: Self) -> Self {
-        self - rhs
-    }
-}
-
-
-/*
- * Code
- */
-
 static mut ONE: usize = 1;
 
 fn make_array() -> [u8; 3] {
diff --git a/tests/run/return-tuple.rs b/tests/run/return-tuple.rs
index 8d40deb8c85ef..f2a5a2e4384df 100644
--- a/tests/run/return-tuple.rs
+++ b/tests/run/return-tuple.rs
@@ -15,18 +15,18 @@
 #[lang = "copy"]
 pub unsafe trait Copy {}
 
-unsafe impl Copy for bool {}
-unsafe impl Copy for u8 {}
-unsafe impl Copy for u16 {}
-unsafe impl Copy for u32 {}
-unsafe impl Copy for u64 {}
-unsafe impl Copy for usize {}
-unsafe impl Copy for i8 {}
-unsafe impl Copy for i16 {}
-unsafe impl Copy for i32 {}
-unsafe impl Copy for isize {}
-unsafe impl Copy for f32 {}
-unsafe impl Copy for char {}
+impl Copy for bool {}
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for u64 {}
+impl Copy for usize {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for isize {}
+impl Copy for f32 {}
+impl Copy for char {}
 
 mod libc {
     #[link(name = "c")]
@@ -43,8 +43,8 @@ mod libc {
 #[lang = "sized"]
 pub trait Sized {}
 
-#[lang = "receiver"]
-trait Receiver {
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {
 }
 
 #[lang = "freeze"]
diff --git a/tests/run/slice.rs b/tests/run/slice.rs
index 35ad594ecdea3..fba93fc155495 100644
--- a/tests/run/slice.rs
+++ b/tests/run/slice.rs
@@ -4,36 +4,12 @@
 //   status: 0
 //   stdout: 5
 
-#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
+#![feature(no_core, start)]
 
 #![no_std]
 #![no_core]
 
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for usize {}
-impl Copy for i32 {}
-impl Copy for u32 {}
-impl<T: ?Sized> Copy for *mut T {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
+extern crate mini_core;
 
 mod libc {
     #[link(name = "c")]
@@ -42,79 +18,6 @@ mod libc {
     }
 }
 
-#[lang = "index"]
-pub trait Index<Idx: ?Sized> {
-    type Output: ?Sized;
-    fn index(&self, index: Idx) -> &Self::Output;
-}
-
-impl<T> Index<usize> for [T; 3] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-impl<T> Index<usize> for [T] {
-    type Output = T;
-
-    fn index(&self, index: usize) -> &Self::Output {
-        &self[index]
-    }
-}
-
-#[lang = "unsize"]
-pub trait Unsize<T: ?Sized> {}
-
-#[lang = "coerce_unsized"]
-pub trait CoerceUnsized<T> {}
-
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
-
-#[lang = "drop_in_place"]
-#[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-    // Code here does not matter - this is replaced by the
-    // real drop glue by the compiler.
-    drop_in_place(to_drop);
-}
-
-#[lang = "panic_location"]
-struct PanicLocation {
-    file: &'static str,
-    line: u32,
-    column: u32,
-}
-
-#[lang = "panic_bounds_check"]
-#[track_caller]
-#[no_mangle]
-fn panic_bounds_check(index: usize, len: usize) -> ! {
-    unsafe {
-        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
-        intrinsics::abort();
-    }
-}
-
-mod intrinsics {
-    use super::Sized;
-
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
-}
-
-/*
- * Code
- */
-
 static mut TWO: usize = 2;
 
 fn index_slice(s: &[u32]) -> u32 {
diff --git a/tests/run/volatile2.rs b/tests/run/volatile2.rs
new file mode 100644
index 0000000000000..a177b817ab35a
--- /dev/null
+++ b/tests/run/volatile2.rs
@@ -0,0 +1,113 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+
+        pub fn sigaction(signum: i32, act: *const sigaction, oldact: *mut sigaction) -> i32;
+        pub fn mmap(addr: *mut (), len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut ();
+        pub fn mprotect(addr: *mut (), len: usize, prot: i32) -> i32;
+    }
+
+    pub const PROT_READ: i32 = 1;
+    pub const PROT_WRITE: i32 = 2;
+    pub const MAP_PRIVATE: i32 = 0x0002;
+    pub const MAP_ANONYMOUS: i32 = 0x0020;
+    pub const MAP_FAILED: *mut u8 = !0 as *mut u8;
+
+    /// glibc sigaction
+    #[repr(C)]
+    pub struct sigaction {
+        pub sa_sigaction: Option<unsafe extern "C" fn(i32, *mut (), *mut ())>,
+        pub sa_mask: [u32; 32],
+        pub sa_flags: i32,
+        pub sa_restorer: Option<unsafe extern "C" fn()>,
+    }
+
+    pub const SA_SIGINFO: i32 = 0x00000004;
+    pub const SIGSEGV: i32 = 11;
+}
+
+static mut COUNT: u32 = 0;
+static mut STORAGE: *mut u8 = core::ptr::null_mut();
+const PAGE_SIZE: usize = 1 << 15;
+
+fn main() {
+    unsafe {
+        // Register a segfault handler
+        libc::sigaction(
+            libc::SIGSEGV,
+            &libc::sigaction {
+                sa_sigaction: Some(segv_handler),
+                sa_flags: libc::SA_SIGINFO,
+                ..core::mem::zeroed()
+            },
+            core::ptr::null_mut(),
+        );
+
+        STORAGE = libc::mmap(
+            core::ptr::null_mut(),
+            PAGE_SIZE * 2,
+            0,
+            libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+            -1,
+            0,
+        ).cast();
+        if STORAGE == libc::MAP_FAILED {
+            panic!("error: mmap failed");
+        }
+
+        let p_count = (&mut COUNT) as *mut u32;
+        p_count.write_volatile(0);
+
+        // Trigger segfaults
+        STORAGE.add(0).write_volatile(1);
+        STORAGE.add(PAGE_SIZE).write_volatile(1);
+        STORAGE.add(0).write_volatile(1);
+        STORAGE.add(PAGE_SIZE).write_volatile(1);
+        STORAGE.add(0).write_volatile(1);
+        STORAGE.add(PAGE_SIZE).write_volatile(1);
+        STORAGE.add(0).read_volatile();
+        STORAGE.add(PAGE_SIZE).read_volatile();
+        STORAGE.add(0).read_volatile();
+        STORAGE.add(PAGE_SIZE).read_volatile();
+        STORAGE.add(0).read_volatile();
+        STORAGE.add(PAGE_SIZE).read_volatile();
+        STORAGE.add(0).write_volatile(1);
+        STORAGE.add(PAGE_SIZE).write_volatile(1);
+
+        // The segfault handler should have been called for every `write_volatile` and
+        // `read_volatile` in `STORAGE`. If the compiler ignores volatility, some of these writes
+        // will be combined, causing a different number of segfaults.
+        //
+        // This `p_count` read is done by a volatile read. If the compiler
+        // ignores volatility, the compiler will speculate that `*p_count` is
+        // unchanged and remove this check, failing the test.
+        if p_count.read_volatile() != 14 {
+            panic!("error: segfault count mismatch: {}", p_count.read_volatile());
+        }
+    }
+}
+
+unsafe extern "C" fn segv_handler(_: i32, _: *mut (), _: *mut ()) {
+    let p_count = (&mut COUNT) as *mut u32;
+    p_count.write_volatile(p_count.read_volatile() + 1);
+    let count = p_count.read_volatile();
+
+    // Toggle the protected page so that the handler will be called for
+    // each `write_volatile`
+    libc::mprotect(
+        STORAGE.cast(),
+        PAGE_SIZE,
+        if count % 2 == 1 { libc::PROT_READ | libc::PROT_WRITE } else { 0 },
+    );
+    libc::mprotect(
+        STORAGE.add(PAGE_SIZE).cast(),
+        PAGE_SIZE,
+        if count % 2 == 0 { libc::PROT_READ | libc::PROT_WRITE } else { 0 },
+    );
+}

From f8b89a3d05e995bd293aaac35d97f4b18b54e8fe Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Mon, 13 Jan 2025 11:48:14 -0500
Subject: [PATCH 02/11] Fix formatting

---
 .rustfmt.toml              | 4 +++-
 src/intrinsic/mod.rs       | 4 ++--
 tests/lang_tests_common.rs | 8 +++-----
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.rustfmt.toml b/.rustfmt.toml
index 725aec25a0718..a11bc41680d24 100644
--- a/.rustfmt.toml
+++ b/.rustfmt.toml
@@ -1,3 +1,5 @@
-version = "Two"
+style_edition = "2024"
 use_small_heuristics = "Max"
 merge_derives = false
+group_imports = "StdExternalCrate"
+imports_granularity = "Module"
diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs
index 11f9604c6d260..42d189d1b7d38 100644
--- a/src/intrinsic/mod.rs
+++ b/src/intrinsic/mod.rs
@@ -13,11 +13,11 @@ use rustc_codegen_ssa::common::IntPredicate;
 use rustc_codegen_ssa::errors::InvalidMonomorphization;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
-use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
 #[cfg(feature = "master")]
 use rustc_codegen_ssa::traits::MiscCodegenMethods;
 use rustc_codegen_ssa::traits::{
-    ArgAbiBuilderMethods, BuilderMethods, ConstCodegenMethods, IntrinsicCallBuilderMethods,
+    ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods,
+    IntrinsicCallBuilderMethods,
 };
 use rustc_middle::bug;
 #[cfg(feature = "master")]
diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs
index fafb7be55ceb0..64c932a265819 100644
--- a/tests/lang_tests_common.rs
+++ b/tests/lang_tests_common.rs
@@ -1,10 +1,8 @@
 //! The common code for `tests/lang_tests_*.rs`
 
-use std::{
-    env::{self, current_dir},
-    path::{Path, PathBuf},
-    process::Command,
-};
+use std::env::{self, current_dir};
+use std::path::{Path, PathBuf};
+use std::process::Command;
 
 use boml::Toml;
 use lang_tester::LangTester;

From 7bc67011d27f3e1ce15d8368f75365644549fbe8 Mon Sep 17 00:00:00 2001
From: Sudhanshu Singh <singhsudhanshu069@gmail.com>
Date: Mon, 13 Jan 2025 22:27:33 +0530
Subject: [PATCH 03/11] Remove codegen_gcc_lto_not_supported in messages.flt

---
 messages.ftl | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/messages.ftl b/messages.ftl
index 85fa17a6ba501..882fff8673a19 100644
--- a/messages.ftl
+++ b/messages.ftl
@@ -5,9 +5,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
 codegen_gcc_invalid_minimum_alignment =
     invalid minimum global alignment: {$err}
 
-codegen_gcc_lto_not_supported =
-    LTO is not supported. You may get a linker error.
-
 codegen_gcc_forbidden_ctarget_feature =
     target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
 

From 50a9f41ce97ec0c297d33611f1cd91e81bf1e519 Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Wed, 15 Jan 2025 10:26:57 -0500
Subject: [PATCH 04/11] Update GCC version

---
 .github/workflows/ci.yml       | 4 ++--
 .github/workflows/failures.yml | 4 ++--
 .github/workflows/m68k.yml     | 6 +++---
 .github/workflows/release.yml  | 4 ++--
 libgccjit.version              | 2 +-
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 73ec6b84a155e..fa6133c75e315 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,8 +19,8 @@ jobs:
       fail-fast: false
       matrix:
         libgccjit_version:
-          - { gcc: "gcc-13.deb" }
-          - { gcc: "gcc-13-without-int128.deb" }
+          - { gcc: "gcc-15.deb" }
+          - { gcc: "gcc-15-without-int128.deb" }
         commands: [
           "--std-tests",
           # FIXME: re-enable asm tests when GCC can emit in the right syntax.
diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml
index f33d9fcc58257..407c9b31d05cf 100644
--- a/.github/workflows/failures.yml
+++ b/.github/workflows/failures.yml
@@ -56,12 +56,12 @@ jobs:
 
     - name: Download artifact
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
-      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-13.deb
+      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-15.deb
 
     - name: Setup path to libgccjit
       if: matrix.libgccjit_version.gcc != 'libgccjit12.so'
       run: |
-          sudo dpkg --force-overwrite -i gcc-13.deb
+          sudo dpkg --force-overwrite -i gcc-15.deb
           echo 'gcc-path = "/usr/lib"' > config.toml
           echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
           echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml
index 07bb372b3606d..369299e644789 100644
--- a/.github/workflows/m68k.yml
+++ b/.github/workflows/m68k.yml
@@ -47,17 +47,17 @@ jobs:
     - name: Install packages
       run: |
         sudo apt-get update
-        sudo apt-get install qemu qemu-user-static
+        sudo apt-get install qemu-system qemu-user-static
 
     - name: Download artifact
-      run: curl -LO https://github.com/cross-cg-gcc-tools/cross-gcc/releases/latest/download/gcc-m68k-13.deb
+      run: curl -LO https://github.com/cross-cg-gcc-tools/cross-gcc/releases/latest/download/gcc-m68k-15.deb
 
     - name: Download VM artifact
       run: curl -LO https://github.com/cross-cg-gcc-tools/vms/releases/latest/download/debian-m68k.img
 
     - name: Setup path to libgccjit
       run: |
-          sudo dpkg -i gcc-m68k-13.deb
+          sudo dpkg -i gcc-m68k-15.deb
           echo 'gcc-path = "/usr/lib/"' > config.toml
 
     - name: Set env
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 60e0943c87dac..f36b149704824 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -37,11 +37,11 @@ jobs:
       run: sudo apt-get install ninja-build ripgrep
 
     - name: Download artifact
-      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-13.deb
+      run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-15.deb
 
     - name: Setup path to libgccjit
       run: |
-          sudo dpkg --force-overwrite -i gcc-13.deb
+          sudo dpkg --force-overwrite -i gcc-15.deb
           echo 'gcc-path = "/usr/lib/"' > config.toml
 
     - name: Set env
diff --git a/libgccjit.version b/libgccjit.version
index ff58accec1d4c..417fd5b03935d 100644
--- a/libgccjit.version
+++ b/libgccjit.version
@@ -1 +1 @@
-45648c2edd4ecd862d9f08196d3d6c6ccba79f07
+e607be166673a8de9fc07f6f02c60426e556c5f2

From 0ab1f8ddb0d8364892e7cf2a064f9eb988c91a23 Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Wed, 15 Jan 2025 10:30:57 -0500
Subject: [PATCH 05/11] Update the CI to Ubuntu 24.04

---
 .github/workflows/ci.yml       | 6 +++---
 .github/workflows/failures.yml | 2 +-
 .github/workflows/gcc12.yml    | 2 +-
 .github/workflows/m68k.yml     | 2 +-
 .github/workflows/release.yml  | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fa6133c75e315..f96912e6b7a83 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,7 +13,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
@@ -108,13 +108,13 @@ jobs:
         cargo clippy --all-targets --features master -- -D warnings
 
   duplicates:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@v4
       - run: python tools/check_intrinsics_duplicates.py
 
   build_system:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@v4
       - name: Test build system
diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml
index 407c9b31d05cf..d080bbfe91fe6 100644
--- a/.github/workflows/failures.yml
+++ b/.github/workflows/failures.yml
@@ -13,7 +13,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml
index 4c2ce91e86eef..bb9e020dc6a4c 100644
--- a/.github/workflows/gcc12.yml
+++ b/.github/workflows/gcc12.yml
@@ -17,7 +17,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml
index 369299e644789..ed1fc02bd9131 100644
--- a/.github/workflows/m68k.yml
+++ b/.github/workflows/m68k.yml
@@ -17,7 +17,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f36b149704824..77bb9056b2795 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -13,7 +13,7 @@ env:
 
 jobs:
   build:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
 
     strategy:
       fail-fast: false

From 638611f5f5ab1262f42791d9e8771d29dac6cd87 Mon Sep 17 00:00:00 2001
From: Raj Aryan Agrawal <rajaryan.a.258@gmail.com>
Date: Thu, 16 Jan 2025 15:46:33 +0900
Subject: [PATCH 06/11] Add grep check for LTO Test

---
 .github/workflows/release.yml | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 77bb9056b2795..886ce90b4713e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -76,4 +76,9 @@ jobs:
     - name: Run y.sh cargo build
       run: |
         EMBED_LTO_BITCODE=1 CHANNEL="release" ./y.sh cargo build --release --manifest-path tests/hello-world/Cargo.toml
-        # TODO: grep the asm output for "call my_func" and fail if it is found.
+        call_found=$(objdump -dj .text tests/hello-world/target/release/hello_world | grep -c "call .*mylib.*my_func" ) ||:
+        if [ $call_found -gt 0 ]; then
+          echo "ERROR: call my_func found in asm"
+          echo "Test is done with LTO enabled, hence inlining should occur across crates"
+          exit 1
+        fi

From 8d0eb87d08ac146cddb85e8f59fa6902204290c1 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Fri, 24 Jan 2025 15:28:16 +0100
Subject: [PATCH 07/11] Remove extra whitespace at the end of some line strings

---
 build_system/src/main.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/build_system/src/main.rs b/build_system/src/main.rs
index 3a860e2b1360c..393617183061b 100644
--- a/build_system/src/main.rs
+++ b/build_system/src/main.rs
@@ -34,11 +34,11 @@ Options:
         --help    : Displays this help message.
 
 Commands:
-        cargo     : Executes a cargo command. 
+        cargo     : Executes a cargo command.
         rustc     : Compiles the program using the GCC compiler.
         clean     : Cleans the build directory, removing all compiled files and artifacts.
         prepare   : Prepares the environment for building, including fetching dependencies and setting up configurations.
-        build     : Compiles the project. 
+        build     : Compiles the project.
         test      : Runs tests for the project.
         info      : Displays information about the build environment and project configuration.
         clone-gcc : Clones the GCC compiler from a specified source.

From f24b0d358ac32af14994657865e1b4493550dc7a Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Fri, 24 Jan 2025 10:48:53 -0500
Subject: [PATCH 08/11] Add comment to explain why CG_RUSTFLAGS is needed

---
 build_system/src/build.rs  | 2 ++
 build_system/src/config.rs | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/build_system/src/build.rs b/build_system/src/build.rs
index d0ced211a6169..a027c82a0b56a 100644
--- a/build_system/src/build.rs
+++ b/build_system/src/build.rs
@@ -150,6 +150,8 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
         "debug"
     };
 
+    // We have a different environment variable than RUSTFLAGS to make sure those flags are only
+    // sent to rustc_codegen_gcc and not the LLVM backend.
     if let Ok(cg_rustflags) = std::env::var("CG_RUSTFLAGS") {
         rustflags.push(' ');
         rustflags.push_str(&cg_rustflags);
diff --git a/build_system/src/config.rs b/build_system/src/config.rs
index 37b4b68950e49..f10eee2651a7e 100644
--- a/build_system/src/config.rs
+++ b/build_system/src/config.rs
@@ -381,6 +381,8 @@ impl ConfigInfo {
         }
 
         // This environment variable is useful in case we want to change options of rustc commands.
+        // We have a different environment variable than RUSTFLAGS to make sure those flags are
+        // only sent to rustc_codegen_gcc and not the LLVM backend.
         if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
             rustflags.extend_from_slice(&split_args(&cg_rustflags)?);
         }

From 4798615ad4199a87f5ad880ad757b67b6db6e4f8 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Fri, 24 Jan 2025 16:09:26 +0100
Subject: [PATCH 09/11] Add `--gcc-path` option

---
 build_system/src/build.rs  |  8 ++++++--
 build_system/src/config.rs | 40 ++++++++++++++++++++++++++------------
 build_system/src/info.rs   |  4 +++-
 build_system/src/test.rs   |  7 +++++--
 4 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/build_system/src/build.rs b/build_system/src/build.rs
index d0ced211a6169..2f48d78e6a8bf 100644
--- a/build_system/src/build.rs
+++ b/build_system/src/build.rs
@@ -184,8 +184,12 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
 fn build_codegen(args: &mut BuildArg) -> Result<(), String> {
     let mut env = HashMap::new();
 
-    env.insert("LD_LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
-    env.insert("LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
+    let gcc_path =
+        args.config_info.gcc_path.clone().expect(
+            "The config module should have emitted an error if the GCC path wasn't provided",
+        );
+    env.insert("LD_LIBRARY_PATH".to_string(), gcc_path.clone());
+    env.insert("LIBRARY_PATH".to_string(), gcc_path);
 
     if args.config_info.no_default_features {
         env.insert("RUSTFLAGS".to_string(), "-Csymbol-mangling-version=v0".to_string());
diff --git a/build_system/src/config.rs b/build_system/src/config.rs
index 37b4b68950e49..e8eeb559c79de 100644
--- a/build_system/src/config.rs
+++ b/build_system/src/config.rs
@@ -112,7 +112,7 @@ pub struct ConfigInfo {
     pub sysroot_panic_abort: bool,
     pub cg_backend_path: String,
     pub sysroot_path: String,
-    pub gcc_path: String,
+    pub gcc_path: Option<String>,
     config_file: Option<String>,
     // This is used in particular in rust compiler bootstrap because it doesn't run at the root
     // of the `cg_gcc` folder, making it complicated for us to get access to local files we need
@@ -173,6 +173,14 @@ impl ConfigInfo {
             "--release-sysroot" => self.sysroot_release_channel = true,
             "--release" => self.channel = Channel::Release,
             "--sysroot-panic-abort" => self.sysroot_panic_abort = true,
+            "--gcc-path" => match args.next() {
+                Some(arg) if !arg.is_empty() => {
+                    self.gcc_path = Some(arg.into());
+                }
+                _ => {
+                    return Err("Expected a value after `--gcc-path`, found nothing".to_string());
+                }
+            },
             "--cg_gcc-path" => match args.next() {
                 Some(arg) if !arg.is_empty() => {
                     self.cg_gcc_path = Some(arg.into());
@@ -260,8 +268,9 @@ impl ConfigInfo {
             create_symlink(&libgccjit_so, output_dir.join(&format!("{}.0", libgccjit_so_name)))?;
         }
 
-        self.gcc_path = output_dir.display().to_string();
-        println!("Using `{}` as path for libgccjit", self.gcc_path);
+        let gcc_path = output_dir.display().to_string();
+        println!("Using `{}` as path for libgccjit", gcc_path);
+        self.gcc_path = Some(gcc_path);
         Ok(())
     }
 
@@ -273,6 +282,11 @@ impl ConfigInfo {
     }
 
     pub fn setup_gcc_path(&mut self) -> Result<(), String> {
+        // If the user used the `--gcc-path` option, no need to look at `config.toml` content
+        // since we already have everything we need.
+        if self.gcc_path.is_some() {
+            return Ok(());
+        }
         let config_file = match self.config_file.as_deref() {
             Some(config_file) => config_file.into(),
             None => self.compute_path("config.toml"),
@@ -283,12 +297,10 @@ impl ConfigInfo {
             self.download_gccjit_if_needed()?;
             return Ok(());
         }
-        self.gcc_path = match gcc_path {
-            Some(path) => path,
-            None => {
-                return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),));
-            }
-        };
+        if gcc_path.is_none() {
+            return Err(format!("missing `gcc-path` value from `{}`", config_file.display()));
+        }
+        self.gcc_path = gcc_path;
         Ok(())
     }
 
@@ -299,10 +311,13 @@ impl ConfigInfo {
     ) -> Result<(), String> {
         env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string());
 
-        if self.gcc_path.is_empty() && !use_system_gcc {
+        if self.gcc_path.is_none() && !use_system_gcc {
             self.setup_gcc_path()?;
         }
-        env.insert("GCC_PATH".to_string(), self.gcc_path.clone());
+        let gcc_path = self.gcc_path.clone().expect(
+            "The config module should have emitted an error if the GCC path wasn't provided",
+        );
+        env.insert("GCC_PATH".to_string(), gcc_path.clone());
 
         if self.cargo_target_dir.is_empty() {
             match env.get("CARGO_TARGET_DIR").filter(|dir| !dir.is_empty()) {
@@ -414,7 +429,7 @@ impl ConfigInfo {
             "{target}:{sysroot}:{gcc_path}",
             target = self.cargo_target_dir,
             sysroot = sysroot.display(),
-            gcc_path = self.gcc_path,
+            gcc_path = gcc_path,
         );
         env.insert("LIBRARY_PATH".to_string(), ld_library_path.clone());
         env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone());
@@ -459,6 +474,7 @@ impl ConfigInfo {
     --release-sysroot      : Build sysroot in release mode
     --sysroot-panic-abort  : Build the sysroot without unwinding support
     --config-file          : Location of the config file to be used
+    --gcc-path             : Location of the GCC root folder
     --cg_gcc-path          : Location of the rustc_codegen_gcc root folder (used
                              when ran from another directory)
     --no-default-features  : Add `--no-default-features` flag to cargo commands
diff --git a/build_system/src/info.rs b/build_system/src/info.rs
index ea38791d38c9a..bd891de2eb4c0 100644
--- a/build_system/src/info.rs
+++ b/build_system/src/info.rs
@@ -14,6 +14,8 @@ pub fn run() -> Result<(), String> {
     }
     config.no_download = true;
     config.setup_gcc_path()?;
-    println!("{}", config.gcc_path);
+    if let Some(gcc_path) = config.gcc_path {
+        println!("{}", gcc_path);
+    }
     Ok(())
 }
diff --git a/build_system/src/test.rs b/build_system/src/test.rs
index 7cc7336612c79..efd7b2b8df3a1 100644
--- a/build_system/src/test.rs
+++ b/build_system/src/test.rs
@@ -1255,8 +1255,11 @@ pub fn run() -> Result<(), String> {
 
     if !args.use_system_gcc {
         args.config_info.setup_gcc_path()?;
-        env.insert("LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
-        env.insert("LD_LIBRARY_PATH".to_string(), args.config_info.gcc_path.clone());
+        let gcc_path = args.config_info.gcc_path.clone().expect(
+            "The config module should have emitted an error if the GCC path wasn't provided",
+        );
+        env.insert("LIBRARY_PATH".to_string(), gcc_path.clone());
+        env.insert("LD_LIBRARY_PATH".to_string(), gcc_path);
     }
 
     build_if_no_backend(&env, &args)?;

From b8218f0d2bcca50dc0128393015207aa649587c0 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Fri, 24 Jan 2025 16:40:47 +0100
Subject: [PATCH 10/11] Add log to mention what GCC path the build script is
 using and where it comes from

---
 build_system/src/config.rs | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/build_system/src/config.rs b/build_system/src/config.rs
index e8eeb559c79de..843f87c8be6b8 100644
--- a/build_system/src/config.rs
+++ b/build_system/src/config.rs
@@ -284,7 +284,11 @@ impl ConfigInfo {
     pub fn setup_gcc_path(&mut self) -> Result<(), String> {
         // If the user used the `--gcc-path` option, no need to look at `config.toml` content
         // since we already have everything we need.
-        if self.gcc_path.is_some() {
+        if let Some(gcc_path) = &self.gcc_path {
+            println!(
+                "`--gcc-path` was provided, ignoring config file. Using `{}` as path for libgccjit",
+                gcc_path
+            );
             return Ok(());
         }
         let config_file = match self.config_file.as_deref() {
@@ -297,10 +301,15 @@ impl ConfigInfo {
             self.download_gccjit_if_needed()?;
             return Ok(());
         }
-        if gcc_path.is_none() {
+        let Some(gcc_path) = gcc_path else {
             return Err(format!("missing `gcc-path` value from `{}`", config_file.display()));
-        }
-        self.gcc_path = gcc_path;
+        };
+        println!(
+            "GCC path retrieved from `{}`. Using `{}` as path for libgccjit",
+            config_file.display(),
+            gcc_path
+        );
+        self.gcc_path = Some(gcc_path);
         Ok(())
     }
 

From 12e73aec910ba8ad6fc673cacf7d5138523c8d30 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Fri, 24 Jan 2025 22:42:42 +0100
Subject: [PATCH 11/11] Fix `--use-system-gcc` option handling

---
 build_system/src/config.rs | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/build_system/src/config.rs b/build_system/src/config.rs
index 0904ea871cd4a..4f9fcc9715140 100644
--- a/build_system/src/config.rs
+++ b/build_system/src/config.rs
@@ -320,12 +320,16 @@ impl ConfigInfo {
     ) -> Result<(), String> {
         env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string());
 
-        if self.gcc_path.is_none() && !use_system_gcc {
-            self.setup_gcc_path()?;
-        }
-        let gcc_path = self.gcc_path.clone().expect(
-            "The config module should have emitted an error if the GCC path wasn't provided",
-        );
+        let gcc_path = if !use_system_gcc {
+            if self.gcc_path.is_none() {
+                self.setup_gcc_path()?;
+            }
+            self.gcc_path.clone().expect(
+                "The config module should have emitted an error if the GCC path wasn't provided",
+            )
+        } else {
+            String::new()
+        };
         env.insert("GCC_PATH".to_string(), gcc_path.clone());
 
         if self.cargo_target_dir.is_empty() {