From 599f88d7717aca793e81c68e66f91b5b9be2d732 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Feb 2025 17:39:05 +0100 Subject: [PATCH 01/18] Add new setting to wrap source code lines when too long --- src/librustdoc/html/static/css/rustdoc.css | 107 +++++++++++++-------- src/librustdoc/html/static/js/main.js | 37 ++++--- src/librustdoc/html/static/js/settings.js | 13 +++ src/librustdoc/html/static/js/storage.js | 3 + 4 files changed, 99 insertions(+), 61 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4f5f8f92264c1..8e904c6200e6f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -41,6 +41,7 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ --font-family: "Source Serif 4", NanumBarunGothic, serif; --font-family-code: "Source Code Pro", monospace; --line-number-padding: 4px; + --line-number-right-margin: 20px; /* scraped examples icons (34x33px) */ --prev-arrow-image: url('data:image/svg+xml, .example-line-numbers, -.rustdoc .scraped-example .src-line-numbers, -.rustdoc .scraped-example .src-line-numbers > pre { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.rustdoc .example-wrap > .example-line-numbers + pre, -.rustdoc .scraped-example .rust { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - .rustdoc .scraped-example { position: relative; } @@ -908,45 +893,31 @@ both the code example and the line numbers, so we need to remove the radius in t overflow: auto; } -.rustdoc .example-wrap pre.example-line-numbers, -.rustdoc .example-wrap .src-line-numbers { - min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */ - flex-grow: 0; - text-align: right; - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; - padding: 14px 8px; - padding-right: 2px; - color: var(--src-line-numbers-span-color); -} - -.example-wrap.digits-1 [data-nosnippet] { +.example-wrap.digits-1:not(.hide-lines) [data-nosnippet] { width: calc(1ch + var(--line-number-padding) * 2); } -.example-wrap.digits-2 [data-nosnippet] { +.example-wrap.digits-2:not(.hide-lines) [data-nosnippet] { width: calc(2ch + var(--line-number-padding) * 2); } -.example-wrap.digits-3 [data-nosnippet] { +.example-wrap.digits-3:not(.hide-lines) [data-nosnippet] { width: calc(3ch + var(--line-number-padding) * 2); } -.example-wrap.digits-4 [data-nosnippet] { +.example-wrap.digits-4:not(.hide-lines) [data-nosnippet] { width: calc(4ch + var(--line-number-padding) * 2); } -.example-wrap.digits-5 [data-nosnippet] { +.example-wrap.digits-5:not(.hide-lines) [data-nosnippet] { width: calc(5ch + var(--line-number-padding) * 2); } -.example-wrap.digits-6 [data-nosnippet] { +.example-wrap.digits-6:not(.hide-lines) [data-nosnippet] { width: calc(6ch + var(--line-number-padding) * 2); } -.example-wrap.digits-7 [data-nosnippet] { +.example-wrap.digits-7:not(.hide-lines) [data-nosnippet] { width: calc(7ch + var(--line-number-padding) * 2); } -.example-wrap.digits-8 [data-nosnippet] { +.example-wrap.digits-8:not(.hide-lines) [data-nosnippet] { width: calc(8ch + var(--line-number-padding) * 2); } -.example-wrap.digits-9 [data-nosnippet] { +.example-wrap.digits-9:not(.hide-lines) [data-nosnippet] { width: calc(9ch + var(--line-number-padding) * 2); } @@ -954,12 +925,12 @@ both the code example and the line numbers, so we need to remove the radius in t color: var(--src-line-numbers-span-color); text-align: right; display: inline-block; - margin-right: 20px; + margin-right: var(--line-number-right-margin); -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; - padding: 0 4px; + padding: 0 var(--line-number-padding); } .example-wrap [data-nosnippet]:target { border-right: none; @@ -967,6 +938,60 @@ both the code example and the line numbers, so we need to remove the radius in t .example-wrap .line-highlighted[data-nosnippet] { background-color: var(--src-line-number-highlighted-background-color); } +:root.wrap-source-code .example-wrap [data-nosnippet] { + position: absolute; + left: 0; +} +.wrap-source-code .example-wrap pre > code { + position: relative; + word-break: break-all; +} +:root.wrap-source-code .example-wrap pre > code { + display: block; + white-space: pre-wrap; +} +:root.wrap-source-code .example-wrap pre > code * { + word-break: break-all; +} +:root.wrap-source-code .example-wrap.digits-1 pre > code { + padding-left: calc( + 1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-2 pre > code { + padding-left: calc( + 2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-3 pre > code { + padding-left: calc( + 3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-4 pre > code { + padding-left: calc( + 4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-5 pre > code { + padding-left: calc( + 5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-6 pre > code { + padding-left: calc( + 6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-7 pre > code { + padding-left: calc( + 7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-8 pre > code { + padding-left: calc( + 8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.wrap-source-code .example-wrap.digits-9 pre > code { + padding-left: calc( + 9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +.example-wrap.hide-lines [data-nosnippet] { + display: none; +} .search-loading { text-align: center; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index a348c6c5678b9..67cc48f4cb26e 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1112,35 +1112,32 @@ function preLoadCss(cssUrl) { // @ts-expect-error window.rustdoc_add_line_numbers_to_examples = () => { - if (document.querySelector(".rustdoc.src")) { - // We are in the source code page, nothing to be done here! - return; + // @ts-expect-error + function generateLine(nb) { + return `${nb}`; } + onEachLazy(document.querySelectorAll( - ":not(.scraped-example) > .example-wrap > pre:not(.example-line-numbers)", - ), x => { - const parent = x.parentNode; - const line_numbers = parent.querySelectorAll(".example-line-numbers"); - if (line_numbers.length > 0) { + ".rustdoc:not(.src) :not(.scraped-example) > .example-wrap > pre > code", + ), code => { + if (hasClass(code.parentElement.parentElement, "hide-lines")) { + removeClass(code.parentElement.parentElement, "hide-lines"); return; } - const count = x.textContent.split("\n").length; - const elems = []; - for (let i = 0; i < count; ++i) { - elems.push(i + 1); - } - const node = document.createElement("pre"); - addClass(node, "example-line-numbers"); - node.innerHTML = elems.join("\n"); - parent.insertBefore(node, x); + const lines = code.innerHTML.split("\n"); + const digits = (lines.length + "").length; + // @ts-expect-error + code.innerHTML = lines.map((line, index) => generateLine(index + 1) + line).join("\n"); + addClass(code.parentElement.parentElement, `digits-${digits}`); }); }; // @ts-expect-error window.rustdoc_remove_line_numbers_from_examples = () => { - onEachLazy(document.querySelectorAll(".example-wrap > .example-line-numbers"), x => { - x.parentNode.removeChild(x); - }); + onEachLazy( + document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"), + x => addClass(x, "hide-lines"), + ); }; if (getSettingValue("line-numbers") === "true") { diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index bf33e0f17e5fe..2cf6d6fde8f1a 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -59,6 +59,14 @@ } else { removeClass(document.documentElement, "sans-serif"); } + break; + case "wrap-source-code": + if (value === true) { + addClass(document.documentElement, "wrap-source-code"); + } else { + removeClass(document.documentElement, "wrap-source-code"); + } + break; } } @@ -246,6 +254,11 @@ "js_name": "sans-serif-fonts", "default": false, }, + { + "name": "Wrap source codes", + "js_name": "wrap-source-code", + "default": false, + }, ]; // Then we build the DOM. diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 3042373fb096f..4f70166848c34 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -286,6 +286,9 @@ if (getSettingValue("hide-modnav") === "true") { if (getSettingValue("sans-serif-fonts") === "true") { addClass(document.documentElement, "sans-serif"); } +if (getSettingValue("wrap-source-code") === "true") { + addClass(document.documentElement, "wrap-source-code"); +} function updateSidebarWidth() { const desktopSidebarWidth = getSettingValue("desktop-sidebar-width"); if (desktopSidebarWidth && desktopSidebarWidth !== "null") { From 10d666f3d6d42e5a65e295551ccff51ac9b0d91a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Feb 2025 22:44:30 +0100 Subject: [PATCH 02/18] Update rustdoc-gui test --- .../docblock-code-block-line-number.goml | 68 +++++-------------- 1 file changed, 16 insertions(+), 52 deletions(-) diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index 032746a6bdf44..97273ceb195fa 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -21,7 +21,7 @@ assert-css: ( set-local-storage: {"rustdoc-line-numbers": "true"} reload: // We wait for the line numbers to be added into the DOM by the JS... -wait-for: "pre.example-line-numbers" +wait-for: ".digits-1 pre" // Otherwise, we can't check text color show-text: true @@ -35,30 +35,21 @@ define-function: ( call-function: ("switch-theme", {"theme": |theme|}) // If the test didn't fail, it means that it was found! assert-css: ( - "pre.example-line-numbers", + ".digits-1 pre [data-nosnippet]", { "color": |color|, - "margin": "0px", - "padding-top": "14px", - "padding-bottom": "14px", - "padding-left": "8px", - "padding-right": "2px", + "margin-top": "0px", + "margin-bottom": "0px", + "margin-left": "0px", + "margin-right": "20px", + "padding-top": "0px", + "padding-bottom": "0px", + "padding-left": "4px", + "padding-right": "4px", "text-align": "right", - // There should not be a radius on the right of the line numbers. - "border-top-left-radius": "6px", - "border-bottom-left-radius": "6px", - "border-top-right-radius": "0px", - "border-bottom-right-radius": "0px", }, ALL, ) - // There should not be a radius on the left of the line numbers. - assert-css: ("pre.example-line-numbers + .rust", { - "border-top-left-radius": "0px", - "border-bottom-left-radius": "0px", - "border-top-right-radius": "6px", - "border-bottom-right-radius": "6px", - }) }, ) call-function: ("check-colors", { @@ -74,9 +65,6 @@ call-function: ("check-colors", { "color": "#c67e2d", }) -// The first code block has two lines so let's check its `
` elements lists both of them.
-assert-text: ("pre.example-line-numbers", "1\n2")
-
 // Now, try changing the setting dynamically. We'll turn it off, using the settings menu,
 // and make sure it goes away.
 
@@ -87,42 +75,17 @@ assert-css: ("#settings", {"display": "block"})
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for-false: "pre.example-line-numbers"
+wait-for: ".digits-1.hide-lines"
 assert-local-storage: {"rustdoc-line-numbers": "false" }
 
-// Check that the rounded corners are back.
-assert-css: (
-    ".example-wrap .rust",
-    {
-        "border-top-left-radius": "6px",
-        "border-bottom-left-radius": "6px",
-        "border-top-right-radius": "6px",
-        "border-bottom-right-radius": "6px",
-    },
-    ALL,
-)
-
 // Finally, turn it on again.
 click: "input#line-numbers"
-wait-for: "pre.example-line-numbers"
+wait-for: ".digits-1:not(.hide-lines)"
 assert-local-storage: {"rustdoc-line-numbers": "true" }
-wait-for: "pre.example-line-numbers"
 
 // Same check with scraped examples line numbers.
 go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
 
-assert-css: (
-    ".scraped-example .rust",
-    {
-        // There should not be a radius on the left of the code.
-        "border-top-left-radius": "0px",
-        "border-bottom-left-radius": "0px",
-        "border-top-right-radius": "6px",
-        "border-bottom-right-radius": "6px",
-    },
-    ALL,
-)
-
 define-function: (
     "check-padding",
     [path, padding_bottom],
@@ -203,17 +166,18 @@ assert-local-storage: {"rustdoc-line-numbers": "true" }
 assert: ".example-wrap > pre.language-txt"
 assert: ".example-wrap > pre.rust"
 assert-count: (".example-wrap", 2)
-assert-count: (".example-wrap > pre.example-line-numbers", 2)
+assert-count: (".example-wrap.digits-1", 2)
 
 click: "#settings-menu"
 wait-for: "#settings"
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for-count: (".example-wrap > pre.example-line-numbers", 0)
+wait-for-count: (".example-wrap.digits-1.hide-lines", 2)
 assert-local-storage-false: {"rustdoc-line-numbers": "true" }
 
 // Now turning off the setting.
 click: "input#line-numbers"
-wait-for-count: (".example-wrap > pre.example-line-numbers", 2)
+wait-for-count: (".example-wrap.digits-1", 2)
+wait-for-count: (".example-wrap.digits-1.hide-lines", 0)
 assert-local-storage: {"rustdoc-line-numbers": "true" }

From 38b5bfce24834457cb3f2f1ccb8ed7cd5c29144b Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Thu, 13 Feb 2025 23:03:34 +0100
Subject: [PATCH 03/18] Add GUI test for code wrapping

---
 tests/rustdoc-gui/source-code-wrapping.goml | 44 +++++++++++++++++++++
 tests/rustdoc-gui/src/test_docs/lib.rs      |  9 +++++
 2 files changed, 53 insertions(+)
 create mode 100644 tests/rustdoc-gui/source-code-wrapping.goml

diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml
new file mode 100644
index 0000000000000..6b70c4c3447c7
--- /dev/null
+++ b/tests/rustdoc-gui/source-code-wrapping.goml
@@ -0,0 +1,44 @@
+// Checks that the interactions with the source code pages are working as expected.
+go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+show-text: true
+
+define-function: (
+    "click-code-wrapping",
+    [expected],
+    block {
+        click: "#wrap-source-code"
+        wait-for-local-storage: {"rustdoc-wrap-source-code": |expected|}
+    },
+)
+
+store-size: (".rust code", {"width": width, "height": height})
+click: "#settings-menu"
+wait-for: "#settings"
+call-function: ("click-code-wrapping", {"expected": "true"})
+store-size: (".rust code", {"width": new_width, "height": new_height})
+// The width should now be smaller than the window's and the height
+// should have increased.
+assert: |width| > |new_width| && |height| < |new_height|
+
+// Switching back to the original setting.
+call-function: ("click-code-wrapping", {"expected": "false"})
+assert-size: (".rust code", {"width": |width|, "height": |height|})
+
+// Now let's check in docs code examples.
+go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html"
+click: "#settings-menu"
+wait-for: "#settings"
+
+store-size: (".example-wrap .rust code", {"width": rust_width, "height": rust_height})
+store-size: (".example-wrap .language-text code", {"width": txt_width, "height": txt_height})
+call-function: ("click-code-wrapping", {"expected": "true"})
+
+store-size: (".example-wrap .rust code", {"width": new_rust_width, "height": new_rust_height})
+store-size: (".example-wrap .language-text code", {"width": new_txt_width, "height": new_txt_height})
+
+assert: |rust_width| > |new_rust_width| && |rust_height| < |new_rust_height|
+assert: |txt_width| > |new_txt_width| && |txt_height| < |new_txt_height|
+
+call-function: ("click-code-wrapping", {"expected": "false"})
+assert-size: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
+assert-size: (".example-wrap .language-text code", {"width": |txt_width|, "height": |txt_height|})
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index 1a9ffbe889851..9cd28c1b4ffbe 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -615,6 +615,15 @@ pub mod private {
     }
 }
 
+/// ```
+/// fn super_long_function_name_because_i_need_to_hit_the_limit_and_break_beyond_it() {
+/// }
+/// ```
+///
+/// ```text
+/// fn super_long_function_name_because_i_need_to_hit_the_limit_and_break_beyond_it_v2() {
+/// }
+/// ```
 pub mod trait_bounds {
     pub trait OneBound: Sized {}
     pub trait TwoBounds: Sized + Copy {}

From e2b522505b367546da7af2cf24be762a4acfc41e Mon Sep 17 00:00:00 2001
From: "progressive.galib" 
Date: Sat, 15 Feb 2025 05:19:09 +0000
Subject: [PATCH 04/18] replaced the four occurrences of issue ="50547" in
 library/core/src/future/mod.rs with issue = "none"

---
 library/core/src/future/mod.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index e5a368796ec93..50c5fdc919d38 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -46,19 +46,19 @@ pub use self::join::join;
 /// It also simplifies the HIR lowering of `.await`.
 #[lang = "ResumeTy"]
 #[doc(hidden)]
-#[unstable(feature = "gen_future", issue = "50547")]
+#[unstable(feature = "gen_future", issue= "none")]
 #[derive(Debug, Copy, Clone)]
 pub struct ResumeTy(NonNull>);
 
-#[unstable(feature = "gen_future", issue = "50547")]
+#[unstable(feature = "gen_future", issue= "none")]
 unsafe impl Send for ResumeTy {}
 
-#[unstable(feature = "gen_future", issue = "50547")]
+#[unstable(feature = "gen_future", issue= "none")]
 unsafe impl Sync for ResumeTy {}
 
 #[lang = "get_context"]
 #[doc(hidden)]
-#[unstable(feature = "gen_future", issue = "50547")]
+#[unstable(feature = "gen_future", issue= "none")]
 #[must_use]
 #[inline]
 pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {

From e52534f7d8f634e60e7acc260f7fe2e751d1c786 Mon Sep 17 00:00:00 2001
From: progressive-galib <125106402+progressive-galib@users.noreply.github.com>
Date: Sat, 15 Feb 2025 13:34:01 +0600
Subject: [PATCH 05/18] tidying up tidy

---
 library/core/src/future/mod.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index 50c5fdc919d38..65c0171c88d5b 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -46,19 +46,19 @@ pub use self::join::join;
 /// It also simplifies the HIR lowering of `.await`.
 #[lang = "ResumeTy"]
 #[doc(hidden)]
-#[unstable(feature = "gen_future", issue= "none")]
+#[unstable(feature = "gen_future", issue = "none")]
 #[derive(Debug, Copy, Clone)]
 pub struct ResumeTy(NonNull>);
 
-#[unstable(feature = "gen_future", issue= "none")]
+#[unstable(feature = "gen_future", issue = "none")]
 unsafe impl Send for ResumeTy {}
 
-#[unstable(feature = "gen_future", issue= "none")]
+#[unstable(feature = "gen_future", issue = "none")]
 unsafe impl Sync for ResumeTy {}
 
 #[lang = "get_context"]
 #[doc(hidden)]
-#[unstable(feature = "gen_future", issue= "none")]
+#[unstable(feature = "gen_future", issue = "none")]
 #[must_use]
 #[inline]
 pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {

From a3f389745e1b07a7fe652a6f23ea5a99a1e6a0ca Mon Sep 17 00:00:00 2001
From: Connor Horman 
Date: Fri, 21 Feb 2025 16:58:37 +0000
Subject: [PATCH 06/18] Stabilize `unbounded_shifts`

---
 library/core/src/num/int_macros.rs         |   8 +-
 library/core/src/num/uint_macros.rs        |   8 +-
 library/coretests/tests/num/int_macros.rs  | 165 +++++++++++++++++++++
 library/coretests/tests/num/uint_macros.rs | 154 +++++++++++++++++++
 4 files changed, 327 insertions(+), 8 deletions(-)

diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 296b5ebdfafcc..5c921c2e845a0 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1306,11 +1306,11 @@ macro_rules! int_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1428,12 +1428,12 @@ macro_rules! int_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 74d3ae699f66f..380e622a38d3b 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1567,11 +1567,11 @@ macro_rules! uint_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1688,11 +1688,11 @@ macro_rules! uint_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs
index f13b836378b9e..b4e911ca55c92 100644
--- a/library/coretests/tests/num/int_macros.rs
+++ b/library/coretests/tests/num/int_macros.rs
@@ -478,5 +478,170 @@ macro_rules! int_module {
                 assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3);
             }
         }
+
+        const SHIFT_AMOUNT_OVERFLOW: $T = <$T>::BITS;
+        const SHIFT_AMOUNT_OVERFLOW2: $T = <$T>::BITS + 3;
+        const SHIFT_AMOUNT_OVERFLOW3: $T = <$T>::BITS << 2;
+
+
+        const SHIFT_AMOUNT_TEST_ONE: $T = <$T>::BITS >> 1;
+        const SHIFT_AMOUNT_TEST_TWO: $T = <$T>::BITS >> 3;
+        const SHIFT_AMOUNT_TEST_THREE: $T = (<$T>::BITS >> 1) - 1;
+        const SHIFT_AMOUNT_TEST_FOUR: $T = <$T>::BITS - 1;
+
+
+        test_runtime_and_compiletime! {
+            fn test_unbounded_shl() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // -1
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_ONE), (-1 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_TWO), (-1 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_THREE), (-1 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, 1), (-1 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, 3), (-1 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, 5), (-1 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+
+            fn test_unbounded_shr() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), -1);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // -1
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_ONE), (-1 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_TWO), (-1 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_THREE), (-1 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, 1), (-1 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, 3), (-1 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, 5), (-1 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW2), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW3), -1);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+        }
     };
 }
diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs
index 99a2d4cd462b1..fbe44e90e5e74 100644
--- a/library/coretests/tests/num/uint_macros.rs
+++ b/library/coretests/tests/num/uint_macros.rs
@@ -317,5 +317,159 @@ macro_rules! uint_module {
                 assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3);
             }
         }
+
+        test_runtime_and_compiletime! {
+            fn test_unbounded_shl() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // !0
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_ONE), (!0 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_TWO), (!0 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_THREE), (!0 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, 1), (!0 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, 3), (!0 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, 5), (!0 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+
+            fn test_unbounded_shr() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // !0
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_ONE), (!0 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_TWO), (!0 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_THREE), (!0 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, 1), (!0 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, 3), (!0 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, 5), (!0 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+        }
     };
 }

From f1c21c9fc6211576c422d5cd6bf7e07182235883 Mon Sep 17 00:00:00 2001
From: Connor Horman 
Date: Fri, 21 Feb 2025 18:13:30 +0000
Subject: [PATCH 07/18] Fix unbounded_shifts tests

---
 library/coretests/tests/num/int_macros.rs  | 21 ++++++++++-----------
 library/coretests/tests/num/uint_macros.rs | 14 ++++++++++++--
 2 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs
index b4e911ca55c92..ed0aaa4dc5b23 100644
--- a/library/coretests/tests/num/int_macros.rs
+++ b/library/coretests/tests/num/int_macros.rs
@@ -479,16 +479,15 @@ macro_rules! int_module {
             }
         }
 
-        const SHIFT_AMOUNT_OVERFLOW: $T = <$T>::BITS;
-        const SHIFT_AMOUNT_OVERFLOW2: $T = <$T>::BITS + 3;
-        const SHIFT_AMOUNT_OVERFLOW3: $T = <$T>::BITS << 2;
-
-
-        const SHIFT_AMOUNT_TEST_ONE: $T = <$T>::BITS >> 1;
-        const SHIFT_AMOUNT_TEST_TWO: $T = <$T>::BITS >> 3;
-        const SHIFT_AMOUNT_TEST_THREE: $T = (<$T>::BITS >> 1) - 1;
-        const SHIFT_AMOUNT_TEST_FOUR: $T = <$T>::BITS - 1;
+        // test_unbounded_sh* constants
+        const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS;
+        const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3;
+        const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2;
 
+        const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1;
+        const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3;
+        const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1;
+        const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1;
 
         test_runtime_and_compiletime! {
             fn test_unbounded_shl() {
@@ -496,7 +495,7 @@ macro_rules! int_module {
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE));
-                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5));
@@ -572,7 +571,7 @@ macro_rules! int_module {
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE));
-                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5));
diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs
index fbe44e90e5e74..6ef83765d0110 100644
--- a/library/coretests/tests/num/uint_macros.rs
+++ b/library/coretests/tests/num/uint_macros.rs
@@ -318,13 +318,23 @@ macro_rules! uint_module {
             }
         }
 
+        // test_unbounded_sh* constants
+        const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS;
+        const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3;
+        const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2;
+
+        const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1;
+        const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3;
+        const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1;
+        const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1;
+
         test_runtime_and_compiletime! {
             fn test_unbounded_shl() {
                 // <$T>::MIN
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE));
-                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3));
                 assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5));
@@ -400,7 +410,7 @@ macro_rules! uint_module {
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE));
-                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUN_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUN_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3));
                 assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5));

From 6041d18de5d8f93f8b5907db4552d02d594c17fd Mon Sep 17 00:00:00 2001
From: Jason Newcomb 
Date: Fri, 21 Feb 2025 15:59:47 -0500
Subject: [PATCH 08/18] Some cleanup of index types in `rustc_hir_typeck`

---
 .../src/fn_ctxt/arg_matrix.rs                 |  6 ++++
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 36 +++++++++----------
 2 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index 358bc389bd138..f6298adf2ebb7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
@@ -22,6 +22,12 @@ impl ExpectedIdx {
     }
 }
 
