From 917d2eb78ac514bf3e3a41b38cb148bf918a0b8d Mon Sep 17 00:00:00 2001 From: Curtis D'Alves Date: Thu, 20 Feb 2025 14:31:19 -0500 Subject: [PATCH 01/19] add verbatim linker to AIXLinker --- compiler/rustc_codegen_ssa/src/back/linker.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e3ace01c1eb54..432bb692fb1e5 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1643,9 +1643,9 @@ impl<'a> Linker for AixLinker<'a> { } } - fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.link_or_cc_arg(format!("-l{name}")); + self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") }); } fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { @@ -1656,7 +1656,7 @@ impl<'a> Linker for AixLinker<'a> { fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.link_or_cc_arg(format!("-l{name}")); + self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") }); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(find_native_static_library(name, verbatim, self.sess)); From d6bb98e7579b3d8711cc00dc95a9425395bae9df Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 12 Feb 2025 05:41:02 +0000 Subject: [PATCH 02/19] span: add a "future" edition It's hard to implement edition migrations without having a perma-unstable "future" edition to target. --- .../src/standard_library_imports.rs | 1 + compiler/rustc_span/src/edition.rs | 29 +++++++++++++++++-- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/prelude/mod.rs | 23 +++++++++++++++ library/std/src/prelude/mod.rs | 15 ++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 6933ca09349a1..ba63b185e0967 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -60,6 +60,7 @@ pub fn inject( Edition2018 => sym::rust_2018, Edition2021 => sym::rust_2021, Edition2024 => sym::rust_2024, + EditionFuture => sym::rust_future, }]) .map(|&symbol| Ident::new(symbol, span)) .collect(); diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 36f9b4cff60b0..da298080ed2f6 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -23,11 +23,27 @@ pub enum Edition { Edition2021, /// The 2024 edition Edition2024, + /// The future edition - this variant will always exist and features associated with this + /// edition can be moved to the next 20XX edition when it is established and it is confirmed + /// that those features will be part of that edition. + /// + /// This variant allows edition changes to be implemented before being assigned to a concrete + /// edition - primarily when there are two different unstable behaviours that need tested across + /// an edition boundary. + /// + /// This edition will be permanently unstable and any features associated with this edition + /// must also be behind a feature gate. + EditionFuture, } // Must be in order from oldest to newest. -pub const ALL_EDITIONS: &[Edition] = - &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024]; +pub const ALL_EDITIONS: &[Edition] = &[ + Edition::Edition2015, + Edition::Edition2018, + Edition::Edition2021, + Edition::Edition2024, + Edition::EditionFuture, +]; pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024"; @@ -42,6 +58,7 @@ impl fmt::Display for Edition { Edition::Edition2018 => "2018", Edition::Edition2021 => "2021", Edition::Edition2024 => "2024", + Edition::EditionFuture => "future", }; write!(f, "{s}") } @@ -54,6 +71,7 @@ impl Edition { Edition::Edition2018 => "rust_2018_compatibility", Edition::Edition2021 => "rust_2021_compatibility", Edition::Edition2024 => "rust_2024_compatibility", + Edition::EditionFuture => "edition_future_compatibility", } } @@ -63,6 +81,7 @@ impl Edition { Edition::Edition2018 => true, Edition::Edition2021 => true, Edition::Edition2024 => true, + Edition::EditionFuture => false, } } @@ -85,6 +104,11 @@ impl Edition { pub fn at_least_rust_2024(self) -> bool { self >= Edition::Edition2024 } + + /// Are we allowed to use features from the future edition? + pub fn at_least_edition_future(self) -> bool { + self >= Edition::EditionFuture + } } impl FromStr for Edition { @@ -95,6 +119,7 @@ impl FromStr for Edition { "2018" => Ok(Edition::Edition2018), "2021" => Ok(Edition::Edition2021), "2024" => Ok(Edition::Edition2024), + "future" => Ok(Edition::EditionFuture), _ => Err(()), } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 172c2faca9639..1823a7de5180e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1711,6 +1711,7 @@ symbols! { rust_cold_cc, rust_eh_catch_typeinfo, rust_eh_personality, + rust_future, rust_logo, rust_out, rustc, diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 590ffd64b5bff..8d867a269a21a 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -70,3 +70,26 @@ pub mod rust_2024 { #[doc(no_inline)] pub use crate::future::{Future, IntoFuture}; } + +/// The Future version of the core prelude. +/// +/// See the [module-level documentation](self) for more. +#[doc(hidden)] +#[unstable(feature = "prelude_future", issue = "none")] +pub mod rust_future { + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use super::v1::*; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::iter::FromIterator; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::convert::{TryFrom, TryInto}; + + #[stable(feature = "prelude_2024", since = "1.85.0")] + #[doc(no_inline)] + pub use crate::future::{Future, IntoFuture}; +} diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 992a9207a7206..5f7097c26e228 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -160,3 +160,18 @@ pub mod rust_2024 { #[doc(no_inline)] pub use core::prelude::rust_2024::*; } + +/// The Future version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[doc(hidden)] +#[unstable(feature = "prelude_future", issue = "none")] +pub mod rust_future { + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use super::v1::*; + + #[unstable(feature = "prelude_next", issue = "none")] + #[doc(no_inline)] + pub use core::prelude::rust_future::*; +} From b5562c04e73590c8eefa67400aba022ff7b61f25 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:14:16 +0100 Subject: [PATCH 03/19] Remove i586-pc-windows-msvc See MCP 840. I left a specialized error message that should help users that hit this in the wild (for example, because they use it in their CI). --- compiler/rustc_target/src/spec/mod.rs | 11 +++++++++-- .../src/spec/targets/i586_pc_windows_msvc.rs | 9 --------- src/ci/github-actions/jobs.yml | 2 +- src/doc/rustc/src/platform-support.md | 1 - src/tools/build-manifest/src/main.rs | 1 - .../stack-protector/stack-protector-target-support.rs | 6 +----- tests/assembly/targets/targets-pe.rs | 3 --- 7 files changed, 11 insertions(+), 22 deletions(-) delete mode 100644 compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index cc8162a2f27ea..1edc66bb9f963 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1915,7 +1915,6 @@ supported_targets! { ("i686-pc-windows-msvc", i686_pc_windows_msvc), ("i686-uwp-windows-msvc", i686_uwp_windows_msvc), ("i686-win7-windows-msvc", i686_win7_windows_msvc), - ("i586-pc-windows-msvc", i586_pc_windows_msvc), ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc), ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc), @@ -3503,7 +3502,15 @@ impl Target { return load_file(&p); } - Err(format!("Could not find specification for target {target_tuple:?}")) + // Leave in a specialized error message for the removed target. + // FIXME: If you see this and it's been a few months after this has been released, + // you can probably remove it. + if target_tuple == "i586-pc-windows-msvc" { + Err("the `i586-pc-windows-msvc` target has been removed. Use the `i686-pc-windows-msvc` target instead.\n\ + Windows 10 (the minimum required OS version) requires a CPU baseline of at least i686 so you can safely switch".into()) + } else { + Err(format!("Could not find specification for target {target_tuple:?}")) + } } TargetTuple::TargetJson { ref contents, .. } => { let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs deleted file mode 100644 index 394e6f9e6bf65..0000000000000 --- a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::spec::Target; - -pub(crate) fn target() -> Target { - let mut base = super::i686_pc_windows_msvc::target(); - base.rustc_abi = None; // overwrite the SSE2 ABI set by the base target - base.cpu = "pentium".into(); - base.llvm_target = "i586-pc-windows-msvc".into(); - base -} diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index bbcc01a0c2998..aff374654dc74 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -591,7 +591,7 @@ auto: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc --host=i686-pc-windows-msvc - --target=i686-pc-windows-msvc,i586-pc-windows-msvc + --target=i686-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c4e5c1aac2f5d..487fb94c229e2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -162,7 +162,6 @@ target | std | notes [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat -`i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index cd5ca74f8ade5..dfc8f3bc7e0db 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -97,7 +97,6 @@ static TARGETS: &[&str] = &[ "bpfeb-unknown-none", "bpfel-unknown-none", "i386-apple-ios", - "i586-pc-windows-msvc", "i586-unknown-linux-gnu", "i586-unknown-linux-musl", "i586-unknown-redox", diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs index e9ba0f9ba899c..a937256a60f8c 100644 --- a/tests/assembly/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly/stack-protector/stack-protector-target-support.rs @@ -3,7 +3,7 @@ // //@ add-core-stubs //@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 -//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r35 r36 r37 r38 r39 r40 r41 r42 r43 r44 +//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r36 r37 r38 r39 r40 r41 r42 r43 r44 //@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 //@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85 //@ assembly-output: emit-asm @@ -73,9 +73,6 @@ //@ [r32] needs-llvm-components: arm //@ [r33] compile-flags: --target armv7-unknown-linux-musleabihf //@ [r33] needs-llvm-components: arm - -//@ [r35] compile-flags: --target i586-pc-windows-msvc -//@ [r35] needs-llvm-components: x86 //@ [r36] compile-flags: --target i586-unknown-linux-gnu //@ [r36] needs-llvm-components: x86 //@ [r37] compile-flags: --target i586-unknown-linux-musl @@ -195,7 +192,6 @@ pub fn foo() { // r3: calll @__security_check_cookie // r7: callq __security_check_cookie // r13: bl __security_check_cookie - // r35: calll @__security_check_cookie // cuda doesn't support stack-smash protection // r49-NOT: __security_check_cookie diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs index f895b79ba5077..de29b9af5020f 100644 --- a/tests/assembly/targets/targets-pe.rs +++ b/tests/assembly/targets/targets-pe.rs @@ -25,9 +25,6 @@ //@ revisions: bpfel_unknown_none //@ [bpfel_unknown_none] compile-flags: --target bpfel-unknown-none //@ [bpfel_unknown_none] needs-llvm-components: bpf -//@ revisions: i586_pc_windows_msvc -//@ [i586_pc_windows_msvc] compile-flags: --target i586-pc-windows-msvc -//@ [i586_pc_windows_msvc] needs-llvm-components: x86 //@ revisions: i686_pc_windows_gnu //@ [i686_pc_windows_gnu] compile-flags: --target i686-pc-windows-gnu //@ [i686_pc_windows_gnu] needs-llvm-components: x86 From 1a5a4537437285bbd0f7f4cc9525b312a44789b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 4 Mar 2025 15:14:59 +0100 Subject: [PATCH 04/19] atomic: clarify that failing conditional RMW operations are not 'writes' --- library/core/src/sync/atomic.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 73180bde54aa9..d55fa347cc5b4 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -44,8 +44,9 @@ //! The most important aspect of this model is that *data races* are undefined behavior. A data race //! is defined as conflicting non-synchronized accesses where at least one of the accesses is //! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at -//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before* -//! the other, according to the happens-before order of the memory model. +//! least one of them is a write. (A `compare_exchange` or `compare_exchange_weak` that does not +//! succeed is not considered a write.) They are *non-synchronized* if neither of them +//! *happens-before* the other, according to the happens-before order of the memory model. //! //! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust //! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially From e07d9a8200bc37e3cd816386d35931f9f02e9464 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski Date: Wed, 5 Mar 2025 04:46:14 +0000 Subject: [PATCH 05/19] rustdoc: Add attribute-related tests for rustdoc JSON. --- tests/rustdoc-json/attrs/export_name_2021.rs | 6 ++++++ tests/rustdoc-json/attrs/export_name_2024.rs | 9 +++++++++ tests/rustdoc-json/attrs/must_use.rs | 9 +++++++++ tests/rustdoc-json/attrs/no_mangle_2021.rs | 6 ++++++ tests/rustdoc-json/attrs/no_mangle_2024.rs | 9 +++++++++ tests/rustdoc-json/attrs/non_exhaustive.rs | 19 +++++++++++++++++++ 6 files changed, 58 insertions(+) create mode 100644 tests/rustdoc-json/attrs/export_name_2021.rs create mode 100644 tests/rustdoc-json/attrs/export_name_2024.rs create mode 100644 tests/rustdoc-json/attrs/must_use.rs create mode 100644 tests/rustdoc-json/attrs/no_mangle_2021.rs create mode 100644 tests/rustdoc-json/attrs/no_mangle_2024.rs create mode 100644 tests/rustdoc-json/attrs/non_exhaustive.rs diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs new file mode 100644 index 0000000000000..badf124bdde36 --- /dev/null +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 +#![no_std] + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +#[export_name = "altered"] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs new file mode 100644 index 0000000000000..c5bb9dcc8f68a --- /dev/null +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -0,0 +1,9 @@ +//@ edition: 2024 +#![no_std] + +// The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 +// is still `#[export_name = ..]` without the `unsafe` attribute wrapper. + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +#[unsafe(export_name = "altered")] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs new file mode 100644 index 0000000000000..dca73abc76a1a --- /dev/null +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -0,0 +1,9 @@ +#![no_std] + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[must_use]"]' +#[must_use] +pub fn example() -> impl Iterator {} + +//@ is "$.index[*][?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' +#[must_use = "does nothing if you do not use it"] +pub fn explicit_message() -> impl Iterator {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs new file mode 100644 index 0000000000000..258542086ec37 --- /dev/null +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 +#![no_std] + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]' +#[no_mangle] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs new file mode 100644 index 0000000000000..4c01082d045ef --- /dev/null +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -0,0 +1,9 @@ +//@ edition: 2024 +#![no_std] + +// The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 +// is still `#[no_mangle]` without the `unsafe` attribute wrapper. + +//@ is "$.index[*][?(@.name=='example')].attrs" '["#[no_mangle]"]' +#[unsafe(no_mangle)] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs new file mode 100644 index 0000000000000..5d738fc0560da --- /dev/null +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -0,0 +1,19 @@ +#![no_std] + +//@ is "$.index[*][?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +#[non_exhaustive] +pub enum MyEnum { + First, +} + +pub enum NonExhaustiveVariant { + //@ is "$.index[*][?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + #[non_exhaustive] + Variant(i64), +} + +//@ is "$.index[*][?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +#[non_exhaustive] +pub struct MyStruct { + pub x: i64, +} From 9d8ce729011a8b8c735e3b3cfea66db1bc0fb303 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 21 Feb 2025 00:07:46 -0800 Subject: [PATCH 06/19] compiler: factor Windows x86-32 ABI impl into its own file While it shares more than zero code with the SysV x86-32 ABI impl, there is no particular reason to organize wildly different ABIs using if-else in the same function. --- compiler/rustc_target/src/callconv/mod.rs | 7 +- compiler/rustc_target/src/callconv/x86.rs | 24 +----- .../rustc_target/src/callconv/x86_win32.rs | 81 +++++++++++++++++++ 3 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 compiler/rustc_target/src/callconv/x86_win32.rs diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 1c044fe98b3ef..8fe19358954e0 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -31,6 +31,7 @@ mod sparc64; mod wasm; mod x86; mod x86_64; +mod x86_win32; mod x86_win64; mod xtensa; @@ -649,7 +650,11 @@ impl<'a, Ty> FnAbi<'a, Ty> { }; let reg_struct_return = cx.x86_abi_opt().reg_struct_return; let opts = x86::X86Options { flavor, regparm, reg_struct_return }; - x86::compute_abi_info(cx, self, opts); + if spec.is_like_msvc { + x86_win32::compute_abi_info(cx, self, opts); + } else { + x86::compute_abi_info(cx, self, opts); + } } "x86_64" => match abi { ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 7e5aab0201b6d..828725e946923 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -36,7 +36,7 @@ where if t.abi_return_struct_as_int || opts.reg_struct_return { // According to Clang, everyone but MSVC returns single-element // float aggregates directly in a floating-point register. - if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) { + if fn_abi.ret.layout.is_single_fp_element(cx) { match fn_abi.ret.layout.size.bytes() { 4 => fn_abi.ret.cast_to(Reg::f32()), 8 => fn_abi.ret.cast_to(Reg::f64()), @@ -64,31 +64,11 @@ where continue; } - // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 - // See https://reviews.llvm.org/D72114 for Clang behavior - let t = cx.target_spec(); let align_4 = Align::from_bytes(4).unwrap(); let align_16 = Align::from_bytes(16).unwrap(); - if t.is_like_msvc - && arg.layout.is_adt() - && let Some(max_repr_align) = arg.layout.max_repr_align - && max_repr_align > align_4 - { - // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. - // Summarized here: - // - Arguments with _requested_ alignment > 4 are passed indirectly. - // - For backwards compatibility, arguments with natural alignment > 4 are still passed - // on stack (via `byval`). For example, this includes `double`, `int64_t`, - // and structs containing them, provided they lack an explicit alignment attribute. - assert!( - arg.layout.align.abi >= max_repr_align, - "abi alignment {:?} less than requested alignment {max_repr_align:?}", - arg.layout.align.abi, - ); - arg.make_indirect(); - } else if arg.layout.is_aggregate() { + if arg.layout.is_aggregate() { // We need to compute the alignment of the `byval` argument. The rules can be found in // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized // here, they are: diff --git a/compiler/rustc_target/src/callconv/x86_win32.rs b/compiler/rustc_target/src/callconv/x86_win32.rs new file mode 100644 index 0000000000000..554a7368848b5 --- /dev/null +++ b/compiler/rustc_target/src/callconv/x86_win32.rs @@ -0,0 +1,81 @@ +use rustc_abi::{Align, HasDataLayout, Reg, TyAbiInterface}; + +use crate::callconv::FnAbi; +use crate::spec::HasTargetSpec; + +pub(crate) fn compute_abi_info<'a, Ty, C>( + cx: &C, + fn_abi: &mut FnAbi<'a, Ty>, + opts: super::x86::X86Options, +) where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if !fn_abi.ret.is_ignore() { + if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() { + // Returning a structure. Most often, this will use + // a hidden first argument. On some platforms, though, + // small structs are returned as integers. + // + // Some links: + // https://www.angelcode.com/dev/callconv/callconv.html + // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp + let t = cx.target_spec(); + // MSVC does not special-case 1-element float aggregates, unlike others. + // GCC used to apply the SysV rule here, breaking windows-gnu's ABI, but was fixed: + // - reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028 + // - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667 + if t.abi_return_struct_as_int || opts.reg_struct_return { + match fn_abi.ret.layout.size.bytes() { + 1 => fn_abi.ret.cast_to(Reg::i8()), + 2 => fn_abi.ret.cast_to(Reg::i16()), + 4 => fn_abi.ret.cast_to(Reg::i32()), + 8 => fn_abi.ret.cast_to(Reg::i64()), + _ => fn_abi.ret.make_indirect(), + } + } else { + fn_abi.ret.make_indirect(); + } + } else { + fn_abi.ret.extend_integer_width_to(32); + } + } + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() || !arg.layout.is_sized() { + continue; + } + + // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 + // See https://reviews.llvm.org/D72114 for Clang behavior + + let align_4 = Align::from_bytes(4).unwrap(); + + if arg.layout.is_adt() + && let Some(max_repr_align) = arg.layout.max_repr_align + && max_repr_align > align_4 + { + // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. + // Summarized here: + // - Arguments with _requested_ alignment > 4 are passed indirectly. + // - For backwards compatibility, arguments with natural alignment > 4 are still passed + // on stack (via `byval`). For example, this includes `double`, `int64_t`, + // and structs containing them, provided they lack an explicit alignment attribute. + assert!( + arg.layout.align.abi >= max_repr_align, + "abi alignment {:?} less than requested alignment {max_repr_align:?}", + arg.layout.align.abi, + ); + arg.make_indirect(); + } else if arg.layout.is_aggregate() { + // Alignment of the `byval` argument. + // The rules can be found in `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. + let byval_align = align_4; + arg.pass_by_stack_offset(Some(byval_align)); + } else { + arg.extend_integer_width_to(32); + } + } + + super::x86::fill_inregs(cx, fn_abi, opts, false); +} From 4e4bed8684a7144c82ea95aa013e7911dd9fe20d Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Thu, 6 Mar 2025 16:24:40 -0800 Subject: [PATCH 07/19] setTargetTriple now accepts Triple rather than string --- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index aea2a8dd09787..6d01095cccad6 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -153,7 +153,11 @@ extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) { extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *Triple) { +#if LLVM_VERSION_GE(21, 0) + unwrap(M)->setTargetTriple(llvm::Triple(Triple::normalize(Triple))); +#else unwrap(M)->setTargetTriple(Triple::normalize(Triple)); +#endif } extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) { From 8814679a5410b8d9ce8385094ec8ec888395b1a5 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Thu, 6 Mar 2025 22:52:20 -0800 Subject: [PATCH 08/19] rename Triple to Target --- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 6d01095cccad6..53df59930f4fd 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -152,11 +152,11 @@ extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) { } extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, - const char *Triple) { + const char *Target) { #if LLVM_VERSION_GE(21, 0) - unwrap(M)->setTargetTriple(llvm::Triple(Triple::normalize(Triple))); + unwrap(M)->setTargetTriple(Triple(Triple::normalize(Target))); #else - unwrap(M)->setTargetTriple(Triple::normalize(Triple)); + unwrap(M)->setTargetTriple(Triple::normalize(Target)); #endif } From d5da6b71fa7f29946a41d624e038c1c0eed8a4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 4 Mar 2025 18:26:11 +0100 Subject: [PATCH 09/19] Add post-merge analysis CI workflow --- .github/workflows/post-merge.yml | 36 +++++ src/build_helper/src/metrics.rs | 2 +- src/ci/citool/src/main.rs | 12 ++ src/ci/citool/src/merge_report.rs | 257 ++++++++++++++++++++++++++++++ src/ci/citool/src/metrics.rs | 22 +-- 5 files changed, 319 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/post-merge.yml create mode 100644 src/ci/citool/src/merge_report.rs diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml new file mode 100644 index 0000000000000..d3f42c5a9052c --- /dev/null +++ b/.github/workflows/post-merge.yml @@ -0,0 +1,36 @@ +# Workflow that runs after a merge to master, analyses changes in test executions +# and posts the result to the merged PR. + +name: Post merge analysis + +on: + push: + branches: + - master + +jobs: + analysis: + runs-on: ubuntu-24.04 + if: github.repository == 'rust-lang/rust' + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v4 + - name: Perform analysis and send PR + run: | + # Get closest bors merge commit + PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` + + # Find PR for the current commit + HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` + + echo "Parent: ${PARENT_COMMIT}" + echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" + + cd src/ci/citool + + echo "Post-merge analysis result" > output.log + cargo run --release post-merge-analysis ${PARENT_COMMIT} ${{ github.sha }} >> output.log + cat output.log + + gh pr comment ${HEAD_PR} -F output.log diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index eb306550fc4a6..b6daac32a4412 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -74,7 +74,7 @@ pub struct Test { pub outcome: TestOutcome, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] #[serde(tag = "outcome", rename_all = "snake_case")] pub enum TestOutcome { Passed, diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 16edd68188649..52e7638d98bdf 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -1,5 +1,6 @@ mod cpu_usage; mod datadog; +mod merge_report; mod metrics; mod utils; @@ -13,6 +14,7 @@ use serde_yaml::Value; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; +use crate::merge_report::post_merge_report; use crate::metrics::postprocess_metrics; use crate::utils::load_env_var; @@ -373,6 +375,13 @@ enum Args { /// Path to a CSV containing the CI job CPU usage. cpu_usage_csv: PathBuf, }, + /// Generate a report of test execution changes between two rustc commits. + PostMergeReport { + /// Parent commit to use as a base of the comparison. + parent: String, + /// Current commit that will be compared to `parent`. + current: String, + }, } #[derive(clap::ValueEnum, Clone)] @@ -410,6 +419,9 @@ fn main() -> anyhow::Result<()> { Args::PostprocessMetrics { metrics_path, summary_path } => { postprocess_metrics(&metrics_path, &summary_path)?; } + Args::PostMergeReport { current: commit, parent } => { + post_merge_report(load_db(default_jobs_file)?, parent, commit)?; + } } Ok(()) diff --git a/src/ci/citool/src/merge_report.rs b/src/ci/citool/src/merge_report.rs new file mode 100644 index 0000000000000..5dd662280f0f3 --- /dev/null +++ b/src/ci/citool/src/merge_report.rs @@ -0,0 +1,257 @@ +use std::cmp::Reverse; +use std::collections::HashMap; + +use anyhow::Context; +use build_helper::metrics::{JsonRoot, TestOutcome}; + +use crate::JobDatabase; +use crate::metrics::get_test_suites; + +type Sha = String; +type JobName = String; + +/// Computes a post merge CI analysis report between the `parent` and `current` commits. +pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> { + let jobs = download_all_metrics(&job_db, &parent, ¤t)?; + let diffs = aggregate_test_diffs(&jobs)?; + report_test_changes(diffs); + + Ok(()) +} + +struct JobMetrics { + parent: Option, + current: JsonRoot, +} + +/// Download before/after metrics for all auto jobs in the job database. +fn download_all_metrics( + job_db: &JobDatabase, + parent: &str, + current: &str, +) -> anyhow::Result> { + let mut jobs = HashMap::default(); + + for job in &job_db.auto_jobs { + eprintln!("Downloading metrics of job {}", job.name); + let metrics_parent = match download_job_metrics(&job.name, parent) { + Ok(metrics) => Some(metrics), + Err(error) => { + eprintln!( + r#"Did not find metrics for job `{}` at `{}`: {error:?}. +Maybe it was newly added?"#, + job.name, parent + ); + None + } + }; + let metrics_current = download_job_metrics(&job.name, current)?; + jobs.insert( + job.name.clone(), + JobMetrics { parent: metrics_parent, current: metrics_current }, + ); + } + Ok(jobs) +} + +fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result { + let url = get_metrics_url(job_name, sha); + let mut response = ureq::get(&url).call()?; + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "Cannot fetch metrics from {url}: {}\n{}", + response.status(), + response.body_mut().read_to_string()? + )); + } + let data: JsonRoot = response + .body_mut() + .read_json() + .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?; + Ok(data) +} + +fn get_metrics_url(job_name: &str, sha: &str) -> String { + let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" }; + format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json") +} + +fn aggregate_test_diffs( + jobs: &HashMap, +) -> anyhow::Result> { + let mut job_diffs = vec![]; + + // Aggregate test suites + for (name, metrics) in jobs { + if let Some(parent) = &metrics.parent { + let tests_parent = aggregate_tests(parent); + let tests_current = aggregate_tests(&metrics.current); + let test_diffs = calculate_test_diffs(tests_parent, tests_current); + if !test_diffs.is_empty() { + job_diffs.push((name.clone(), test_diffs)); + } + } + } + + // Aggregate jobs with the same diff, as often the same diff will appear in many jobs + let job_diffs: HashMap, Vec> = + job_diffs.into_iter().fold(HashMap::new(), |mut acc, (job, diffs)| { + acc.entry(diffs).or_default().push(job); + acc + }); + + Ok(job_diffs + .into_iter() + .map(|(test_diffs, jobs)| AggregatedTestDiffs { jobs, test_diffs }) + .collect()) +} + +fn calculate_test_diffs( + reference: TestSuiteData, + current: TestSuiteData, +) -> Vec<(Test, TestOutcomeDiff)> { + let mut diffs = vec![]; + for (test, outcome) in ¤t.tests { + match reference.tests.get(test) { + Some(before) => { + if before != outcome { + diffs.push(( + test.clone(), + TestOutcomeDiff::ChangeOutcome { + before: before.clone(), + after: outcome.clone(), + }, + )); + } + } + None => diffs.push((test.clone(), TestOutcomeDiff::Added(outcome.clone()))), + } + } + for (test, outcome) in &reference.tests { + if !current.tests.contains_key(test) { + diffs.push((test.clone(), TestOutcomeDiff::Missing { before: outcome.clone() })); + } + } + + diffs +} + +/// Represents a difference in the outcome of tests between a base and a current commit. +#[derive(Debug)] +struct AggregatedTestDiffs { + /// All jobs that had the exact same test diffs. + jobs: Vec, + test_diffs: Vec<(Test, TestOutcomeDiff)>, +} + +#[derive(Eq, PartialEq, Hash, Debug)] +enum TestOutcomeDiff { + ChangeOutcome { before: TestOutcome, after: TestOutcome }, + Missing { before: TestOutcome }, + Added(TestOutcome), +} + +/// Aggregates test suite executions from all bootstrap invocations in a given CI job. +#[derive(Default)] +struct TestSuiteData { + tests: HashMap, +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone)] +struct Test { + name: String, +} + +/// Extracts all tests from the passed metrics and map them to their outcomes. +fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { + let mut tests = HashMap::new(); + let test_suites = get_test_suites(&metrics); + for suite in test_suites { + for test in &suite.tests { + let test_entry = Test { name: normalize_test_name(&test.name) }; + tests.insert(test_entry, test.outcome.clone()); + } + } + TestSuiteData { tests } +} + +/// Normalizes Windows-style path delimiters to Unix-style paths. +fn normalize_test_name(name: &str) -> String { + name.replace('\\', "/") +} + +/// Prints test changes in Markdown format to stdout. +fn report_test_changes(mut diffs: Vec) { + println!("## Test differences"); + if diffs.is_empty() { + println!("No test diffs found"); + return; + } + + // Sort diffs in decreasing order by diff count + diffs.sort_by_key(|entry| Reverse(entry.test_diffs.len())); + + fn format_outcome(outcome: &TestOutcome) -> String { + match outcome { + TestOutcome::Passed => "pass".to_string(), + TestOutcome::Failed => "fail".to_string(), + TestOutcome::Ignored { ignore_reason } => { + let reason = match ignore_reason { + Some(reason) => format!(" ({reason})"), + None => String::new(), + }; + format!("ignore{reason}") + } + } + } + + fn format_diff(diff: &TestOutcomeDiff) -> String { + match diff { + TestOutcomeDiff::ChangeOutcome { before, after } => { + format!("{} -> {}", format_outcome(before), format_outcome(after)) + } + TestOutcomeDiff::Missing { before } => { + format!("{} -> [missing]", format_outcome(before)) + } + TestOutcomeDiff::Added(outcome) => { + format!("[missing] -> {}", format_outcome(outcome)) + } + } + } + + let max_diff_count = 10; + let max_job_count = 5; + let max_test_count = 10; + + for diff in diffs.iter().take(max_diff_count) { + let mut jobs = diff.jobs.clone(); + jobs.sort(); + + let jobs = jobs.iter().take(max_job_count).map(|j| format!("`{j}`")).collect::>(); + + let extra_jobs = diff.jobs.len().saturating_sub(max_job_count); + let suffix = if extra_jobs > 0 { + format!(" (and {extra_jobs} {})", pluralize("other", extra_jobs)) + } else { + String::new() + }; + println!("- {}{suffix}", jobs.join(",")); + + let extra_tests = diff.test_diffs.len().saturating_sub(max_test_count); + for (test, outcome_diff) in diff.test_diffs.iter().take(max_test_count) { + println!(" - {}: {}", test.name, format_diff(&outcome_diff)); + } + if extra_tests > 0 { + println!(" - (and {extra_tests} additional {})", pluralize("tests", extra_tests)); + } + } + + let extra_diffs = diffs.len().saturating_sub(max_diff_count); + if extra_diffs > 0 { + println!("\n(and {extra_diffs} additional {})", pluralize("diff", extra_diffs)); + } +} + +fn pluralize(text: &str, count: usize) -> String { + if count == 1 { text.to_string() } else { format!("{text}s") } +} diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs index 2386413ed6b1d..8548602b31cb7 100644 --- a/src/ci/citool/src/metrics.rs +++ b/src/ci/citool/src/metrics.rs @@ -105,17 +105,21 @@ struct TestSuiteRecord { failed: u64, } +fn test_metadata_name(metadata: &TestSuiteMetadata) -> String { + match metadata { + TestSuiteMetadata::CargoPackage { crates, stage, .. } => { + format!("{} (stage {stage})", crates.join(", ")) + } + TestSuiteMetadata::Compiletest { suite, stage, .. } => { + format!("{suite} (stage {stage})") + } + } +} + fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap { let mut records: BTreeMap = BTreeMap::new(); for suite in suites { - let name = match &suite.metadata { - TestSuiteMetadata::CargoPackage { crates, stage, .. } => { - format!("{} (stage {stage})", crates.join(", ")) - } - TestSuiteMetadata::Compiletest { suite, stage, .. } => { - format!("{suite} (stage {stage})") - } - }; + let name = test_metadata_name(&suite.metadata); let record = records.entry(name).or_default(); for test in &suite.tests { match test.outcome { @@ -134,7 +138,7 @@ fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap Vec<&TestSuite> { +pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> { fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) { for node in nodes { match node { From ec3cde249f5b5a8406dcdf6b8abc702e86e6e56b Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 7 Mar 2025 19:05:03 +0800 Subject: [PATCH 10/19] Apply `--cfg windows_raw_dylib` for bootstrap tools too This is already applied for rustc/std tools. This is needed to make `windows` crates avoid trying to depend on a generated `windows.0.xx.0.lib`. --- src/bootstrap/src/core/builder/cargo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index d1d52d82eaa0f..12dd40d14e9bf 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -597,7 +597,7 @@ impl Builder<'_> { // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native // library unnecessary. This can be removed when windows-rs enables raw-dylib // unconditionally. - if let Mode::Rustc | Mode::ToolRustc = mode { + if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode { rustflags.arg("--cfg=windows_raw_dylib"); } From bd884d8043b9ebd4e2bbae0e31bc4780d2e26c6a 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 20:10:49 +0800 Subject: [PATCH 11/19] Prevent `rmake.rs` from using any nightly/unstable features --- src/tools/compiletest/src/runtest/run_make.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 8900752bd4be8..073116933bdb6 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -105,6 +105,11 @@ impl TestCx<'_> { .expect("stage0 rustc is required to run run-make tests"); let mut rustc = Command::new(&stage0_rustc); rustc + // `rmake.rs` **must** be buildable by a stable compiler, it may not use *any* unstable + // library or compiler features. Here, we force the stage 0 rustc to consider itself as + // a stable-channel compiler via `RUSTC_BOOTSTRAP=-1` to prevent *any* unstable + // library/compiler usages, even if stage 0 rustc is *actually* a nightly rustc. + .env("RUSTC_BOOTSTRAP", "-1") .arg("-o") .arg(&recipe_bin) // Specify library search paths for `run_make_support`. From da57f1418f0e302e43c757c7f93cad688a895e57 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 19:17:40 +0800 Subject: [PATCH 12/19] Fix `issue-107495-archive-permissions` to not rely on `rustc_private` --- tests/run-make/issue-107495-archive-permissions/rmake.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index f210b7c737b43..5d7c8a49bcc9b 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -1,7 +1,5 @@ -#![feature(rustc_private)] - #[cfg(unix)] -extern crate libc; +use run_make_support::libc; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; From 9befcfd0f4671675341e770c5bb3bf696c7aa670 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 19:37:10 +0800 Subject: [PATCH 13/19] Fix `cross-lang-lto` to not use `path_file_prefix` --- tests/run-make/cross-lang-lto/rmake.rs | 15 ++++++++++----- .../issue-107495-archive-permissions/rmake.rs | 5 ++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/run-make/cross-lang-lto/rmake.rs b/tests/run-make/cross-lang-lto/rmake.rs index dc376b561e43e..50d37460d8dbb 100644 --- a/tests/run-make/cross-lang-lto/rmake.rs +++ b/tests/run-make/cross-lang-lto/rmake.rs @@ -3,8 +3,6 @@ // -Clinker-plugin-lto. // See https://github.com/rust-lang/rust/pull/50000 -#![feature(path_file_prefix)] - use std::path::PathBuf; use run_make_support::{ @@ -92,10 +90,17 @@ fn check_bitcode(instructions: LibBuild) { llvm_ar().extract().arg(&instructions.output).run(); } - for object in shallow_find_files(cwd(), |path| { - has_prefix(path, instructions.output.file_prefix().unwrap().to_str().unwrap()) + let objects = shallow_find_files(cwd(), |path| { + let mut output_path = instructions.output.clone(); + output_path.set_extension(""); + has_prefix(path, output_path.file_name().unwrap().to_str().unwrap()) && has_extension(path, "o") - }) { + }); + assert!(!objects.is_empty()); + println!("objects: {:#?}", objects); + + for object in objects { + println!("reading bitcode: {}", object.display()); // All generated object files should be LLVM bitcode files - this will fail otherwise. llvm_bcanalyzer().input(object).run(); } diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index 5d7c8a49bcc9b..228cfb0864e7b 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -1,10 +1,9 @@ -#[cfg(unix)] -use run_make_support::libc; - #[cfg(unix)] use std::os::unix::fs::PermissionsExt; use std::path::Path; +#[cfg(unix)] +use run_make_support::libc; use run_make_support::{aux_build, rfs}; fn main() { From d47e5a371bb3a4353587e95bf4ee271a273d1326 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 20:01:49 +0800 Subject: [PATCH 14/19] Temporarily depend on `os_pipe` in `run-make-support` and re-export it For `broken-pipe-no-ice` until std `anonymous_pipe` stabilizes. --- Cargo.lock | 11 +++++++++++ src/tools/run-make-support/Cargo.toml | 4 ++++ src/tools/run-make-support/src/lib.rs | 2 ++ 3 files changed, 17 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 72f2d4f6cd390..5886b96b72813 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2526,6 +2526,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "overload" version = "0.1.1" @@ -3050,6 +3060,7 @@ dependencies = [ "gimli 0.31.1", "libc", "object 0.36.7", + "os_pipe", "regex", "serde_json", "similar", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 15ed03ad5c23d..f9beffec75085 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -14,5 +14,9 @@ build_helper = { path = "../../build_helper" } serde_json = "1.0" libc = "0.2" +# FIXME(#137532): replace `os_pipe` with `anonymous_pipe` once it stabilizes and +# reaches beta. +os_pipe = "1.2.1" + [lib] crate-type = ["lib", "dylib"] diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index d40ec9c4116e7..c846a2d53e5f0 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -40,6 +40,8 @@ pub use bstr; pub use gimli; pub use libc; pub use object; +// FIXME(#137532): replace with std `anonymous_pipe` once it stabilizes and reaches beta. +pub use os_pipe; pub use regex; pub use serde_json; pub use similar; From 224f287f3226a89eff12ff3cbf0ca4e64c96d351 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 20:02:44 +0800 Subject: [PATCH 15/19] Fix `broken-pipe-no-ice` to not depend on unstable `anonymous_pipe` feature --- tests/run-make/broken-pipe-no-ice/rmake.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/run-make/broken-pipe-no-ice/rmake.rs b/tests/run-make/broken-pipe-no-ice/rmake.rs index 54d13b62f4a0e..3e54b576fd421 100644 --- a/tests/run-make/broken-pipe-no-ice/rmake.rs +++ b/tests/run-make/broken-pipe-no-ice/rmake.rs @@ -11,12 +11,12 @@ // Internal Compiler Error strangely, but it doesn't even go through normal diagnostic infra. Very // strange. -#![feature(anonymous_pipe)] - use std::io::Read; use std::process::{Command, Stdio}; -use run_make_support::env_var; +// FIXME(#137532): replace `os_pipe` dependency with std `anonymous_pipe` once that stabilizes and +// reaches beta. +use run_make_support::{env_var, os_pipe}; #[derive(Debug, PartialEq)] enum Binary { @@ -25,7 +25,7 @@ enum Binary { } fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) { - let (reader, writer) = std::io::pipe().unwrap(); + let (reader, writer) = os_pipe::pipe().unwrap(); drop(reader); // close read-end cmd.stdout(writer).stderr(Stdio::piped()); From c9c572cd927b223d22280ca606086d64d20b733b 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 20:14:25 +0800 Subject: [PATCH 16/19] Document that `rmake.rs`/`run-make-support` may not use unstable features --- src/doc/rustc-dev-guide/src/tests/compiletest.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 2905e470fabd3..a6996e3982215 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -415,6 +415,10 @@ Compiletest directives like `//@ only-` or `//@ ignore-` are supported in `rmake.rs`, like in UI tests. However, revisions or building auxiliary via directives are not currently supported. +`rmake.rs` and `run-make-support` may *not* use any nightly/unstable features, +as they must be compilable by a stage 0 rustc that may be a beta or even stable +rustc. + #### Quickly check if `rmake.rs` tests can be compiled You can quickly check if `rmake.rs` tests can be compiled without having to From bbc80a819b542d751450bd82208438de5754ee47 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Mar 2025 17:09:36 +0000 Subject: [PATCH 17/19] Delay bug for negative auto trait rather than ICEing --- .../src/check/always_applicable.rs | 5 +++- tests/ui/auto-traits/ungated-impl.rs | 7 ++++++ tests/ui/auto-traits/ungated-impl.stderr | 23 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/ui/auto-traits/ungated-impl.rs create mode 100644 tests/ui/auto-traits/ungated-impl.stderr diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index ba5b61d3fce0b..8a841a1155674 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -124,7 +124,10 @@ pub(crate) fn check_negative_auto_trait_impl<'tcx>( // be implemented here to handle non-ADT rigid types. Ok(()) } else { - span_bug!(tcx.def_span(impl_def_id), "incoherent impl of negative auto trait"); + Err(tcx.dcx().span_delayed_bug( + tcx.def_span(impl_def_id), + "incoherent impl of negative auto trait", + )) } } } diff --git a/tests/ui/auto-traits/ungated-impl.rs b/tests/ui/auto-traits/ungated-impl.rs new file mode 100644 index 0000000000000..d46b4b01af9c7 --- /dev/null +++ b/tests/ui/auto-traits/ungated-impl.rs @@ -0,0 +1,7 @@ +auto trait MyTrait {} +//~^ ERROR auto traits are experimental and possibly buggy + +impl !MyTrait for *mut T {} +//~^ ERROR negative trait bounds are not fully implemented + +fn main() {} diff --git a/tests/ui/auto-traits/ungated-impl.stderr b/tests/ui/auto-traits/ungated-impl.stderr new file mode 100644 index 0000000000000..9d10d46a90283 --- /dev/null +++ b/tests/ui/auto-traits/ungated-impl.stderr @@ -0,0 +1,23 @@ +error[E0658]: auto traits are experimental and possibly buggy + --> $DIR/ungated-impl.rs:1:1 + | +LL | auto trait MyTrait {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #13231 for more information + = help: add `#![feature(auto_traits)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: negative trait bounds are not fully implemented; use marker types for now + --> $DIR/ungated-impl.rs:4:9 + | +LL | impl !MyTrait for *mut T {} + | ^^^^^^^^ + | + = note: see issue #68318 for more information + = help: add `#![feature(negative_impls)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 06eecca264f4f793b5ad94af318f5688b739a168 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Fri, 7 Mar 2025 12:36:33 -0800 Subject: [PATCH 18/19] Allow anyone to relabel CI-spurious-* --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 7114c7ab27bc4..305b99ad5ecd0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -18,6 +18,7 @@ allow-unauthenticated = [ "WG-*", "-Z*", "beta-nominated", + "CI-spurious-*", "const-hack", "llvm-*", "needs-fcp", From e0c2636df57e65fc7aa0ff940210e0af03b9bba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 7 Mar 2025 21:48:54 +0100 Subject: [PATCH 19/19] remove clones --- compiler/rustc_builtin_macros/src/autodiff.rs | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6d9c35756574e..7b5c4a159b0c5 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -286,7 +286,7 @@ mod llvm_enzyme { let orig_annotatable: Annotatable = match item { Annotatable::Item(ref mut iitem) => { if !iitem.attrs.iter().any(|a| a.id == attr.id) { - iitem.attrs.push(attr.clone()); + iitem.attrs.push(attr); } if !iitem.attrs.iter().any(|a| a.id == inline_never.id) { iitem.attrs.push(inline_never.clone()); @@ -295,7 +295,7 @@ mod llvm_enzyme { } Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => { if !assoc_item.attrs.iter().any(|a| a.id == attr.id) { - assoc_item.attrs.push(attr.clone()); + assoc_item.attrs.push(attr); } if !assoc_item.attrs.iter().any(|a| a.id == inline_never.id) { assoc_item.attrs.push(inline_never.clone()); @@ -322,7 +322,7 @@ mod llvm_enzyme { let d_annotatable = if is_impl { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); let d_fn = P(ast::AssocItem { - attrs: thin_vec![d_attr.clone(), inline_never], + attrs: thin_vec![d_attr, inline_never], id: ast::DUMMY_NODE_ID, span, vis, @@ -332,12 +332,8 @@ mod llvm_enzyme { }); Annotatable::AssocItem(d_fn, Impl) } else { - let mut d_fn = ecx.item( - span, - d_ident, - thin_vec![d_attr.clone(), inline_never], - ItemKind::Fn(asdf), - ); + let mut d_fn = + ecx.item(span, d_ident, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); d_fn.vis = vis; Annotatable::Item(d_fn) }; @@ -446,7 +442,7 @@ mod llvm_enzyme { if primal_ret && n_active == 0 && x.mode.is_rev() { // We only have the primal ret. - body.stmts.push(ecx.stmt_expr(black_box_primal_call.clone())); + body.stmts.push(ecx.stmt_expr(black_box_primal_call)); return body; } @@ -471,7 +467,7 @@ mod llvm_enzyme { if primal_ret { // We have both primal ret and active floats. // primal ret is first, by construction. - exprs.push(primal_call.clone()); + exprs.push(primal_call); } // Now construct default placeholder for each active float. @@ -538,16 +534,11 @@ mod llvm_enzyme { return body; } [arg] => { - ret = ecx.expr_call( - new_decl_span, - blackbox_call_expr.clone(), - thin_vec![arg.clone()], - ); + ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![arg.clone()]); } args => { let ret_tuple: P = ecx.expr_tuple(span, args.into()); - ret = - ecx.expr_call(new_decl_span, blackbox_call_expr.clone(), thin_vec![ret_tuple]); + ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![ret_tuple]); } } assert!(has_ret(&d_sig.decl.output)); @@ -567,7 +558,7 @@ mod llvm_enzyme { let args: ThinVec<_> = idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); let self_expr = ecx.expr_self(span); - ecx.expr_method_call(span, self_expr, primal, args.clone()) + ecx.expr_method_call(span, self_expr, primal, args) } else { let args: ThinVec<_> = idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect();