From 21bdfa14cbd99aba173751a2c723fb1e65de401b Mon Sep 17 00:00:00 2001 From: Aurelia Molzer <5550310+HeroicKatora@users.noreply.github.com> Date: Sat, 9 Aug 2025 17:54:43 +0200 Subject: [PATCH 01/12] Ensure consistent drop for hint::select_unpredictable There are a few alternatives to the implementation. The principal problem is that the selected value must be owned (in the sense of having any drop flag of sorts) when the unselected value is dropped, such that panic unwind goes through the drop of both. This ownership must then be passed on in return when the drop went smoothly. The basic way of achieving this is by extracting the selected value first, at the cost of relying on the optimizer a little more for detecting the copy as constructing the return value despite having a place in the body. --- library/core/src/hint.rs | 6 +++++- library/coretests/tests/hint.rs | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index c72eeb9a9c976..53c17d6c887c3 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -790,8 +790,12 @@ pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T // is returned. This is necessary because the intrinsic doesn't drop the // value that is not selected. unsafe { + // Extract the selected value first, ensure it is dropped as well if dropping the unselected + // value panics. + let ret = crate::intrinsics::select_unpredictable(condition, &true_val, &false_val) + .assume_init_read(); crate::intrinsics::select_unpredictable(!condition, &mut true_val, &mut false_val) .assume_init_drop(); - crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init() + ret } } diff --git a/library/coretests/tests/hint.rs b/library/coretests/tests/hint.rs index 032bbc1dcc80f..9ef5567681e93 100644 --- a/library/coretests/tests/hint.rs +++ b/library/coretests/tests/hint.rs @@ -21,3 +21,40 @@ fn select_unpredictable_drop() { assert!(a_dropped.get()); assert!(b_dropped.get()); } + +#[test] +#[should_panic] +fn select_unpredictable_drop_on_panic() { + use core::cell::Cell; + + struct X<'a> { + cell: &'a Cell, + expect: u16, + write: u16, + } + + impl Drop for X<'_> { + fn drop(&mut self) { + let value = self.cell.get(); + self.cell.set(self.write); + assert_eq!(value, self.expect); + } + } + + let cell = Cell::new(0); + + // Trigger a double-panic if the selected cell was not dropped during panic. + let _armed = X { cell: &cell, expect: 0xdead, write: 0 }; + let selected = X { cell: &cell, write: 0xdead, expect: 1 }; + let unselected = X { cell: &cell, write: 1, expect: 0xff }; + + // The correct drop order is: + // + // 1. `unselected` drops, writes 1, and panics as 0 != 0xff + // 2. `selected` drops during unwind, writes 0xdead and does not panic as 1 == 1 + // 3. `armed` drops during unwind, writes 0 and does not panic as 0xdead == 0xdead + // + // If `selected` is not dropped, `armed` panics as 1 != 0xdead + let _unreachable = + core::hint::select_unpredictable(core::hint::black_box(true), selected, unselected); +} From 7d7fe3ff05c7c14834252e3345389e4dbf842cc5 Mon Sep 17 00:00:00 2001 From: Aurelia Molzer <5550310+HeroicKatora@users.noreply.github.com> Date: Sat, 9 Aug 2025 21:40:12 +0200 Subject: [PATCH 02/12] Adjust for codegen of unpredictable return value It seems important for LLVM that we select on the values by-value instead of reading and have no intermediate store. So make sure the guards selects both potential drops but defers the return value to the second selection. Since the two options alias we use raw mutable pointers instead of mutable references as before. --- library/core/src/hint.rs | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 53c17d6c887c3..1bb1c56950879 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -786,16 +786,42 @@ pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T // Change this to use ManuallyDrop instead. let mut true_val = MaybeUninit::new(true_val); let mut false_val = MaybeUninit::new(false_val); + + struct DropOnPanic { + inner: *mut MaybeUninit, + } + + impl Drop for DropOnPanic { + fn drop(&mut self) { + // SAFETY: Must be guaranteed on construction of local type `DropOnPanic`. + unsafe { (*self.inner).assume_init_drop() } + } + } + + let true_ptr = (&mut true_val) as *mut _; + let false_ptr = (&mut false_val) as *mut _; + // SAFETY: The value that is not selected is dropped, and the selected one // is returned. This is necessary because the intrinsic doesn't drop the // value that is not selected. unsafe { // Extract the selected value first, ensure it is dropped as well if dropping the unselected // value panics. - let ret = crate::intrinsics::select_unpredictable(condition, &true_val, &false_val) - .assume_init_read(); - crate::intrinsics::select_unpredictable(!condition, &mut true_val, &mut false_val) - .assume_init_drop(); - ret + let (guard, drop) = crate::intrinsics::select_unpredictable( + condition, + (true_ptr, false_ptr), + (false_ptr, true_ptr), + ); + + // SAFETY: both pointers are to valid `MaybeUninit`, in both variants they do not alias but + // the two arguments we have selected from did alias each other. + let guard = DropOnPanic { inner: guard }; + (*drop).assume_init_drop(); + crate::mem::forget(guard); + + // Note that it is important to use the values here. Reading from the pointer we got makes + // LLVM forget the !unpredictable annotation sometimes (in tests, integer sized values in + // particular seemed to confuse it, also observed in llvm/llvm-project #82340). + crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init() } } From fdbaaac245673d8dbf7bcc21ebedc833693434f6 Mon Sep 17 00:00:00 2001 From: Nilotpal Gupta Date: Tue, 19 Aug 2025 11:10:32 +0530 Subject: [PATCH 03/12] Fix format string grammar in docs and improve alignment error message --- compiler/rustc_parse_format/src/lib.rs | 4 +++- library/alloc/src/fmt.rs | 2 +- tests/ui/fmt/format-string-wrong-order.rs | 8 +++++--- tests/ui/fmt/format-string-wrong-order.stderr | 14 ++++++++++---- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 8e4da7923fcb5..5cda0b813d233 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -858,7 +858,9 @@ impl<'input> Parser<'input> { self.errors.insert( 0, ParseError { - description: "expected format parameter to occur after `:`".to_owned(), + description: + "expected alignment specifier after `:` in format string; example: `{:>?}`" + .to_owned(), note: None, label: format!("expected `{}` to occur after `:`", alignment), span: range, diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index d0ba9c398864f..82eaf7d87244d 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -354,7 +354,7 @@ //! sign := '+' | '-' //! width := count //! precision := count | '*' -//! type := '?' | 'x?' | 'X?' | identifier +//! type := '?' | 'x?' | 'X?' | 'o' | 'x' | 'X' | 'p' | 'b' | 'e' | 'E' //! count := parameter | integer //! parameter := argument '$' //! ``` diff --git a/tests/ui/fmt/format-string-wrong-order.rs b/tests/ui/fmt/format-string-wrong-order.rs index 891279b97e4d3..4d4e04ecd042d 100644 --- a/tests/ui/fmt/format-string-wrong-order.rs +++ b/tests/ui/fmt/format-string-wrong-order.rs @@ -13,9 +13,11 @@ fn main() { format!("{?:#?}", bar); //~^ ERROR invalid format string: expected format parameter to occur after `:` format!("Hello {<5:}!", "x"); - //~^ ERROR invalid format string: expected format parameter to occur after `:` + //~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` format!("Hello {^5:}!", "x"); - //~^ ERROR invalid format string: expected format parameter to occur after `:` + //~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` format!("Hello {>5:}!", "x"); - //~^ ERROR invalid format string: expected format parameter to occur after `:` + //~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` + println!("{0:#X>18}", 12345); + //~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` } diff --git a/tests/ui/fmt/format-string-wrong-order.stderr b/tests/ui/fmt/format-string-wrong-order.stderr index 7f017511761f5..441ae6d2e505f 100644 --- a/tests/ui/fmt/format-string-wrong-order.stderr +++ b/tests/ui/fmt/format-string-wrong-order.stderr @@ -50,23 +50,29 @@ LL | format!("{?:#?}", bar); | = note: `?` comes after `:`, try `:?` instead -error: invalid format string: expected format parameter to occur after `:` +error: invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` --> $DIR/format-string-wrong-order.rs:15:21 | LL | format!("Hello {<5:}!", "x"); | ^ expected `<` to occur after `:` in format string -error: invalid format string: expected format parameter to occur after `:` +error: invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` --> $DIR/format-string-wrong-order.rs:17:21 | LL | format!("Hello {^5:}!", "x"); | ^ expected `^` to occur after `:` in format string -error: invalid format string: expected format parameter to occur after `:` +error: invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` --> $DIR/format-string-wrong-order.rs:19:21 | LL | format!("Hello {>5:}!", "x"); | ^ expected `>` to occur after `:` in format string -error: aborting due to 9 previous errors +error: invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}` + --> $DIR/format-string-wrong-order.rs:21:20 + | +LL | println!("{0:#X>18}", 12345); + | ^ expected `>` to occur after `:` in format string + +error: aborting due to 10 previous errors From c7e1885075b3ac9c3f3c0553dbf813f0d44d18e7 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 25 Jul 2025 11:28:37 +0200 Subject: [PATCH 04/12] allow using `target_val!` with a rename --- compiler/rustc_target/src/spec/json.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index f56a65d9c0cab..2ea7c4df881d9 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -245,19 +245,17 @@ impl ToJson for Target { target.update_to_cli(); macro_rules! target_val { - ($attr:ident) => {{ - let name = (stringify!($attr)).replace("_", "-"); - d.insert(name, target.$attr.to_json()); + ($attr:ident) => { + target_val!($attr, (stringify!($attr)).replace("_", "-")) + }; + ($attr:ident, $json_name:expr) => {{ + let name = $json_name; + d.insert(name.into(), target.$attr.to_json()); }}; } macro_rules! target_option_val { - ($attr:ident) => {{ - let name = (stringify!($attr)).replace("_", "-"); - if default.$attr != target.$attr { - d.insert(name, target.$attr.to_json()); - } - }}; + ($attr:ident) => {{ target_option_val!($attr, (stringify!($attr)).replace("_", "-")) }}; ($attr:ident, $json_name:expr) => {{ let name = $json_name; if default.$attr != target.$attr { @@ -290,7 +288,7 @@ impl ToJson for Target { target_val!(llvm_target); target_val!(metadata); - d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json()); + target_val!(pointer_width, "target-pointer-width"); target_val!(arch); target_val!(data_layout); From 1f7efabdc6204b3a1cc9bfe612136f848f643949 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 25 Jul 2025 11:28:37 +0200 Subject: [PATCH 05/12] turn pointer width into an integer in target.json --- compiler/rustc_abi/src/lib.rs | 2 +- compiler/rustc_ast_ir/src/lib.rs | 4 ++-- compiler/rustc_target/src/spec/json.rs | 7 ++----- compiler/rustc_target/src/spec/mod.rs | 2 +- tests/run-make/rust-lld-custom-target/custom-target.json | 2 +- tests/run-make/rustdoc-target-spec-json-path/target.json | 2 +- tests/run-make/target-specs/endianness-mismatch.json | 2 +- tests/run-make/target-specs/mismatching-data-layout.json | 2 +- tests/run-make/target-specs/my-awesome-platform.json | 2 +- tests/run-make/target-specs/my-incomplete-platform.json | 2 +- .../target-specs/my-x86_64-unknown-linux-gnu-platform.json | 2 +- tests/run-make/target-specs/require-explicit-cpu.json | 2 +- 12 files changed, 14 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 14e256b8045df..a1a0de5aaf8f3 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -315,7 +315,7 @@ pub enum TargetDataLayoutErrors<'a> { MissingAlignment { cause: &'a str }, InvalidAlignment { cause: &'a str, err: AlignFromBytesError }, InconsistentTargetArchitecture { dl: &'a str, target: &'a str }, - InconsistentTargetPointerWidth { pointer_size: u64, target: u32 }, + InconsistentTargetPointerWidth { pointer_size: u64, target: u16 }, InvalidBitsSize { err: String }, UnknownPointerSpecification { err: String }, } diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 8f2a37c121088..44837b1b49407 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -69,7 +69,7 @@ impl IntTy { }) } - pub fn normalize(&self, target_width: u32) -> Self { + pub fn normalize(&self, target_width: u16) -> Self { match self { IntTy::Isize => match target_width { 16 => IntTy::I16, @@ -148,7 +148,7 @@ impl UintTy { }) } - pub fn normalize(&self, target_width: u32) -> Self { + pub fn normalize(&self, target_width: u16) -> Self { match self { UintTy::Usize => match target_width { 16 => UintTy::U16, diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 2ea7c4df881d9..e9ae5734d5b26 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -25,10 +25,7 @@ impl Target { let mut base = Target { llvm_target: json.llvm_target, metadata: Default::default(), - pointer_width: json - .target_pointer_width - .parse() - .map_err(|err| format!("invalid target-pointer-width: {err}"))?, + pointer_width: json.target_pointer_width, data_layout: json.data_layout, arch: json.arch, options: Default::default(), @@ -461,7 +458,7 @@ struct TargetSpecJsonMetadata { #[serde(deny_unknown_fields)] struct TargetSpecJson { llvm_target: StaticCow, - target_pointer_width: String, + target_pointer_width: u16, data_layout: StaticCow, arch: StaticCow, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c53d92bee9d29..7873f03eb2967 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2327,7 +2327,7 @@ pub struct Target { /// Used for generating target documentation. pub metadata: TargetMetadata, /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable. - pub pointer_width: u32, + pub pointer_width: u16, /// Architecture to use for ABI considerations. Valid options include: "x86", /// "x86_64", "arm", "aarch64", "mips", "powerpc", "powerpc64", and others. pub arch: StaticCow, diff --git a/tests/run-make/rust-lld-custom-target/custom-target.json b/tests/run-make/rust-lld-custom-target/custom-target.json index e2c64cbdb43c2..28c3dc6f387aa 100644 --- a/tests/run-make/rust-lld-custom-target/custom-target.json +++ b/tests/run-make/rust-lld-custom-target/custom-target.json @@ -53,5 +53,5 @@ "target-family": [ "unix" ], - "target-pointer-width": "64" + "target-pointer-width": 64 } diff --git a/tests/run-make/rustdoc-target-spec-json-path/target.json b/tests/run-make/rustdoc-target-spec-json-path/target.json index d7e4cac57ae75..6d8fe8528c80d 100644 --- a/tests/run-make/rustdoc-target-spec-json-path/target.json +++ b/tests/run-make/rustdoc-target-spec-json-path/target.json @@ -33,5 +33,5 @@ "thread" ], "target-family": "unix", - "target-pointer-width": "64" + "target-pointer-width": 64 } diff --git a/tests/run-make/target-specs/endianness-mismatch.json b/tests/run-make/target-specs/endianness-mismatch.json index cc03becc59af6..d73ea1cbcfec3 100644 --- a/tests/run-make/target-specs/endianness-mismatch.json +++ b/tests/run-make/target-specs/endianness-mismatch.json @@ -4,7 +4,7 @@ "linker-flavor": "gcc", "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "big", - "target-pointer-width": "64", + "target-pointer-width": 64, "arch": "x86_64", "os": "linux" } diff --git a/tests/run-make/target-specs/mismatching-data-layout.json b/tests/run-make/target-specs/mismatching-data-layout.json index d12caaad14a03..e948d4d2f99fd 100644 --- a/tests/run-make/target-specs/mismatching-data-layout.json +++ b/tests/run-make/target-specs/mismatching-data-layout.json @@ -2,5 +2,5 @@ "arch": "x86_64", "data-layout": "e-m:e-i64:16:32:64", "llvm-target": "x86_64-unknown-unknown-gnu", - "target-pointer-width": "64" + "target-pointer-width": 64 } diff --git a/tests/run-make/target-specs/my-awesome-platform.json b/tests/run-make/target-specs/my-awesome-platform.json index d41038b84a865..732a6bacd157c 100644 --- a/tests/run-make/target-specs/my-awesome-platform.json +++ b/tests/run-make/target-specs/my-awesome-platform.json @@ -3,7 +3,7 @@ "linker-flavor": "gcc", "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", - "target-pointer-width": "32", + "target-pointer-width": 32, "arch": "x86", "os": "linux" } diff --git a/tests/run-make/target-specs/my-incomplete-platform.json b/tests/run-make/target-specs/my-incomplete-platform.json index 8bdc4108f494a..68dbfc62d1c21 100644 --- a/tests/run-make/target-specs/my-incomplete-platform.json +++ b/tests/run-make/target-specs/my-incomplete-platform.json @@ -2,7 +2,7 @@ "data-layout": "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32", "linker-flavor": "gcc", "target-endian": "little", - "target-pointer-width": "32", + "target-pointer-width": 32, "arch": "x86", "os": "foo" } diff --git a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json index 27833f1abdd9e..008ea54838312 100644 --- a/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json +++ b/tests/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json @@ -4,7 +4,7 @@ "linker-flavor": "gcc", "llvm-target": "x86_64-unknown-linux-gnu", "target-endian": "little", - "target-pointer-width": "64", + "target-pointer-width": 64, "arch": "x86_64", "os": "linux" } diff --git a/tests/run-make/target-specs/require-explicit-cpu.json b/tests/run-make/target-specs/require-explicit-cpu.json index 9744bca168e2d..4f23b644d8cf6 100644 --- a/tests/run-make/target-specs/require-explicit-cpu.json +++ b/tests/run-make/target-specs/require-explicit-cpu.json @@ -3,7 +3,7 @@ "linker-flavor": "gcc", "llvm-target": "i686-unknown-linux-gnu", "target-endian": "little", - "target-pointer-width": "32", + "target-pointer-width": 32, "arch": "x86", "os": "linux", "need-explicit-cpu": true From aa0887b223d3af4570f2a6f31c9d85d792a7b4de Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 25 Jul 2025 15:12:44 +0200 Subject: [PATCH 06/12] accept integer `target-pointer-width` in compiletest --- src/tools/compiletest/src/common.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 7fc80c1edb158..645ed474b6044 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -6,7 +6,6 @@ use std::sync::OnceLock; use build_helper::git::GitConfig; use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; -use serde::de::{Deserialize, Deserializer, Error as _}; use crate::executor::{ColorConfig, OutputFormat}; use crate::fatal; @@ -1080,7 +1079,7 @@ pub struct TargetCfg { pub(crate) abi: String, #[serde(rename = "target-family", default)] pub(crate) families: Vec, - #[serde(rename = "target-pointer-width", deserialize_with = "serde_parse_u32")] + #[serde(rename = "target-pointer-width")] pub(crate) pointer_width: u32, #[serde(rename = "target-endian", default)] endian: Endian, @@ -1190,11 +1189,6 @@ fn query_rustc_output(config: &Config, args: &[&str], envs: HashMap>(deserializer: D) -> Result { - let string = String::deserialize(deserializer)?; - string.parse().map_err(D::Error::custom) -} - #[derive(Debug, Clone)] pub struct TestPaths { pub file: Utf8PathBuf, // e.g., compile-test/foo/bar/baz.rs From 6a3187af13e59beb00f6eaff8c4c9da19b382d36 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 31 Jul 2025 19:03:22 +0200 Subject: [PATCH 07/12] fix target-pointer-width in tests --- .../rustc_codegen_gcc/target_specs/m68k-unknown-linux-gnu.json | 2 +- compiler/rustc_target/src/tests.rs | 2 +- library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json | 2 +- src/tools/miri/tests/x86_64-unknown-kernel.json | 2 +- tests/ui/check-cfg/my-awesome-platform.json | 2 +- tests/ui/codegen/mismatched-data-layout.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_gcc/target_specs/m68k-unknown-linux-gnu.json b/compiler/rustc_codegen_gcc/target_specs/m68k-unknown-linux-gnu.json index 95ea06106fb1b..b13b640a7c7e6 100644 --- a/compiler/rustc_codegen_gcc/target_specs/m68k-unknown-linux-gnu.json +++ b/compiler/rustc_codegen_gcc/target_specs/m68k-unknown-linux-gnu.json @@ -22,5 +22,5 @@ "unix" ], "target-mcount": "_mcount", - "target-pointer-width": "32" + "target-pointer-width": 32 } diff --git a/compiler/rustc_target/src/tests.rs b/compiler/rustc_target/src/tests.rs index ee847a84007f0..a2692ea6be5e0 100644 --- a/compiler/rustc_target/src/tests.rs +++ b/compiler/rustc_target/src/tests.rs @@ -7,7 +7,7 @@ fn report_unused_fields() { "arch": "powerpc64", "data-layout": "e-m:e-i64:64-n32:64", "llvm-target": "powerpc64le-elf", - "target-pointer-width": "64", + "target-pointer-width": 64, "code-mode": "foo" } "#; diff --git a/library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json b/library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json index 81273d44e4965..6369bbe254775 100644 --- a/library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json +++ b/library/compiler-builtins/etc/thumbv7em-none-eabi-renamed.json @@ -19,5 +19,5 @@ }, "panic-strategy": "abort", "relocation-model": "static", - "target-pointer-width": "32" + "target-pointer-width": 32 } diff --git a/src/tools/miri/tests/x86_64-unknown-kernel.json b/src/tools/miri/tests/x86_64-unknown-kernel.json index a5eaceb4f68e7..0f8032c39d568 100644 --- a/src/tools/miri/tests/x86_64-unknown-kernel.json +++ b/src/tools/miri/tests/x86_64-unknown-kernel.json @@ -1,7 +1,7 @@ { "llvm-target": "x86_64-unknown-none", "target-endian": "little", - "target-pointer-width": "64", + "target-pointer-width": 64, "target-c-int-width": 32, "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", diff --git a/tests/ui/check-cfg/my-awesome-platform.json b/tests/ui/check-cfg/my-awesome-platform.json index 4c16d06c7b7d6..3a1f6b1a54c61 100644 --- a/tests/ui/check-cfg/my-awesome-platform.json +++ b/tests/ui/check-cfg/my-awesome-platform.json @@ -3,7 +3,7 @@ "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", - "target-pointer-width": "64", + "target-pointer-width": 64, "os": "ericos", "linker-flavor": "ld.lld", "linker": "rust-lld", diff --git a/tests/ui/codegen/mismatched-data-layout.json b/tests/ui/codegen/mismatched-data-layout.json index f8c510c186362..a1b222010abd5 100644 --- a/tests/ui/codegen/mismatched-data-layout.json +++ b/tests/ui/codegen/mismatched-data-layout.json @@ -3,7 +3,7 @@ "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", - "target-pointer-width": "64", + "target-pointer-width": 64, "os": "none", "linker-flavor": "ld.lld", "linker": "rust-lld", From 2d8cb59784711f503170011461c23385042a974d Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 21 Aug 2025 20:18:00 +0200 Subject: [PATCH 08/12] CI: rfl: support Rust >= 1.91.0 target spec To unblock the Rust CI in PR [1], use a temporary commit from Rust for Linux that supports the future target spec format. Link: https://github.com/rust-lang/rust/pull/144443 [1] Signed-off-by: Miguel Ojeda --- src/ci/docker/scripts/rfl-build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 8acc5040a2fc7..70ff5d0d2c722 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,8 @@ set -euo pipefail -LINUX_VERSION=v6.16-rc1 +# https://github.com/rust-lang/rust/pull/144443 +LINUX_VERSION=7770d51bce622b13195b2d3c85407282fc9c27e5 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt From f29327ff6093bc09c445028bd05a172e570e8486 Mon Sep 17 00:00:00 2001 From: gonzalobg <65027571+gonzalobg@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:21:07 +0200 Subject: [PATCH 09/12] Clarify that align_offset overaligns The current documentation is not clear whether adding `a` to a pointer overaligns (align up) or underaligns (align down). It should say this explicitly. --- library/core/src/ptr/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 6fc85a83e179e..6b94088cb5679 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2166,10 +2166,9 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { } } -/// Align pointer `p`. +/// Calculate an element-offset that increases a pointer's alignment. /// -/// Calculate offset (in terms of elements of `size_of::()` stride) that has to be applied -/// to pointer `p` so that pointer `p` would get aligned to `a`. +/// Calculate an element-offset (not byte-offset) that when added to a given pointer `p`, increases `p`'s alignment to at least the given alignment `a`. /// /// # Safety /// `a` must be a power of two. From 539f8400e769ad6092b5fe1cac0ebe885e5543a8 Mon Sep 17 00:00:00 2001 From: Aurelia Molzer <5550310+HeroicKatora@users.noreply.github.com> Date: Sat, 30 Aug 2025 11:50:28 +0200 Subject: [PATCH 10/12] Clarify panic-drop test for select_unpredictable --- library/coretests/tests/hint.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/coretests/tests/hint.rs b/library/coretests/tests/hint.rs index 9ef5567681e93..24de27b24b802 100644 --- a/library/coretests/tests/hint.rs +++ b/library/coretests/tests/hint.rs @@ -23,7 +23,7 @@ fn select_unpredictable_drop() { } #[test] -#[should_panic] +#[should_panic = "message canary"] fn select_unpredictable_drop_on_panic() { use core::cell::Cell; @@ -37,7 +37,7 @@ fn select_unpredictable_drop_on_panic() { fn drop(&mut self) { let value = self.cell.get(); self.cell.set(self.write); - assert_eq!(value, self.expect); + assert_eq!(value, self.expect, "message canary"); } } @@ -55,6 +55,5 @@ fn select_unpredictable_drop_on_panic() { // 3. `armed` drops during unwind, writes 0 and does not panic as 0xdead == 0xdead // // If `selected` is not dropped, `armed` panics as 1 != 0xdead - let _unreachable = - core::hint::select_unpredictable(core::hint::black_box(true), selected, unselected); + let _unreachable = core::hint::select_unpredictable(true, selected, unselected); } From 354787b5ba8210070929e7454312c51da8e6f988 Mon Sep 17 00:00:00 2001 From: Aurelia Molzer <5550310+HeroicKatora@users.noreply.github.com> Date: Sat, 30 Aug 2025 11:58:48 +0200 Subject: [PATCH 11/12] Simplify select_unpredictable guard selection Instead of a tuple, select the dropped value and its guard with two separate calls to the intrinsic which makes both calls have a pointer-valued argument that should be simpler in codegen. Use the same condition on all (not an inverted condition) to clarify the intent of parallel selection. This should also be a simpler value-dependency chain if the guard is deduced unused (i.e. drop_in_place a noop for the type). --- library/core/src/hint.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 1bb1c56950879..852882aa7f4c7 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -788,6 +788,7 @@ pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T let mut false_val = MaybeUninit::new(false_val); struct DropOnPanic { + // Invariant: valid pointer and points to an initialized `MaybeUninit`. inner: *mut MaybeUninit, } @@ -806,12 +807,11 @@ pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T // value that is not selected. unsafe { // Extract the selected value first, ensure it is dropped as well if dropping the unselected - // value panics. - let (guard, drop) = crate::intrinsics::select_unpredictable( - condition, - (true_ptr, false_ptr), - (false_ptr, true_ptr), - ); + // value panics. We construct a temporary by-pointer guard around the selected value while + // dropping the unselected value. Arguments overlap here, so we can not use mutable + // reference for these arguments. + let guard = crate::intrinsics::select_unpredictable(condition, true_ptr, false_ptr); + let drop = crate::intrinsics::select_unpredictable(condition, false_ptr, true_ptr); // SAFETY: both pointers are to valid `MaybeUninit`, in both variants they do not alias but // the two arguments we have selected from did alias each other. From ee9803a244d65a830a999f8066da2a70e1972d5e Mon Sep 17 00:00:00 2001 From: Aurelia Molzer <5550310+HeroicKatora@users.noreply.github.com> Date: Sat, 30 Aug 2025 13:00:02 +0200 Subject: [PATCH 12/12] Switch select_unpredictable guard to raw pointer --- library/core/src/hint.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 852882aa7f4c7..89c64f6d28fef 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -788,19 +788,20 @@ pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T let mut false_val = MaybeUninit::new(false_val); struct DropOnPanic { - // Invariant: valid pointer and points to an initialized `MaybeUninit`. - inner: *mut MaybeUninit, + // Invariant: valid pointer and points to an initialized value that is not further used, + // i.e. it can be dropped by this guard. + inner: *mut T, } impl Drop for DropOnPanic { fn drop(&mut self) { // SAFETY: Must be guaranteed on construction of local type `DropOnPanic`. - unsafe { (*self.inner).assume_init_drop() } + unsafe { self.inner.drop_in_place() } } } - let true_ptr = (&mut true_val) as *mut _; - let false_ptr = (&mut false_val) as *mut _; + let true_ptr = true_val.as_mut_ptr(); + let false_ptr = false_val.as_mut_ptr(); // SAFETY: The value that is not selected is dropped, and the selected one // is returned. This is necessary because the intrinsic doesn't drop the @@ -813,10 +814,12 @@ pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T let guard = crate::intrinsics::select_unpredictable(condition, true_ptr, false_ptr); let drop = crate::intrinsics::select_unpredictable(condition, false_ptr, true_ptr); - // SAFETY: both pointers are to valid `MaybeUninit`, in both variants they do not alias but - // the two arguments we have selected from did alias each other. + // SAFETY: both pointers are well-aligned and point to initialized values inside a + // `MaybeUninit` each. In both possible values for `condition` the pointer `guard` and + // `drop` do not alias (even though the two argument pairs we have selected from did alias + // each other). let guard = DropOnPanic { inner: guard }; - (*drop).assume_init_drop(); + drop.drop_in_place(); crate::mem::forget(guard); // Note that it is important to use the values here. Reading from the pointer we got makes