+impl ProvidedIdx {
+    pub(crate) fn to_expected_idx(self) -> ExpectedIdx {
+        ExpectedIdx::from_u32(self.as_u32())
+    }
+}
+
 // An issue that might be found in the compatibility matrix
 #[derive(Debug)]
 enum Issue {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index e90474cabb420..29ee120a67518 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -773,7 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // First, check if we just need to wrap some arguments in a tuple.
         if let Some((mismatch_idx, terr)) =
-            compatibility_diagonal.iter().enumerate().find_map(|(i, c)| {
+            compatibility_diagonal.iter_enumerated().find_map(|(i, c)| {
                 if let Compatibility::Incompatible(Some(terr)) = c {
                     Some((i, *terr))
                 } else {
@@ -785,24 +785,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Do we have as many extra provided arguments as the tuple's length?
             // If so, we might have just forgotten to wrap some args in a tuple.
             if let Some(ty::Tuple(tys)) =
-                formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
+                formal_and_expected_inputs.get(mismatch_idx.to_expected_idx()).map(|tys| tys.1.kind())
                 // If the tuple is unit, we're not actually wrapping any arguments.
                 && !tys.is_empty()
                 && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
             {
                 // Wrap up the N provided arguments starting at this position in a tuple.
-                let provided_as_tuple = Ty::new_tup_from_iter(
-                    tcx,
-                    provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
-                );
+                let provided_args_to_tuple = &provided_arg_tys.raw[mismatch_idx.idx()..];
+                let (provided_args_to_tuple, provided_args_after_tuple) =
+                    provided_args_to_tuple.split_at(tys.len());
+                let provided_as_tuple =
+                    Ty::new_tup_from_iter(tcx, provided_args_to_tuple.iter().map(|&(ty, _)| ty));
 
                 let mut satisfied = true;
                 // Check if the newly wrapped tuple + rest of the arguments are compatible.
                 for ((_, expected_ty), provided_ty) in std::iter::zip(
-                    formal_and_expected_inputs.iter().skip(mismatch_idx),
-                    [provided_as_tuple].into_iter().chain(
-                        provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
-                    ),
+                    formal_and_expected_inputs[mismatch_idx.to_expected_idx()..].iter(),
+                    [provided_as_tuple]
+                        .into_iter()
+                        .chain(provided_args_after_tuple.iter().map(|&(ty, _)| ty)),
                 ) {
                     if !self.may_coerce(provided_ty, *expected_ty) {
                         satisfied = false;
@@ -814,10 +815,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Take some care with spans, so we don't suggest wrapping a macro's
                 // innards in parenthesis, for example.
                 if satisfied
-                    && let Some((_, lo)) =
-                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx))
-                    && let Some((_, hi)) =
-                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1))
+                    && let &[(_, hi @ lo)] | &[(_, lo), .., (_, hi)] = provided_args_to_tuple
                 {
                     let mut err;
                     if tys.len() == 1 {
@@ -825,9 +823,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // so don't do anything special here.
                         err = self.err_ctxt().report_and_explain_type_error(
                             mk_trace(
-                                *lo,
-                                formal_and_expected_inputs[mismatch_idx.into()],
-                                provided_arg_tys[mismatch_idx.into()].0,
+                                lo,
+                                formal_and_expected_inputs[mismatch_idx.to_expected_idx()],
+                                provided_arg_tys[mismatch_idx].0,
                             ),
                             self.param_env,
                             terr,
@@ -866,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         callee_ty,
                         call_expr,
                         None,
-                        Some(mismatch_idx),
+                        Some(mismatch_idx.as_usize()),
                         &matched_inputs,
                         &formal_and_expected_inputs,
                         is_method,
@@ -2648,7 +2646,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 let expected_display_type = self
-                    .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                    .resolve_vars_if_possible(formal_and_expected_inputs[idx].1)
                     .sort_string(self.tcx);
                 let label = if idxs_matched == params_with_generics.len() - 1 {
                     format!(

From a74f3fb5fc955fe3876fa206ce2146cd355e1bb5 Mon Sep 17 00:00:00 2001
From: Jason Newcomb 
Date: Fri, 21 Feb 2025 16:01:07 -0500
Subject: [PATCH 09/18] Iterate directly on block indices in
 `rustc_mir_transform`

---
 compiler/rustc_mir_transform/src/check_pointers.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs
index 72460542f8745..fffd59746622c 100644
--- a/compiler/rustc_mir_transform/src/check_pointers.rs
+++ b/compiler/rustc_mir_transform/src/check_pointers.rs
@@ -70,8 +70,7 @@ pub(crate) fn check_pointers<'a, 'tcx, F>(
     // statements/blocks after. Iterating or visiting the MIR in order would require updating
     // our current location after every insertion. By iterating backwards, we dodge this issue:
     // The only Locations that an insertion changes have already been handled.
-    for block in (0..basic_blocks.len()).rev() {
-        let block = block.into();
+    for block in basic_blocks.indices().rev() {
         for statement_index in (0..basic_blocks[block].statements.len()).rev() {
             let location = Location { block, statement_index };
             let statement = &basic_blocks[block].statements[statement_index];

From 162fb713ac66fef8f6a1d14bae9d1d4b35f76411 Mon Sep 17 00:00:00 2001
From: Jason Newcomb 
Date: Fri, 21 Feb 2025 16:01:19 -0500
Subject: [PATCH 10/18] Allow SliceIndex to be indexed by ranges.

---
 compiler/rustc_codegen_ssa/src/mir/mod.rs     |  4 +-
 .../src/sorted_map/index_map.rs               |  2 +-
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    |  2 +-
 compiler/rustc_index/src/idx.rs               | 91 +++++++++++++++++++
 compiler/rustc_index/src/lib.rs               |  3 +-
 compiler/rustc_index/src/slice.rs             | 33 ++++---
 .../src/infer/lexical_region_resolve/mod.rs   |  2 +-
 .../src/coverage/counters.rs                  |  2 +-
 .../rustc_mir_transform/src/coverage/graph.rs |  2 +-
 compiler/rustc_mir_transform/src/gvn.rs       |  2 +-
 10 files changed, 121 insertions(+), 22 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 3a896071bc6b8..3cbec337d6bf7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -3,7 +3,7 @@ use std::iter;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::{UnwindTerminateReason, traversal};
+use rustc_middle::mir::{Local, UnwindTerminateReason, traversal};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_middle::{bug, mir, span_bug};
@@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let local_values = {
         let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
 
-        let mut allocate_local = |local| {
+        let mut allocate_local = |local: Local| {
             let decl = &mir.local_decls[local];
             let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
             assert!(!layout.ty.has_erasable_regions());
diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
index e9a5fb5197548..278b3a9270c5c 100644
--- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
@@ -147,7 +147,7 @@ impl FromIterator<(K, V)> for SortedIndexMultiMap {
     where
         J: IntoIterator,
     {
-        let items = IndexVec::from_iter(iter);
+        let items = IndexVec::::from_iter(iter);
         let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect();
 
         // `sort_by_key` is stable, so insertion order is preserved for duplicate items.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 29ee120a67518..10185117b9cd8 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -791,7 +791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
             {
                 // Wrap up the N provided arguments starting at this position in a tuple.
-                let provided_args_to_tuple = &provided_arg_tys.raw[mismatch_idx.idx()..];
+                let provided_args_to_tuple = &provided_arg_tys[mismatch_idx..];
                 let (provided_args_to_tuple, provided_args_after_tuple) =
                     provided_args_to_tuple.split_at(tys.len());
                 let provided_as_tuple =
diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs
index b85160540d872..33f406e21137d 100644
--- a/compiler/rustc_index/src/idx.rs
+++ b/compiler/rustc_index/src/idx.rs
@@ -1,5 +1,7 @@
 use std::fmt::Debug;
 use std::hash::Hash;
+use std::ops;
+use std::slice::SliceIndex;
 
 /// Represents some newtyped `usize` wrapper.
 ///
@@ -43,3 +45,92 @@ impl Idx for u32 {
         self as usize
     }
 }
+
+/// Helper trait for indexing operations with a custom index type.
+pub trait IntoSliceIdx {
+    type Output: SliceIndex;
+    fn into_slice_idx(self) -> Self::Output;
+}
+
+impl IntoSliceIdx for I {
+    type Output = usize;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        self.index()
+    }
+}
+
+impl IntoSliceIdx for ops::RangeFull {
+    type Output = ops::RangeFull;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        self
+    }
+}
+
+impl IntoSliceIdx for ops::Range {
+    type Output = ops::Range;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ops::Range { start: self.start.index(), end: self.end.index() }
+    }
+}
+
+impl IntoSliceIdx for ops::RangeFrom {
+    type Output = ops::RangeFrom;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ops::RangeFrom { start: self.start.index() }
+    }
+}
+
+impl IntoSliceIdx for ops::RangeTo {
+    type Output = ops::RangeTo;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ..self.end.index()
+    }
+}
+
+impl IntoSliceIdx for ops::RangeInclusive {
+    type Output = ops::RangeInclusive;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ops::RangeInclusive::new(self.start().index(), self.end().index())
+    }
+}
+
+impl IntoSliceIdx for ops::RangeToInclusive {
+    type Output = ops::RangeToInclusive;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ..=self.end.index()
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl IntoSliceIdx for core::range::Range {
+    type Output = core::range::Range;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        core::range::Range { start: self.start.index(), end: self.end.index() }
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl IntoSliceIdx for core::range::RangeFrom {
+    type Output = core::range::RangeFrom;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        core::range::RangeFrom { start: self.start.index() }
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl IntoSliceIdx for core::range::RangeInclusive {
+    type Output = core::range::RangeInclusive;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        core::range::RangeInclusive { start: self.start.index(), end: self.end.index() }
+    }
+}
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index cae55230b0679..3441a5f65c785 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -2,6 +2,7 @@
 #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
 #![cfg_attr(feature = "nightly", allow(internal_features))]
 #![cfg_attr(feature = "nightly", feature(extend_one, step_trait, test))]
+#![cfg_attr(feature = "nightly", feature(new_range_api))]
 #![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
@@ -14,7 +15,7 @@ mod idx;
 mod slice;
 mod vec;
 
-pub use idx::Idx;
+pub use idx::{Idx, IntoSliceIdx};
 pub use rustc_index_macros::newtype_index;
 pub use slice::IndexSlice;
 #[doc(no_inline)]
diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs
index 956d32c9a6943..cc8080ee69753 100644
--- a/compiler/rustc_index/src/slice.rs
+++ b/compiler/rustc_index/src/slice.rs
@@ -1,8 +1,9 @@
+use std::fmt;
 use std::marker::PhantomData;
 use std::ops::{Index, IndexMut};
-use std::{fmt, slice};
+use std::slice::{self, SliceIndex};
 
-use crate::{Idx, IndexVec};
+use crate::{Idx, IndexVec, IntoSliceIdx};
 
 /// A view into contiguous `T`s, indexed by `I` rather than by `usize`.
 ///
@@ -99,13 +100,19 @@ impl IndexSlice {
     }
 
     #[inline]
-    pub fn get(&self, index: I) -> Option<&T> {
-        self.raw.get(index.index())
+    pub fn get>(
+        &self,
+        index: R,
+    ) -> Option<&>::Output> {
+        self.raw.get(index.into_slice_idx())
     }
 
     #[inline]
-    pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
-        self.raw.get_mut(index.index())
+    pub fn get_mut>(
+        &mut self,
+        index: R,
+    ) -> Option<&mut >::Output> {
+        self.raw.get_mut(index.into_slice_idx())
     }
 
     /// Returns mutable references to two distinct elements, `a` and `b`.
@@ -186,19 +193,19 @@ impl fmt::Debug for IndexSlice {
     }
 }
 
-impl Index for IndexSlice {
-    type Output = T;
+impl> Index for IndexSlice {
+    type Output = >::Output;
 
     #[inline]
-    fn index(&self, index: I) -> &T {
-        &self.raw[index.index()]
+    fn index(&self, index: R) -> &Self::Output {
+        &self.raw[index.into_slice_idx()]
     }
 }
 
-impl IndexMut for IndexSlice {
+impl> IndexMut for IndexSlice {
     #[inline]
-    fn index_mut(&mut self, index: I) -> &mut T {
-        &mut self.raw[index.index()]
+    fn index_mut(&mut self, index: R) -> &mut Self::Output {
+        &mut self.raw[index.into_slice_idx()]
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index e454a88e847fd..03c4614af139b 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -160,7 +160,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     /// empty region. The `expansion` phase will grow this larger.
     fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> {
         LexicalRegionResolutions {
-            values: IndexVec::from_fn_n(
+            values: IndexVec::::from_fn_n(
                 |vid| {
                     let vid_universe = self.var_infos[vid].universe;
                     VarValue::Empty(vid_universe)
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index adb99a75a9e47..fddcd341a9974 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -47,7 +47,7 @@ fn make_node_flow_priority_list(
     // A "reloop" node has exactly one out-edge, which jumps back to the top
     // of an enclosing loop. Reloop nodes are typically visited more times
     // than loop-exit nodes, so try to avoid giving them physical counters.
-    let is_reloop_node = IndexVec::from_fn_n(
+    let is_reloop_node = IndexVec::::from_fn_n(
         |node| match graph.successors[node].as_slice() {
             &[succ] => graph.dominates(succ, node),
             _ => false,
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 392b54c8d819b..d7db0140f3dd8 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -42,7 +42,7 @@ impl CoverageGraph {
         // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so
         // de-duplication is required. This is done without reordering the successors.
 
-        let successors = IndexVec::from_fn_n(
+        let successors = IndexVec::::from_fn_n(
             |bcb| {
                 let mut seen_bcbs = FxHashSet::default();
                 let terminator = mir_body[bcbs[bcb].last_bb()].terminator();
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index d2ffd26f0a06d..4128e8b09d022 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1259,7 +1259,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         let layout = self.ecx.layout_of(lhs_ty).ok()?;
 
-        let as_bits = |value| {
+        let as_bits = |value: VnIndex| {
             let constant = self.evaluated[value].as_ref()?;
             if layout.backend_repr.is_scalar() {
                 let scalar = self.ecx.read_scalar(constant).discard_err()?;

From a1471f3aa68ad97fc809e37c3c2c7b8b9e2ae227 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Sun, 16 Feb 2025 00:34:29 +0100
Subject: [PATCH 11/18] Rename feature into `Word wrap source code`

---
 src/librustdoc/html/static/css/rustdoc.css  | 26 ++++++++++-----------
 src/librustdoc/html/static/js/settings.js   | 10 ++++----
 src/librustdoc/html/static/js/storage.js    |  4 ++--
 tests/rustdoc-gui/source-code-wrapping.goml |  9 ++++---
 4 files changed, 26 insertions(+), 23 deletions(-)

diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 8e904c6200e6f..0ea4d8f1e3914 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -938,54 +938,54 @@ ul.block, .block li, .block ul {
 .example-wrap .line-highlighted[data-nosnippet] {
 	background-color: var(--src-line-number-highlighted-background-color);
 }
-:root.wrap-source-code .example-wrap [data-nosnippet] {
+:root.word-wrap-source-code .example-wrap [data-nosnippet] {
 	position: absolute;
 	left: 0;
 }
-.wrap-source-code .example-wrap pre > code {
+.word-wrap-source-code .example-wrap pre > code {
 	position: relative;
 	word-break: break-all;
 }
-:root.wrap-source-code .example-wrap pre > code {
+:root.word-wrap-source-code .example-wrap pre > code {
 	display: block;
 	white-space: pre-wrap;
 }
-:root.wrap-source-code .example-wrap pre > code * {
+:root.word-wrap-source-code .example-wrap pre > code * {
 	word-break: break-all;
 }
-:root.wrap-source-code .example-wrap.digits-1 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-1 pre > code {
 	padding-left: calc(
 		1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-2 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-2 pre > code {
 	padding-left: calc(
 		2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-3 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-3 pre > code {
 	padding-left: calc(
 		3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-4 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-4 pre > code {
 	padding-left: calc(
 		4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-5 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-5 pre > code {
 	padding-left: calc(
 		5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-6 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-6 pre > code {
 	padding-left: calc(
 		6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-7 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-7 pre > code {
 	padding-left: calc(
 		7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-8 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-8 pre > code {
 	padding-left: calc(
 		8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
-:root.wrap-source-code .example-wrap.digits-9 pre > code {
+:root.word-wrap-source-code .example-wrap.digits-9 pre > code {
 	padding-left: calc(
 		9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
 }
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 2cf6d6fde8f1a..5f1bbd27328cb 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -60,11 +60,11 @@
                     removeClass(document.documentElement, "sans-serif");
                 }
                 break;
-            case "wrap-source-code":
+            case "word-wrap-source-code":
                 if (value === true) {
-                    addClass(document.documentElement, "wrap-source-code");
+                    addClass(document.documentElement, "word-wrap-source-code");
                 } else {
-                    removeClass(document.documentElement, "wrap-source-code");
+                    removeClass(document.documentElement, "word-wrap-source-code");
                 }
                 break;
         }
@@ -255,8 +255,8 @@
                 "default": false,
             },
             {
-                "name": "Wrap source codes",
-                "js_name": "wrap-source-code",
+                "name": "Word wrap source code",
+                "js_name": "word-wrap-source-code",
                 "default": false,
             },
         ];
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 4f70166848c34..425b915b5f94e 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -286,8 +286,8 @@ if (getSettingValue("hide-modnav") === "true") {
 if (getSettingValue("sans-serif-fonts") === "true") {
     addClass(document.documentElement, "sans-serif");
 }
-if (getSettingValue("wrap-source-code") === "true") {
-    addClass(document.documentElement, "wrap-source-code");
+if (getSettingValue("word-wrap-source-code") === "true") {
+    addClass(document.documentElement, "word-wrap-source-code");
 }
 function updateSidebarWidth() {
     const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml
index 6b70c4c3447c7..cb2fd3052cdac 100644
--- a/tests/rustdoc-gui/source-code-wrapping.goml
+++ b/tests/rustdoc-gui/source-code-wrapping.goml
@@ -1,13 +1,14 @@
 // Checks that the interactions with the source code pages are working as expected.
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 show-text: true
+set-window-size: (1000, 1000)
 
 define-function: (
     "click-code-wrapping",
     [expected],
     block {
-        click: "#wrap-source-code"
-        wait-for-local-storage: {"rustdoc-wrap-source-code": |expected|}
+        click: "#word-wrap-source-code"
+        wait-for-local-storage: {"rustdoc-word-wrap-source-code": |expected|}
     },
 )
 
@@ -15,6 +16,7 @@ store-size: (".rust code", {"width": width, "height": height})
 click: "#settings-menu"
 wait-for: "#settings"
 call-function: ("click-code-wrapping", {"expected": "true"})
+wait-for-size-false: (".rust code", {"width": |width|, "height": |height|})
 store-size: (".rust code", {"width": new_width, "height": new_height})
 // The width should now be smaller than the window's and the height
 // should have increased.
@@ -32,6 +34,7 @@ wait-for: "#settings"
 store-size: (".example-wrap .rust code", {"width": rust_width, "height": rust_height})
 store-size: (".example-wrap .language-text code", {"width": txt_width, "height": txt_height})
 call-function: ("click-code-wrapping", {"expected": "true"})
+wait-for-size-false: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
 
 store-size: (".example-wrap .rust code", {"width": new_rust_width, "height": new_rust_height})
 store-size: (".example-wrap .language-text code", {"width": new_txt_width, "height": new_txt_height})
@@ -40,5 +43,5 @@ assert: |rust_width| > |new_rust_width| && |rust_height| < |new_rust_height|
 assert: |txt_width| > |new_txt_width| && |txt_height| < |new_txt_height|
 
 call-function: ("click-code-wrapping", {"expected": "false"})
-assert-size: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
+wait-for-size: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
 assert-size: (".example-wrap .language-text code", {"width": |txt_width|, "height": |txt_height|})

From 87c03807994b3767b9dc806df730ca2491d4cf94 Mon Sep 17 00:00:00 2001
From: Dennis Duda 
Date: Sun, 23 Feb 2025 14:19:58 +0100
Subject: [PATCH 12/18] Win: use existing wrappers for
 `SetFileInformationByHandle` in `File::open_native`

---
 library/std/src/sys/pal/windows/fs.rs | 36 ++++++++-------------------
 1 file changed, 11 insertions(+), 25 deletions(-)

diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index 0ddce30cf8e44..dce5a429cb0d4 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -1,4 +1,4 @@
-use super::api::{self, WinError};
+use super::api::{self, WinError, set_file_information_by_handle};
 use super::{IoResult, to_u16s};
 use crate::alloc::{alloc, handle_alloc_error};
 use crate::borrow::Cow;
@@ -319,31 +319,17 @@ impl File {
                 && creation == c::OPEN_ALWAYS
                 && api::get_last_error() == WinError::ALREADY_EXISTS
             {
-                unsafe {
-                    // This first tries `FileAllocationInfo` but falls back to
-                    // `FileEndOfFileInfo` in order to support WINE.
-                    // If WINE gains support for FileAllocationInfo, we should
-                    // remove the fallback.
-                    let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 };
-                    let result = c::SetFileInformationByHandle(
-                        handle.as_raw_handle(),
-                        c::FileAllocationInfo,
-                        (&raw const alloc).cast::(),
-                        mem::size_of::() as u32,
-                    );
-                    if result == 0 {
+                // This first tries `FileAllocationInfo` but falls back to
+                // `FileEndOfFileInfo` in order to support WINE.
+                // If WINE gains support for FileAllocationInfo, we should
+                // remove the fallback.
+                let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 };
+                set_file_information_by_handle(handle.as_raw_handle(), &alloc)
+                    .or_else(|_| {
                         let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 };
-                        let result = c::SetFileInformationByHandle(
-                            handle.as_raw_handle(),
-                            c::FileEndOfFileInfo,
-                            (&raw const eof).cast::(),
-                            mem::size_of::() as u32,
-                        );
-                        if result == 0 {
-                            return Err(io::Error::last_os_error());
-                        }
-                    }
-                }
+                        set_file_information_by_handle(handle.as_raw_handle(), &eof)
+                    })
+                    .io_result()?;
             }
             Ok(File { handle: Handle::from_inner(handle) })
         } else {

From 1a440d56d63458e4491f289c4950396f73304264 Mon Sep 17 00:00:00 2001
From: yukang 
Date: Sun, 23 Feb 2025 22:29:53 +0800
Subject: [PATCH 13/18] Fix documentation for unstable sort

---
 library/core/src/slice/mod.rs | 48 ++++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 7b9a76e814a15..c8f723dd0c1e4 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2928,10 +2928,17 @@ impl [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting
-    /// order of elements in the slice is unspecified. All original elements will remain in the
-    /// slice and any possible modifications via interior mutability are observed in the input. Same
-    /// is true if the implementation of [`Ord`] for `T` panics.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
+    ///
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
+    ///
+    ///
+    /// All original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics.
     ///
     /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require
     /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the
@@ -2954,7 +2961,8 @@ impl [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if
+    /// the [`Ord`] implementation panics.
     ///
     /// # Examples
     ///
@@ -2982,15 +2990,17 @@ impl [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If the comparison function `compare` does not implement a [total order] the resulting order
-    /// of elements in the slice is unspecified. All original elements will remain in the slice and
-    /// any possible modifications via interior mutability are observed in the input. Same is true
-    /// if `compare` panics.
+    /// If the comparison function `compare` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
     /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
     /// examples see the [`Ord`] documentation.
     ///
+    /// All original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. Same is true if `compare` panics.
+    ///
     /// # Current implementation
     ///
     /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which
@@ -3003,7 +3013,8 @@ impl [T] {
     ///
     /// # Panics
     ///
-    /// May panic if `compare` does not implement a [total order].
+    /// May panic if the `compare` does not implement a [total order], or if
+    /// the `compare` itself panics.
     ///
     /// # Examples
     ///
@@ -3034,10 +3045,16 @@ impl [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
-    /// order of elements in the slice is unspecified. All original elements will remain in the
-    /// slice and any possible modifications via interior mutability are observed in the input. Same
-    /// is true if the implementation of [`Ord`] for `K` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
+    ///
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
+    ///
+    /// All original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// # Current implementation
     ///
@@ -3051,7 +3068,8 @@ impl [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if
+    /// the [`Ord`] implementation panics.
     ///
     /// # Examples
     ///

From e15ce94eae9e6d085b64cb0d9226c3548494aee9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <39484203+jieyouxu@users.noreply.github.com>
Date: Mon, 24 Feb 2025 01:12:55 +0800
Subject: [PATCH 14/18] tests: tighten `CHECK-NOT`s to make
 `str-to-string-128690.rs` less likely to collide with symbol name mangling

---
 tests/codegen/issues/str-to-string-128690.rs | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/tests/codegen/issues/str-to-string-128690.rs b/tests/codegen/issues/str-to-string-128690.rs
index 8b416306ba66e..d9e69764be28e 100644
--- a/tests/codegen/issues/str-to-string-128690.rs
+++ b/tests/codegen/issues/str-to-string-128690.rs
@@ -2,25 +2,27 @@
 #![crate_type = "lib"]
 
 //! Make sure str::to_string is specialized not to use fmt machinery.
+//!
+//! Note that the `CHECK-NOT`s here try to match on calls to functions under `core::fmt`.
 
 // CHECK-LABEL: define {{(dso_local )?}}void @one_ref
 #[no_mangle]
 pub fn one_ref(input: &str) -> String {
-    // CHECK-NOT: {{(call|invoke).*}}fmt
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }
 
 // CHECK-LABEL: define {{(dso_local )?}}void @two_ref
 #[no_mangle]
 pub fn two_ref(input: &&str) -> String {
-    // CHECK-NOT: {{(call|invoke).*}}fmt
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }
 
 // CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref
 #[no_mangle]
 pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
-    // CHECK-NOT: {{(call|invoke).*}}fmt
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }
 
@@ -31,6 +33,6 @@ pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
 // CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref
 #[no_mangle]
 pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String {
-    // CHECK: {{(call|invoke).*}}fmt
+    // CHECK: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }

From 1eddb158f9f804a9ca843d5ccce70c341340c9d2 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Mon, 24 Feb 2025 09:16:10 +1100
Subject: [PATCH 15/18] Move `impl` blocks out of
 `rustc_middle/src/mir/syntax.rs`.

As the comment at the top says, this file is not supposed to contain any
code. But some has crept in. This commit moves it out.
---
 compiler/rustc_middle/src/mir/mod.rs        |  11 ++
 compiler/rustc_middle/src/mir/statement.rs  |  57 ++++++++++
 compiler/rustc_middle/src/mir/syntax.rs     | 112 --------------------
 compiler/rustc_middle/src/mir/terminator.rs |  38 +++++++
 4 files changed, 106 insertions(+), 112 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index cf90df1b198b8..ea0bb5feb1220 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -96,6 +96,17 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
 }
 
 impl MirPhase {
+    pub fn name(&self) -> &'static str {
+        match *self {
+            MirPhase::Built => "built",
+            MirPhase::Analysis(AnalysisPhase::Initial) => "analysis",
+            MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup",
+            MirPhase::Runtime(RuntimePhase::Initial) => "runtime",
+            MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup",
+            MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized",
+        }
+    }
+
     /// Gets the (dialect, phase) index of the current `MirPhase`. Both numbers
     /// are 1-indexed.
     pub fn index(&self) -> (usize, usize) {
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 595a5e548b011..f05a798949b7e 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -25,6 +25,26 @@ impl Statement<'_> {
 }
 
 impl<'tcx> StatementKind<'tcx> {
+    /// Returns a simple string representation of a `StatementKind` variant, independent of any
+    /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`).
+    pub const fn name(&self) -> &'static str {
+        match self {
+            StatementKind::Assign(..) => "Assign",
+            StatementKind::FakeRead(..) => "FakeRead",
+            StatementKind::SetDiscriminant { .. } => "SetDiscriminant",
+            StatementKind::Deinit(..) => "Deinit",
+            StatementKind::StorageLive(..) => "StorageLive",
+            StatementKind::StorageDead(..) => "StorageDead",
+            StatementKind::Retag(..) => "Retag",
+            StatementKind::PlaceMention(..) => "PlaceMention",
+            StatementKind::AscribeUserType(..) => "AscribeUserType",
+            StatementKind::Coverage(..) => "Coverage",
+            StatementKind::Intrinsic(..) => "Intrinsic",
+            StatementKind::ConstEvalCounter => "ConstEvalCounter",
+            StatementKind::Nop => "Nop",
+            StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint",
+        }
+    }
     pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> {
         match self {
             StatementKind::Assign(x) => Some(x),
@@ -862,3 +882,40 @@ impl<'tcx> BinOp {
         })
     }
 }
+
+impl From for RawPtrKind {
+    fn from(other: Mutability) -> Self {
+        match other {
+            Mutability::Mut => RawPtrKind::Mut,
+            Mutability::Not => RawPtrKind::Const,
+        }
+    }
+}
+
+impl RawPtrKind {
+    pub fn is_fake(self) -> bool {
+        match self {
+            RawPtrKind::Mut | RawPtrKind::Const => false,
+            RawPtrKind::FakeForPtrMetadata => true,
+        }
+    }
+
+    pub fn to_mutbl_lossy(self) -> Mutability {
+        match self {
+            RawPtrKind::Mut => Mutability::Mut,
+            RawPtrKind::Const => Mutability::Not,
+
+            // We have no type corresponding to a fake borrow, so use
+            // `*const` as an approximation.
+            RawPtrKind::FakeForPtrMetadata => Mutability::Not,
+        }
+    }
+
+    pub fn ptr_str(self) -> &'static str {
+        match self {
+            RawPtrKind::Mut => "mut",
+            RawPtrKind::Const => "const",
+            RawPtrKind::FakeForPtrMetadata => "const (fake)",
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index af6f0e4c55183..4f86703e95376 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -97,19 +97,6 @@ pub enum MirPhase {
     Runtime(RuntimePhase),
 }
 
-impl MirPhase {
-    pub fn name(&self) -> &'static str {
-        match *self {
-            MirPhase::Built => "built",
-            MirPhase::Analysis(AnalysisPhase::Initial) => "analysis",
-            MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup",
-            MirPhase::Runtime(RuntimePhase::Initial) => "runtime",
-            MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup",
-            MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized",
-        }
-    }
-}
-
 /// See [`MirPhase::Analysis`].
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(HashStable)]
@@ -206,43 +193,6 @@ pub enum RawPtrKind {
     FakeForPtrMetadata,
 }
 
-impl From for RawPtrKind {
-    fn from(other: Mutability) -> Self {
-        match other {
-            Mutability::Mut => RawPtrKind::Mut,
-            Mutability::Not => RawPtrKind::Const,
-        }
-    }
-}
-
-impl RawPtrKind {
-    pub fn is_fake(self) -> bool {
-        match self {
-            RawPtrKind::Mut | RawPtrKind::Const => false,
-            RawPtrKind::FakeForPtrMetadata => true,
-        }
-    }
-
-    pub fn to_mutbl_lossy(self) -> Mutability {
-        match self {
-            RawPtrKind::Mut => Mutability::Mut,
-            RawPtrKind::Const => Mutability::Not,
-
-            // We have no type corresponding to a fake borrow, so use
-            // `*const` as an approximation.
-            RawPtrKind::FakeForPtrMetadata => Mutability::Not,
-        }
-    }
-
-    pub fn ptr_str(self) -> &'static str {
-        match self {
-            RawPtrKind::Mut => "mut",
-            RawPtrKind::Const => "const",
-            RawPtrKind::FakeForPtrMetadata => "const (fake)",
-        }
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(Hash, HashStable)]
 pub enum MutBorrowKind {
@@ -515,29 +465,6 @@ pub enum StatementKind<'tcx> {
     },
 }
 
-impl StatementKind<'_> {
-    /// Returns a simple string representation of a `StatementKind` variant, independent of any
-    /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`).
-    pub const fn name(&self) -> &'static str {
-        match self {
-            StatementKind::Assign(..) => "Assign",
-            StatementKind::FakeRead(..) => "FakeRead",
-            StatementKind::SetDiscriminant { .. } => "SetDiscriminant",
-            StatementKind::Deinit(..) => "Deinit",
-            StatementKind::StorageLive(..) => "StorageLive",
-            StatementKind::StorageDead(..) => "StorageDead",
-            StatementKind::Retag(..) => "Retag",
-            StatementKind::PlaceMention(..) => "PlaceMention",
-            StatementKind::AscribeUserType(..) => "AscribeUserType",
-            StatementKind::Coverage(..) => "Coverage",
-            StatementKind::Intrinsic(..) => "Intrinsic",
-            StatementKind::ConstEvalCounter => "ConstEvalCounter",
-            StatementKind::Nop => "Nop",
-            StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint",
-        }
-    }
-}
-
 #[derive(
     Clone,
     TyEncodable,
@@ -673,12 +600,6 @@ pub enum CallSource {
     Normal,
 }
 
-impl CallSource {
-    pub fn from_hir_call(self) -> bool {
-        matches!(self, CallSource::Normal)
-    }
-}
-
 #[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 #[derive(TypeFoldable, TypeVisitable)]
 /// The macro that an inline assembly block was created by
@@ -689,15 +610,6 @@ pub enum InlineAsmMacro {
     NakedAsm,
 }
 
-impl InlineAsmMacro {
-    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
-        match self {
-            InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
-            InlineAsmMacro::NakedAsm => true,
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Terminators
 
@@ -999,30 +911,6 @@ pub enum BackwardIncompatibleDropReason {
     Edition2024,
 }
 
-impl TerminatorKind<'_> {
-    /// Returns a simple string representation of a `TerminatorKind` variant, independent of any
-    /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`).
-    pub const fn name(&self) -> &'static str {
-        match self {
-            TerminatorKind::Goto { .. } => "Goto",
-            TerminatorKind::SwitchInt { .. } => "SwitchInt",
-            TerminatorKind::UnwindResume => "UnwindResume",
-            TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
-            TerminatorKind::Return => "Return",
-            TerminatorKind::Unreachable => "Unreachable",
-            TerminatorKind::Drop { .. } => "Drop",
-            TerminatorKind::Call { .. } => "Call",
-            TerminatorKind::TailCall { .. } => "TailCall",
-            TerminatorKind::Assert { .. } => "Assert",
-            TerminatorKind::Yield { .. } => "Yield",
-            TerminatorKind::CoroutineDrop => "CoroutineDrop",
-            TerminatorKind::FalseEdge { .. } => "FalseEdge",
-            TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
-            TerminatorKind::InlineAsm { .. } => "InlineAsm",
-        }
-    }
-}
-
 #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub struct SwitchTargets {
     /// Possible values. For each value, the location to branch to is found in
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index fdfcb128778a7..7d6795ee678c0 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -2,6 +2,7 @@
 
 use std::slice;
 
+use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::packed::Pu128;
 use rustc_hir::LangItem;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
@@ -414,6 +415,28 @@ impl<'tcx> Terminator<'tcx> {
 }
 
 impl<'tcx> TerminatorKind<'tcx> {
+    /// Returns a simple string representation of a `TerminatorKind` variant, independent of any
+    /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`).
+    pub const fn name(&self) -> &'static str {
+        match self {
+            TerminatorKind::Goto { .. } => "Goto",
+            TerminatorKind::SwitchInt { .. } => "SwitchInt",
+            TerminatorKind::UnwindResume => "UnwindResume",
+            TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
+            TerminatorKind::Return => "Return",
+            TerminatorKind::Unreachable => "Unreachable",
+            TerminatorKind::Drop { .. } => "Drop",
+            TerminatorKind::Call { .. } => "Call",
+            TerminatorKind::TailCall { .. } => "TailCall",
+            TerminatorKind::Assert { .. } => "Assert",
+            TerminatorKind::Yield { .. } => "Yield",
+            TerminatorKind::CoroutineDrop => "CoroutineDrop",
+            TerminatorKind::FalseEdge { .. } => "FalseEdge",
+            TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
+            TerminatorKind::InlineAsm { .. } => "InlineAsm",
+        }
+    }
+
     #[inline]
     pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
         TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
@@ -698,3 +721,18 @@ impl<'tcx> TerminatorKind<'tcx> {
         }
     }
 }
+
+impl CallSource {
+    pub fn from_hir_call(self) -> bool {
+        matches!(self, CallSource::Normal)
+    }
+}
+
+impl InlineAsmMacro {
+    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
+        match self {
+            InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
+            InlineAsmMacro::NakedAsm => true,
+        }
+    }
+}

From 4183c085116e36a2ee78a5b1f3d94892cefce7ba Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Mon, 24 Feb 2025 09:30:42 +1100
Subject: [PATCH 16/18] Fix some `use` items that import more than necessary.

---
 compiler/rustc_middle/src/mir/terminator.rs                | 2 +-
 compiler/rustc_middle/src/ty/mod.rs                        | 2 +-
 compiler/rustc_mir_build/src/builder/matches/match_pair.rs | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 7d6795ee678c0..b887370fd699a 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -8,7 +8,7 @@ use rustc_hir::LangItem;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use smallvec::{SmallVec, smallvec};
 
-use super::{TerminatorKind, *};
+use super::*;
 
 impl SwitchTargets {
     /// Creates switch targets from an iterator of values and target blocks.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8ed5a118093f3..dbbbdc606bbb4 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -47,7 +47,7 @@ pub use rustc_session::lint::RegisteredTools;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym};
 pub use rustc_type_ir::relate::VarianceDiagInfo;
-pub use rustc_type_ir::{Movability, Mutability, *};
+pub use rustc_type_ir::*;
 use tracing::{debug, instrument};
 pub use vtable::*;
 use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
index ee331713736e7..10b43390eb288 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -1,7 +1,7 @@
 use std::sync::Arc;
 
 use rustc_middle::mir::*;
-use rustc_middle::thir::{self, *};
+use rustc_middle::thir::*;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
 use crate::builder::Builder;
@@ -134,7 +134,7 @@ impl<'tcx> MatchPairTree<'tcx> {
             PatKind::Constant { value } => TestCase::Constant { value },
 
             PatKind::AscribeUserType {
-                ascription: thir::Ascription { ref annotation, variance },
+                ascription: Ascription { ref annotation, variance },
                 ref subpattern,
                 ..
             } => {

From f49b6c6cd58aa61c804dcb22cc013c728f8924af Mon Sep 17 00:00:00 2001
From: Madhav Madhusoodanan 
Date: Mon, 24 Feb 2025 00:36:25 +0530
Subject: [PATCH 17/18] Added into_value const function to ControlFlow

Fixed issue with usage of generics and moved feature gate to crate root

Removed const tag

Fixed alphabetical ordering of feature gate, added same to doctest

Removed crate-level declaration of feature gate control_flow_into_value

Used const_precise_live_drops to constify into_value without issue of a drop
---
 library/core/src/ops/control_flow.rs | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index c8fcee5c140f5..8993e14fcd379 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -229,6 +229,27 @@ impl ControlFlow {
     }
 }
 
+impl ControlFlow {
+    /// Extracts the value `T` that is wrapped by `ControlFlow`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(control_flow_into_value)]
+    /// use std::ops::ControlFlow;
+    ///
+    /// assert_eq!(ControlFlow::::Break(1024).into_value(), 1024);
+    /// assert_eq!(ControlFlow::::Continue(512).into_value(), 512);
+    /// ```
+    #[unstable(feature = "control_flow_into_value", issue = "137461")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    pub const fn into_value(self) -> T {
+        match self {
+            ControlFlow::Continue(x) | ControlFlow::Break(x) => x,
+        }
+    }
+}
+
 /// These are used only as part of implementing the iterator adapters.
 /// They have mediocre names and non-obvious semantics, so aren't
 /// currently on a path to potential stabilization.

From 7a2db88a569ca125516f3ac5e546952f1df0c0fa Mon Sep 17 00:00:00 2001
From: Trevor Gross 
Date: Mon, 24 Feb 2025 02:47:59 +0000
Subject: [PATCH 18/18] Add a span to `CompilerBuiltinsCannotCall`

Currently, this error emit a diagnostic with no context like:

    error: `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from ` as core::fmt::LowerHex>::fmt` to `core::fmt::num::::fmt`

With this change, it at least usually points to the problematic
function:

    error: `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from ` as core::fmt::LowerHex>::fmt` to `core::fmt::num::::fmt`
       --> src/../libm/src/math/support/hex_float.rs:270:5
        |
    270 |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        |
---
 compiler/rustc_codegen_cranelift/src/abi/mod.rs | 10 +++++++---
 compiler/rustc_codegen_ssa/src/errors.rs        |  2 ++
 compiler/rustc_codegen_ssa/src/mir/block.rs     | 10 +++++++---
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 756a2226753f6..e8076ce77abcf 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -402,9 +402,13 @@ pub(crate) fn codegen_terminator_call<'tcx>(
 
         if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
             if target.is_some() {
-                let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id()));
-                let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
-                fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
+                let caller_def = fx.instance.def_id();
+                let e = CompilerBuiltinsCannotCall {
+                    span: fx.tcx.def_span(caller_def),
+                    caller: with_no_trimmed_paths!(fx.tcx.def_path_str(caller_def)),
+                    callee: with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)),
+                };
+                fx.tcx.dcx().emit_err(e);
             } else {
                 fx.bcx.ins().trap(TrapCode::user(2).unwrap());
                 return;
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 3ddbe4aeeec5d..5e25de02a77f2 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1180,6 +1180,8 @@ pub(crate) struct ErrorCreatingRemarkDir {
 pub struct CompilerBuiltinsCannotCall {
     pub caller: String,
     pub callee: String,
+    #[primary_span]
+    pub span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 676a241c74b47..e351e7352e0c9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -165,9 +165,13 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         if let Some(instance) = instance {
             if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
                 if destination.is_some() {
-                    let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id()));
-                    let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id()));
-                    tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
+                    let caller_def = fx.instance.def_id();
+                    let e = CompilerBuiltinsCannotCall {
+                        span: tcx.def_span(caller_def),
+                        caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
+                        callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
+                    };
+                    tcx.dcx().emit_err(e);
                 } else {
                     info!(
                         "compiler_builtins call to diverging function {:?} replaced with abort",