From eada6195185411f2cf9c00a3f2a9c5d9f2dea4d3 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:44:51 +0100 Subject: [PATCH 01/22] ci: use ubuntu 24 for free arm runner --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index c08104e796b9..bc4ae7d51f6c 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -50,7 +50,7 @@ runners: - &job-aarch64-linux # Free some disk space to avoid running out of space during the build. free_disk: true - os: ubuntu-22.04-arm + os: ubuntu-24.04-arm - &job-aarch64-linux-8c os: ubuntu-22.04-arm64-8core-32gb From 4e36f46464d6473ca1f2c8612b7aed4ea0141bcf Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 12:40:27 -0800 Subject: [PATCH 02/22] core: Apply unsafe_op_in_unsafe_fn --- library/core/src/alloc/global.rs | 2 +- library/core/src/hint.rs | 2 +- library/core/src/intrinsics/mod.rs | 8 ++++---- library/core/src/mem/maybe_uninit.rs | 4 ++-- library/core/src/mem/transmutability.rs | 2 +- library/core/src/ptr/const_ptr.rs | 4 ++-- library/core/src/ptr/mut_ptr.rs | 4 ++-- library/core/src/ptr/non_null.rs | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 8f48af24557d..5bf6f143b4f8 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -70,7 +70,7 @@ use crate::{cmp, ptr}; /// { /// return null_mut(); /// }; -/// self.arena.get().cast::().add(allocated) +/// unsafe { self.arena.get().cast::().add(allocated) } /// } /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} /// } diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 520b9941ae45..76afb3b8e20c 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -52,7 +52,7 @@ use crate::{intrinsics, ub_checks}; /// // Safety: `divisor` can't be zero because of `prepare_inputs`, /// // but the compiler does not know about this. We *promise* /// // that we always call `prepare_inputs`. -/// std::hint::unreachable_unchecked() +/// unsafe { std::hint::unreachable_unchecked() } /// } /// // The compiler would normally introduce a check here that prevents /// // a division by zero. However, if `divisor` was zero, the branch diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 6c9c6d0edc23..99c42f3626e7 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1703,12 +1703,12 @@ pub const fn forget(_: T) { /// ``` /// struct R<'a>(&'a i32); /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { -/// std::mem::transmute::, R<'static>>(r) +/// unsafe { std::mem::transmute::, R<'static>>(r) } /// } /// /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) /// -> &'b mut R<'c> { -/// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) +/// unsafe { std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) } /// } /// ``` /// @@ -4498,11 +4498,11 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// /// // SAFETY: Our precondition ensures the source is aligned and valid, /// // and `Vec::with_capacity` ensures that we have usable space to write them. -/// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); } /// /// // SAFETY: We created it with this much capacity earlier, /// // and the previous `copy` has initialized these elements. -/// dst.set_len(elts); +/// unsafe { dst.set_len(elts); } /// dst /// } /// ``` diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 0d8c3ef906bf..9ab05ca89d13 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -98,7 +98,7 @@ use crate::{fmt, intrinsics, ptr, slice}; /// /// unsafe fn make_vec(out: *mut Vec) { /// // `write` does not drop the old contents, which is important. -/// out.write(vec![1, 2, 3]); +/// unsafe { out.write(vec![1, 2, 3]); } /// } /// /// let mut v = MaybeUninit::uninit(); @@ -844,7 +844,7 @@ impl MaybeUninit { /// # #![allow(unexpected_cfgs)] /// use std::mem::MaybeUninit; /// - /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] } + /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { unsafe { *buf = [0; 1024] } } /// # #[cfg(FALSE)] /// extern "C" { /// /// Initializes *all* the bytes of the input buffer. diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 6a4f84c849cb..7b920d7a777c 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -32,7 +32,7 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; /// src: ManuallyDrop::new(src), /// }; /// -/// let dst = transmute.dst; +/// let dst = unsafe { transmute.dst }; /// /// ManuallyDrop::into_inner(dst) /// } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 0c6eaf60d048..974946a7818d 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -724,13 +724,13 @@ impl *const T { /// that their safety preconditions are met: /// ```rust /// # #![feature(ptr_sub_ptr)] - /// # unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool { + /// # unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool { unsafe { /// ptr.sub_ptr(origin) == count /// # && /// origin.add(count) == ptr /// # && /// ptr.sub(count) == origin - /// # } + /// # } } /// ``` /// /// # Safety diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index d1b0104c0fa9..94ebd0d2522e 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -896,13 +896,13 @@ impl *mut T { /// that their safety preconditions are met: /// ```rust /// # #![feature(ptr_sub_ptr)] - /// # unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool { + /// # unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool { unsafe { /// ptr.sub_ptr(origin) == count /// # && /// origin.add(count) == ptr /// # && /// ptr.sub(count) == origin - /// # } + /// # } } /// ``` /// /// # Safety diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index d93069d384ed..f4ac00062d73 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -857,13 +857,13 @@ impl NonNull { /// that their safety preconditions are met: /// ```rust /// # #![feature(ptr_sub_ptr)] - /// # unsafe fn blah(ptr: std::ptr::NonNull, origin: std::ptr::NonNull, count: usize) -> bool { + /// # unsafe fn blah(ptr: std::ptr::NonNull, origin: std::ptr::NonNull, count: usize) -> bool { unsafe { /// ptr.sub_ptr(origin) == count /// # && /// origin.add(count) == ptr /// # && /// ptr.sub(count) == origin - /// # } + /// # } } /// ``` /// /// # Safety From e13928de93c142d2b4052d28d7ed0aaca192c0ee Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 12:42:29 -0800 Subject: [PATCH 03/22] panic_abort: Apply unsafe_op_in_unsafe_fn --- library/panic_abort/src/android.rs | 18 +++++++++-------- library/panic_abort/src/lib.rs | 31 +++++++++++++++++++++--------- library/panic_abort/src/zkvm.rs | 4 +++- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs index 47c22834597d..1cc2077d14bd 100644 --- a/library/panic_abort/src/android.rs +++ b/library/panic_abort/src/android.rs @@ -16,9 +16,10 @@ type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> (); // Weakly resolve the symbol for android_set_abort_message. This function is only available // for API >= 21. pub(crate) unsafe fn android_set_abort_message(payload: &mut dyn PanicPayload) { - let func_addr = + let func_addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, ANDROID_SET_ABORT_MESSAGE.as_ptr() as *const libc::c_char) - as usize; + as usize + }; if func_addr == 0 { return; } @@ -37,13 +38,14 @@ pub(crate) unsafe fn android_set_abort_message(payload: &mut dyn PanicPayload) { // Allocate a new buffer to append the null byte. let size = msg.len() + 1usize; - let buf = libc::malloc(size) as *mut libc::c_char; + let buf = unsafe { libc::malloc(size) as *mut libc::c_char }; if buf.is_null() { return; // allocation failure } - copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len()); - buf.add(msg.len()).write(0); - - let func = transmute::(func_addr); - func(buf); + unsafe { + copy_nonoverlapping(msg.as_ptr(), buf as *mut u8, msg.len()); + buf.add(msg.len()).write(0); + let func = transmute::(func_addr); + func(buf); + } } diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 7718d68aef8e..b2ad0f4ac3d0 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -15,6 +15,7 @@ #![feature(staged_api)] #![feature(rustc_attrs)] #![allow(internal_features)] +#![deny(unsafe_op_in_unsafe_fn)] #[cfg(target_os = "android")] mod android; @@ -36,16 +37,22 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { // Android has the ability to attach a message as part of the abort. #[cfg(target_os = "android")] - android::android_set_abort_message(_payload); + unsafe { + android::android_set_abort_message(_payload); + } #[cfg(target_os = "zkvm")] - zkvm::zkvm_set_abort_message(_payload); + unsafe { + zkvm::zkvm_set_abort_message(_payload); + } - abort(); + unsafe { + abort(); + } cfg_if::cfg_if! { if #[cfg(any(unix, target_os = "solid_asp3"))] { unsafe fn abort() -> ! { - libc::abort(); + unsafe { libc::abort(); } } } else if #[cfg(any(target_os = "hermit", all(target_vendor = "fortanix", target_env = "sgx"), @@ -57,7 +64,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { unsafe extern "C" { pub fn __rust_abort() -> !; } - __rust_abort(); + unsafe { __rust_abort(); } } } else if #[cfg(all(windows, not(miri)))] { // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 @@ -75,11 +82,17 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { const FAST_FAIL_FATAL_APP_EXIT: usize = 7; cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); + unsafe { + core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); + } } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { - core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); + unsafe { + core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); + } } else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { - core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); + unsafe { + core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack)); + } } else { core::intrinsics::abort(); } @@ -93,7 +106,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { } unsafe fn abort() -> ! { - teeos::TEE_Panic(1); + unsafe { teeos::TEE_Panic(1); } } } else { unsafe fn abort() -> ! { diff --git a/library/panic_abort/src/zkvm.rs b/library/panic_abort/src/zkvm.rs index 11150eafd0b8..7b1e89c6a8e6 100644 --- a/library/panic_abort/src/zkvm.rs +++ b/library/panic_abort/src/zkvm.rs @@ -20,5 +20,7 @@ pub(crate) unsafe fn zkvm_set_abort_message(payload: &mut dyn PanicPayload) { fn sys_panic(msg_ptr: *const u8, len: usize) -> !; } - sys_panic(msg.as_ptr(), msg.len()); + unsafe { + sys_panic(msg.as_ptr(), msg.len()); + } } From 331911e699f91bc890074fa42374c63dbea06c44 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 12:44:32 -0800 Subject: [PATCH 04/22] panic_unwind: Apply unsafe_op_in_unsafe_fn --- library/panic_unwind/src/emcc.rs | 60 ++++++++++++----------- library/panic_unwind/src/gcc.rs | 40 +++++++-------- library/panic_unwind/src/hermit.rs | 8 ++- library/panic_unwind/src/lib.rs | 9 ++-- library/panic_unwind/src/miri.rs | 4 +- library/panic_unwind/src/seh.rs | 78 ++++++++++++++++-------------- 6 files changed, 110 insertions(+), 89 deletions(-) diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index 4140b004ad13..1569c26c9de4 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -71,42 +71,46 @@ pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box { ptr: *mut u8, is_rust_panic: bool, } - let catch_data = &*(ptr as *mut CatchData); + unsafe { + let catch_data = &*(ptr as *mut CatchData); - let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception; - if !catch_data.is_rust_panic { - super::__rust_foreign_exception(); - } + let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception; + if !catch_data.is_rust_panic { + super::__rust_foreign_exception(); + } - let canary = (&raw const (*adjusted_ptr).canary).read(); - if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) { - super::__rust_foreign_exception(); - } + let canary = (&raw const (*adjusted_ptr).canary).read(); + if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) { + super::__rust_foreign_exception(); + } - let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::Relaxed); - if was_caught { - // Since cleanup() isn't allowed to panic, we just abort instead. - intrinsics::abort(); + let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::Relaxed); + if was_caught { + // Since cleanup() isn't allowed to panic, we just abort instead. + intrinsics::abort(); + } + let out = (*adjusted_ptr).data.take().unwrap(); + __cxa_end_catch(); + out } - let out = (*adjusted_ptr).data.take().unwrap(); - __cxa_end_catch(); - out } pub(crate) unsafe fn panic(data: Box) -> u32 { - let exception = __cxa_allocate_exception(mem::size_of::()) as *mut Exception; - if exception.is_null() { - return uw::_URC_FATAL_PHASE1_ERROR as u32; + unsafe { + let exception = __cxa_allocate_exception(mem::size_of::()) as *mut Exception; + if exception.is_null() { + return uw::_URC_FATAL_PHASE1_ERROR as u32; + } + ptr::write( + exception, + Exception { + canary: &EXCEPTION_TYPE_INFO, + caught: AtomicBool::new(false), + data: Some(data), + }, + ); + __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup); } - ptr::write( - exception, - Exception { - canary: &EXCEPTION_TYPE_INFO, - caught: AtomicBool::new(false), - data: Some(data), - }, - ); - __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup); } extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void { diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index e478f6c5fc86..5f95870069dc 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -69,7 +69,7 @@ pub(crate) unsafe fn panic(data: Box) -> u32 { cause: data, }); let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception; - return uw::_Unwind_RaiseException(exception_param) as u32; + return unsafe { uw::_Unwind_RaiseException(exception_param) as u32 }; extern "C" fn exception_cleanup( _unwind_code: uw::_Unwind_Reason_Code, @@ -83,26 +83,28 @@ pub(crate) unsafe fn panic(data: Box) -> u32 { } pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box { - let exception = ptr as *mut uw::_Unwind_Exception; - if (*exception).exception_class != RUST_EXCEPTION_CLASS { - uw::_Unwind_DeleteException(exception); - super::__rust_foreign_exception(); - } + unsafe { + let exception = ptr as *mut uw::_Unwind_Exception; + if (*exception).exception_class != RUST_EXCEPTION_CLASS { + uw::_Unwind_DeleteException(exception); + super::__rust_foreign_exception(); + } - let exception = exception.cast::(); - // Just access the canary field, avoid accessing the entire `Exception` as - // it can be a foreign Rust exception. - let canary = (&raw const (*exception).canary).read(); - if !ptr::eq(canary, &CANARY) { - // A foreign Rust exception, treat it slightly differently from other - // foreign exceptions, because call into `_Unwind_DeleteException` will - // call into `__rust_drop_panic` which produces a confusing - // "Rust panic must be rethrown" message. - super::__rust_foreign_exception(); - } + let exception = exception.cast::(); + // Just access the canary field, avoid accessing the entire `Exception` as + // it can be a foreign Rust exception. + let canary = (&raw const (*exception).canary).read(); + if !ptr::eq(canary, &CANARY) { + // A foreign Rust exception, treat it slightly differently from other + // foreign exceptions, because call into `_Unwind_DeleteException` will + // call into `__rust_drop_panic` which produces a confusing + // "Rust panic must be rethrown" message. + super::__rust_foreign_exception(); + } - let exception = Box::from_raw(exception as *mut Exception); - exception.cause + let exception = Box::from_raw(exception as *mut Exception); + exception.cause + } } // Rust's exception class identifier. This is used by personality routines to diff --git a/library/panic_unwind/src/hermit.rs b/library/panic_unwind/src/hermit.rs index 9719c1334152..8f4562d07fc4 100644 --- a/library/panic_unwind/src/hermit.rs +++ b/library/panic_unwind/src/hermit.rs @@ -9,12 +9,16 @@ pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box { unsafe extern "C" { fn __rust_abort() -> !; } - __rust_abort(); + unsafe { + __rust_abort(); + } } pub(crate) unsafe fn panic(_data: Box) -> u32 { unsafe extern "C" { fn __rust_abort() -> !; } - __rust_abort(); + unsafe { + __rust_abort(); + } } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 45e2a466b4df..1111c2009b3d 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -27,6 +27,7 @@ #![allow(internal_features)] #![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] #![warn(unreachable_pub)] +#![deny(unsafe_op_in_unsafe_fn)] use alloc::boxed::Box; use core::any::Any; @@ -87,14 +88,16 @@ unsafe extern "C" { #[rustc_std_internal_symbol] #[allow(improper_ctypes_definitions)] pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) { - Box::into_raw(imp::cleanup(payload)) + unsafe { Box::into_raw(imp::cleanup(payload)) } } // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[rustc_std_internal_symbol] pub unsafe fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32 { - let payload = Box::from_raw(payload.take_box()); + unsafe { + let payload = Box::from_raw(payload.take_box()); - imp::panic(payload) + imp::panic(payload) + } } diff --git a/library/panic_unwind/src/miri.rs b/library/panic_unwind/src/miri.rs index ec48b1105ab4..d6d4af8218d3 100644 --- a/library/panic_unwind/src/miri.rs +++ b/library/panic_unwind/src/miri.rs @@ -16,11 +16,11 @@ pub(crate) unsafe fn panic(payload: Box) -> u32 { // The payload we pass to `miri_start_unwind` will be exactly the argument we get // in `cleanup` below. So we just box it up once, to get something pointer-sized. let payload_box: Payload = Box::new(payload); - miri_start_unwind(Box::into_raw(payload_box) as *mut u8) + unsafe { miri_start_unwind(Box::into_raw(payload_box) as *mut u8) } } pub(crate) unsafe fn cleanup(payload_box: *mut u8) -> Box { // Recover the underlying `Box`. - let payload_box: Payload = Box::from_raw(payload_box as *mut _); + let payload_box: Payload = unsafe { Box::from_raw(payload_box as *mut _) }; *payload_box } diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index c8dfddf821e6..3a95b940221c 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -268,9 +268,11 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { macro_rules! define_cleanup { ($abi:tt $abi2:tt) => { unsafe extern $abi fn exception_cleanup(e: *mut Exception) { - if let Exception { data: Some(b), .. } = e.read() { - drop(b); - super::__rust_drop_panic(); + unsafe { + if let Exception { data: Some(b), .. } = e.read() { + drop(b); + super::__rust_drop_panic(); + } } } unsafe extern $abi2 fn exception_copy( @@ -322,45 +324,51 @@ pub(crate) unsafe fn panic(data: Box) -> u32 { // // In any case, we basically need to do something like this until we can // express more operations in statics (and we may never be able to). - atomic_store_seqcst( - (&raw mut THROW_INFO.pmfnUnwind).cast(), - ptr_t::new(exception_cleanup as *mut u8).raw(), - ); - atomic_store_seqcst( - (&raw mut THROW_INFO.pCatchableTypeArray).cast(), - ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(), - ); - atomic_store_seqcst( - (&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), - ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(), - ); - atomic_store_seqcst( - (&raw mut CATCHABLE_TYPE.pType).cast(), - ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(), - ); - atomic_store_seqcst( - (&raw mut CATCHABLE_TYPE.copyFunction).cast(), - ptr_t::new(exception_copy as *mut u8).raw(), - ); + unsafe { + atomic_store_seqcst( + (&raw mut THROW_INFO.pmfnUnwind).cast(), + ptr_t::new(exception_cleanup as *mut u8).raw(), + ); + atomic_store_seqcst( + (&raw mut THROW_INFO.pCatchableTypeArray).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(), + ); + atomic_store_seqcst( + (&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(), + ); + atomic_store_seqcst( + (&raw mut CATCHABLE_TYPE.pType).cast(), + ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(), + ); + atomic_store_seqcst( + (&raw mut CATCHABLE_TYPE.copyFunction).cast(), + ptr_t::new(exception_copy as *mut u8).raw(), + ); + } unsafe extern "system-unwind" { fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; } - _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _); + unsafe { + _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _); + } } pub(crate) unsafe fn cleanup(payload: *mut u8) -> Box { - // A null payload here means that we got here from the catch (...) of - // __rust_try. This happens when a non-Rust foreign exception is caught. - if payload.is_null() { - super::__rust_foreign_exception(); + unsafe { + // A null payload here means that we got here from the catch (...) of + // __rust_try. This happens when a non-Rust foreign exception is caught. + if payload.is_null() { + super::__rust_foreign_exception(); + } + let exception = payload as *mut Exception; + let canary = (&raw const (*exception).canary).read(); + if !core::ptr::eq(canary, &raw const TYPE_DESCRIPTOR) { + // A foreign Rust exception. + super::__rust_foreign_exception(); + } + (*exception).data.take().unwrap() } - let exception = payload as *mut Exception; - let canary = (&raw const (*exception).canary).read(); - if !core::ptr::eq(canary, &raw const TYPE_DESCRIPTOR) { - // A foreign Rust exception. - super::__rust_foreign_exception(); - } - (*exception).data.take().unwrap() } From 0484d23465eb8b977e7549cd8ee7b12c7a62b54d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 12:45:31 -0800 Subject: [PATCH 05/22] unwind: Apply unsafe_op_in_unsafe_fn --- library/unwind/src/lib.rs | 1 + library/unwind/src/libunwind.rs | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 2650b273a4db..761f92484462 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -9,6 +9,7 @@ )] #![allow(internal_features)] #![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] +#![deny(unsafe_op_in_unsafe_fn)] // Force libc to be included even if unused. This is required by many platforms. #[cfg(not(all(windows, target_env = "msvc")))] diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 62165f8a2003..1a640bbde71d 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -218,36 +218,38 @@ if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "a pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word { let mut val: _Unwind_Word = core::ptr::null(); - _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - (&raw mut val) as *mut c_void); + unsafe { _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, + (&raw mut val) as *mut c_void); } val } pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { let mut value = value; - _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - (&raw mut value) as *mut c_void); + unsafe { _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, + (&raw mut value) as *mut c_void); } } pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word { - let val = _Unwind_GetGR(ctx, UNWIND_IP_REG); + let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) }; val.map_addr(|v| v & !1) } pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word) { // Propagate thumb bit to instruction pointer - let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG).addr() & 1; + let thumb_state = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG).addr() & 1 }; let value = value.map_addr(|v| v | thumb_state); - _Unwind_SetGR(ctx, UNWIND_IP_REG, value); + unsafe { _Unwind_SetGR(ctx, UNWIND_IP_REG, value); } } pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int) -> _Unwind_Word { - *ip_before_insn = 0; - _Unwind_GetIP(ctx) + unsafe { + *ip_before_insn = 0; + _Unwind_GetIP(ctx) + } } // This function also doesn't exist on Android or ARM/Linux, so make it a no-op From d5f0aa49e711db038d7bd30ceb76ba260de8b1fd Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Feb 2025 14:15:19 -0800 Subject: [PATCH 06/22] Fix safety of windows uwp functions These functions were changed to be safe in https://github.com/rust-lang/rust/pull/127763, but this particular UWP version was missed. Otherwise this causes unnecessary unsafe block warnings/errors. --- library/std/src/sys/pal/windows/stack_overflow_uwp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs index 9e9b3efaf1b1..6f1ea12fc1e0 100644 --- a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs +++ b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs @@ -1,4 +1,4 @@ #![cfg_attr(test, allow(dead_code))] -pub unsafe fn reserve_stack() {} -pub unsafe fn init() {} +pub fn reserve_stack() {} +pub fn init() {} From 4f4ea35a6969cdbebfdf96778e8a9d49bea8c9ce Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 12:51:22 -0800 Subject: [PATCH 07/22] std: Apply unsafe_op_in_unsafe_fn --- library/std/src/alloc.rs | 8 ++++---- library/std/src/sys/pal/teeos/thread.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 3936ed057e6e..99d105a2454a 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -20,11 +20,11 @@ //! //! unsafe impl GlobalAlloc for MyAllocator { //! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { -//! System.alloc(layout) +//! unsafe { System.alloc(layout) } //! } //! //! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { -//! System.dealloc(ptr, layout) +//! unsafe { System.dealloc(ptr, layout) } //! } //! } //! @@ -102,7 +102,7 @@ pub use alloc_crate::alloc::*; /// /// unsafe impl GlobalAlloc for Counter { /// unsafe fn alloc(&self, layout: Layout) -> *mut u8 { -/// let ret = System.alloc(layout); +/// let ret = unsafe { System.alloc(layout) }; /// if !ret.is_null() { /// ALLOCATED.fetch_add(layout.size(), Relaxed); /// } @@ -110,7 +110,7 @@ pub use alloc_crate::alloc::*; /// } /// /// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { -/// System.dealloc(ptr, layout); +/// unsafe { System.dealloc(ptr, layout); } /// ALLOCATED.fetch_sub(layout.size(), Relaxed); /// } /// } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index c779c5f3ed89..e3b4908f8586 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -56,7 +56,7 @@ impl Thread { } }; - let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); + let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) }; // Note: if the thread creation fails and this assert fails, then p will // be leaked. However, an alternative design could cause double-free // which is clearly worse. From 80a7eb1c09b97f7ad1a68f538d2d9b04ded7da2b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 12:52:22 -0800 Subject: [PATCH 08/22] proc_macro: Apply unsafe_op_in_unsafe_fn --- library/proc_macro/src/bridge/closure.rs | 2 +- library/proc_macro/src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/proc_macro/src/bridge/closure.rs b/library/proc_macro/src/bridge/closure.rs index 524fdf53d6b7..e0e688434dce 100644 --- a/library/proc_macro/src/bridge/closure.rs +++ b/library/proc_macro/src/bridge/closure.rs @@ -19,7 +19,7 @@ struct Env; impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { fn from(f: &'a mut F) -> Self { unsafe extern "C" fn call R>(env: *mut Env, arg: A) -> R { - (*(env as *mut _ as *mut F))(arg) + unsafe { (*(env as *mut _ as *mut F))(arg) } } Closure { call: call::, env: f as *mut _ as *mut Env, _marker: PhantomData } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 6611ce30a1b0..d9141eab5919 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -33,6 +33,7 @@ #![deny(ffi_unwind_calls)] #![warn(rustdoc::unescaped_backticks)] #![warn(unreachable_pub)] +#![deny(unsafe_op_in_unsafe_fn)] #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] From 28307554125f60440fcbf8076eee86f2ec1e4c1d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 14:26:15 -0800 Subject: [PATCH 09/22] Bless miri tests after applying unsafe_op_in_unsafe_fn --- src/tools/miri/tests/fail/panic/panic_abort1.rs | 2 +- src/tools/miri/tests/fail/panic/panic_abort2.rs | 2 +- src/tools/miri/tests/fail/panic/panic_abort3.rs | 2 +- src/tools/miri/tests/fail/panic/panic_abort4.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.rs b/src/tools/miri/tests/fail/panic/panic_abort1.rs index 300bfa32ecbd..7552c7b7e808 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort1.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.rs b/src/tools/miri/tests/fail/panic/panic_abort2.rs index 5d6913505770..624f99335455 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort2.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.rs b/src/tools/miri/tests/fail/panic/panic_abort3.rs index 25afc315628e..d1435b55946c 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort3.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.rs b/src/tools/miri/tests/fail/panic/panic_abort4.rs index 025b51a5cf51..54b9c9cbfdb0 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort4.rs @@ -1,6 +1,6 @@ //@error-in-other-file: the program aborted execution //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();" //@compile-flags: -C panic=abort fn main() { From 6ec3cf9abc15368df705b65e20e7e753d565fe71 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 15 Feb 2025 11:53:08 +0100 Subject: [PATCH 10/22] Load all builtin targets at once instead of one by one This should give us some performance improvements as we won't need to do the lookup for the _currently_ 287 targets we have. --- compiler/rustc_session/src/config/cfg.rs | 8 ++------ compiler/rustc_target/src/spec/mod.rs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index d586f913335e..1078757d09e9 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -29,7 +29,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS; use rustc_span::{Symbol, sym}; -use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTuple}; +use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, Target}; use crate::Session; use crate::config::{CrateType, FmtDebug}; @@ -426,11 +426,7 @@ impl CheckCfg { panic!("unable to get all the check-cfg values buckets"); }; - for target in TARGETS - .iter() - .map(|target| Target::expect_builtin(&TargetTuple::from_tuple(target))) - .chain(iter::once(current_target.clone())) - { + for target in Target::builtins().chain(iter::once(current_target.clone())) { values_target_abi.insert(Symbol::intern(&target.options.abi)); values_target_arch.insert(Symbol::intern(&target.arch)); values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 72600225e7a3..2acc4ded5d80 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1662,6 +1662,14 @@ macro_rules! supported_targets { Some(t) } + fn load_all_builtins() -> impl Iterator { + [ + $( targets::$module::target, )+ + ] + .into_iter() + .map(|f| f()) + } + #[cfg(test)] mod tests { // Cannot put this into a separate file without duplication, make an exception. @@ -3360,6 +3368,11 @@ impl Target { } } + /// Load all built-in targets + pub fn builtins() -> impl Iterator { + load_all_builtins() + } + /// Search for a JSON file specifying the given target tuple. /// /// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the From 61a97448e51bafab3f94a7c4ccb5d43c6c97ad22 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 31 Jan 2025 11:55:53 -0700 Subject: [PATCH 11/22] rustdoc: improve refdef handling in the unresolved link lint This commit takes advantage of a feature in pulldown-cmark that makes the list of link definitions available to the consuming application. It produces unresolved link warnings for refdefs that aren't used, and can now produce exact spans for the dest even when it has escapes. --- compiler/rustc_resolve/src/rustdoc.rs | 18 +++- src/librustdoc/html/markdown.rs | 70 +++++++++++++++- tests/rustdoc-ui/intra-doc/weird-syntax.rs | 43 ++++++++-- .../rustdoc-ui/intra-doc/weird-syntax.stderr | 82 ++++++++++++------- 4 files changed, 170 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index fecb97350193..52aaab77ebed 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -7,7 +7,7 @@ use pulldown_cmark::{ use rustc_ast as ast; use rustc_ast::attr::AttributeExt; use rustc_ast::util::comments::beautify_doc_string; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, kw, sym}; @@ -422,9 +422,11 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { ); let mut links = Vec::new(); + let mut refids = FxHashSet::default(); + while let Some(event) = event_iter.next() { match event { - Event::Start(Tag::Link { link_type, dest_url, title: _, id: _ }) + Event::Start(Tag::Link { link_type, dest_url, title: _, id }) if may_be_doc_link(link_type) => { if matches!( @@ -439,6 +441,12 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { links.push(display_text); } } + if matches!( + link_type, + LinkType::Reference | LinkType::Shortcut | LinkType::Collapsed + ) { + refids.insert(id); + } links.push(preprocess_link(&dest_url)); } @@ -446,6 +454,12 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { } } + for (label, refdef) in event_iter.reference_definitions().iter() { + if !refids.contains(label) { + links.push(preprocess_link(&refdef.dest)); + } + } + links } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index bd8eda2fed62..d9e49577d392 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -38,7 +38,7 @@ use std::sync::{Arc, Weak}; use pulldown_cmark::{ BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html, }; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Diag, DiagMessage}; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; @@ -1763,6 +1763,46 @@ pub(crate) fn markdown_links<'md, R>( } }; + let span_for_refdef = |link: &CowStr<'_>, span: Range| { + // We want to underline the link's definition, but `span` will point at the entire refdef. + // Skip the label, then try to find the entire URL. + let mut square_brace_count = 0; + let mut iter = md.as_bytes()[span.start..span.end].iter().copied().enumerate(); + for (_i, c) in &mut iter { + match c { + b':' if square_brace_count == 0 => break, + b'[' => square_brace_count += 1, + b']' => square_brace_count -= 1, + _ => {} + } + } + while let Some((i, c)) = iter.next() { + if c == b'<' { + while let Some((j, c)) = iter.next() { + match c { + b'\\' => { + let _ = iter.next(); + } + b'>' => { + return MarkdownLinkRange::Destination( + i + 1 + span.start..j + span.start, + ); + } + _ => {} + } + } + } else if !c.is_ascii_whitespace() { + while let Some((j, c)) = iter.next() { + if c.is_ascii_whitespace() { + return MarkdownLinkRange::Destination(i + span.start..j + span.start); + } + } + return MarkdownLinkRange::Destination(i + span.start..span.end); + } + } + span_for_link(link, span) + }; + let span_for_offset_backward = |span: Range, open: u8, close: u8| { let mut open_brace = !0; let mut close_brace = !0; @@ -1844,9 +1884,16 @@ pub(crate) fn markdown_links<'md, R>( .into_offset_iter(); let mut links = Vec::new(); + let mut refdefs = FxIndexMap::default(); + for (label, refdef) in event_iter.reference_definitions().iter() { + refdefs.insert(label.to_string(), (false, refdef.dest.to_string(), refdef.span.clone())); + } + for (event, span) in event_iter { match event { - Event::Start(Tag::Link { link_type, dest_url, .. }) if may_be_doc_link(link_type) => { + Event::Start(Tag::Link { link_type, dest_url, id, .. }) + if may_be_doc_link(link_type) => + { let range = match link_type { // Link is pulled from the link itself. LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => { @@ -1856,7 +1903,12 @@ pub(crate) fn markdown_links<'md, R>( LinkType::Inline => span_for_offset_backward(span, b'(', b')'), // Link is pulled from elsewhere in the document. LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => { - span_for_link(&dest_url, span) + if let Some((is_used, dest_url, span)) = refdefs.get_mut(&id[..]) { + *is_used = true; + span_for_refdef(&CowStr::from(&dest_url[..]), span.clone()) + } else { + span_for_link(&dest_url, span) + } } LinkType::Autolink | LinkType::Email => unreachable!(), }; @@ -1873,6 +1925,18 @@ pub(crate) fn markdown_links<'md, R>( } } + for (_label, (is_used, dest_url, span)) in refdefs.into_iter() { + if !is_used + && let Some(link) = preprocess_link(MarkdownLink { + kind: LinkType::Reference, + range: span_for_refdef(&CowStr::from(&dest_url[..]), span), + link: dest_url, + }) + { + links.push(link); + } + } + links } diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs index ca18842fb21c..d2a922b2b624 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.rs +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -117,24 +117,49 @@ pub struct WLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace; // References -/// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected //~ERROR link -/// in Markdown for not being URL-shaped enough. -/// -/// [cln]: Clone() //~ERROR link +/// The [cln][] link here is going to be unresolved, because `Clone()` gets +//~^ ERROR link +/// rejected in Markdown for not being URL-shaped enough. +/// [cln]: Clone() +//~^ ERROR link pub struct LinkToCloneWithParensInReference; -/// The [cln][] link here is going to be unresolved, because `struct@Clone` gets //~ERROR link -/// rejected in Markdown for not being URL-shaped enough. +/// The [cln][] link here is going to produce a good inline suggestion /// -/// [cln]: struct@Clone //~ERROR link +/// [cln]: struct@Clone +//~^ ERROR link pub struct LinkToCloneWithWrongPrefix; -/// The [cln][] link here will produce a plain text suggestion //~ERROR link +/// The [cln][] link here will produce a good inline suggestion /// /// [cln]: Clone\(\) +//~^ ERROR link pub struct LinkToCloneWithEscapedParensInReference; -/// The [cln][] link here will produce a plain text suggestion //~ERROR link +/// The [cln][] link here will produce a good inline suggestion /// /// [cln]: struct\@Clone +//~^ ERROR link pub struct LinkToCloneWithEscapedAtsInReference; + + +/// This link reference definition isn't used, but since it is still parsed, +/// it should still produce a warning. +/// +/// [cln]: struct\@Clone +//~^ ERROR link +pub struct UnusedLinkToCloneReferenceDefinition; + +/// +/// +/// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the +//~^ ERROR link +/// `(__unsafe_unretained)` NSWindow associated with the window, if you want +/// to wrap an existing window. +/// - [`SDL_PROP_WINDOW_CREATE_COCOA_VIEW_POINTER`]: the `(__unsafe_unretained)` +/// NSView associated with the window, defaults to `[window contentView]` +pub fn a() {} +#[allow(nonstandard_style)] +pub struct SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER; +#[allow(nonstandard_style)] +pub struct SDL_PROP_WINDOW_CREATE_COCOA_VIEW_POINTER; diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index 1381c1b31ebb..ad813f0f9b62 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -230,7 +230,7 @@ LL | /// [w](Clone \)) error: unresolved link to `cln` --> $DIR/weird-syntax.rs:120:10 | -LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected +LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets | ^^^ no item named `cln` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -243,37 +243,61 @@ LL | /// [cln]: Clone() | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: unresolved link to `cln` - --> $DIR/weird-syntax.rs:126:10 - | -LL | /// The [cln][] link here is going to be unresolved, because `struct@Clone` gets - | ^^^ no item named `cln` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - -error: unresolved link to `cln` - --> $DIR/weird-syntax.rs:129:6 +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:129:12 | LL | /// [cln]: struct@Clone - | ^^^ no item named `cln` in scope + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [cln]: struct@Clone +LL + /// [cln]: trait@Clone + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:135:12 + | +LL | /// [cln]: Clone\(\) + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not a function + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [cln]: Clone\(\) +LL + /// [cln]: trait@Clone + | + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:141:12 + | +LL | /// [cln]: struct\@Clone + | ^^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [cln]: struct\@Clone +LL + /// [cln]: trait@struct + | + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:149:12 + | +LL | /// [cln]: struct\@Clone + | ^^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [cln]: struct\@Clone +LL + /// [cln]: trait@struct + | + +error: unresolved link to `the` + --> $DIR/weird-syntax.rs:155:56 + | +LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the + | ^^^ no item named `the` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: unresolved link to `Clone` - --> $DIR/weird-syntax.rs:132:9 - | -LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolves to the trait `Clone`, which is not a function - | - = help: to link to the trait, prefix with `trait@`: trait@Clone - -error: incompatible link kind for `Clone` - --> $DIR/weird-syntax.rs:137:9 - | -LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolved to a trait, which is not a struct - | - = help: to link to the trait, prefix with `trait@`: trait@Clone - -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors From 4d551dd754477bb81ddef0829121ca90c8a8b286 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 31 Jan 2025 14:28:44 -0700 Subject: [PATCH 12/22] docs: fix broken intra-doc links that never worked --- library/alloc/src/boxed.rs | 4 ---- library/core/src/task/wake.rs | 7 ++----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1ea7b731461e..4b124b5a3b38 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1053,7 +1053,6 @@ impl Box { /// ``` /// /// [memory layout]: self#memory-layout - /// [`Layout`]: crate::Layout #[stable(feature = "box_raw", since = "1.4.0")] #[inline] #[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"] @@ -1108,7 +1107,6 @@ impl Box { /// ``` /// /// [memory layout]: self#memory-layout - /// [`Layout`]: crate::Layout #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] #[inline] #[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"] @@ -1165,7 +1163,6 @@ impl Box { /// ``` /// /// [memory layout]: self#memory-layout - /// [`Layout`]: crate::Layout #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_box", issue = "92521")] #[inline] @@ -1219,7 +1216,6 @@ impl Box { /// ``` /// /// [memory layout]: self#memory-layout - /// [`Layout`]: crate::Layout #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")] #[rustc_const_unstable(feature = "const_box", issue = "92521")] diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 4c51ca0a5e43..3f57b04753a6 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -40,17 +40,14 @@ impl RawWaker { /// of the `vtable` as the first parameter. /// /// It is important to consider that the `data` pointer must point to a - /// thread safe type such as an `[Arc]` + /// thread safe type such as an `Arc` /// when used to construct a [`Waker`]. This restriction is lifted when /// constructing a [`LocalWaker`], which allows using types that do not implement - /// [Send] + [Sync] like `[Rc]`. + /// [Send] + [Sync] like `Rc`. /// /// The `vtable` customizes the behavior of a `Waker` which gets created /// from a `RawWaker`. For each operation on the `Waker`, the associated /// function in the `vtable` of the underlying `RawWaker` will be called. - /// - /// [`Arc`]: std::sync::Arc - /// [`Rc`]: std::rc::Rc #[inline] #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] From 17071ff8a5bef6e0f801e7d6b73529d0e1053b81 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 15 Feb 2025 21:49:50 +0000 Subject: [PATCH 13/22] Rework name_regions to not rely on reverse scc graph for non-member-constrain usages --- .../src/diagnostics/region_errors.rs | 30 +++++++++++++++---- .../src/region_infer/opaque_types.rs | 8 ++++- .../ui/borrowck/alias-liveness/name-region.rs | 13 ++++++++ .../alias-liveness/name-region.stderr | 14 +++++++++ 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 tests/ui/borrowck/alias-liveness/name-region.rs create mode 100644 tests/ui/borrowck/alias-liveness/name-region.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b7e2510e035a..df79da76bcea 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -14,7 +14,10 @@ use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; -use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::fold::fold_regions; +use rustc_middle::ty::{ + self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, +}; use rustc_span::{Ident, Span, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::nice_region_error::{ @@ -183,6 +186,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } + /// Map the regions in the type to named regions, where possible. + fn name_regions(&self, tcx: TyCtxt<'tcx>, ty: T) -> T + where + T: TypeFoldable>, + { + fold_regions(tcx, ty, |region, _| match *region { + ty::ReVar(vid) => self.to_error_region(vid).unwrap_or(region), + _ => region, + }) + } + /// Returns `true` if a closure is inferred to be an `FnMut` closure. fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref() @@ -314,7 +328,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let type_test_span = type_test.span; if let Some(lower_bound_region) = lower_bound_region { - let generic_ty = self.regioncx.name_regions( + let generic_ty = self.name_regions( self.infcx.tcx, type_test.generic_kind.to_ty(self.infcx.tcx), ); @@ -323,7 +337,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.body.source.def_id().expect_local(), type_test_span, Some(origin), - self.regioncx.name_regions(self.infcx.tcx, type_test.generic_kind), + self.name_regions(self.infcx.tcx, type_test.generic_kind), lower_bound_region, )); } else { @@ -354,9 +368,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => { - let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); - let named_key = self.regioncx.name_regions(self.infcx.tcx, key); - let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); + let named_ty = + self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, hidden_ty); + let named_key = + self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, key); + let named_region = self + .regioncx + .name_regions_for_member_constraint(self.infcx.tcx, member_region); let diag = unexpected_hidden_region_diagnostic( self.infcx, self.mir_def_id(), diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 9c19f8b3ad82..54f9e82dbb82 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -204,7 +204,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// that the regions produced are in fact equal to the named region they are /// replaced with. This is fine because this function is only to improve the /// region names in error messages. - pub(crate) fn name_regions(&self, tcx: TyCtxt<'tcx>, ty: T) -> T + /// + /// This differs from `MirBorrowckCtxt::name_regions` since it is particularly + /// lax with mapping region vids that are *shorter* than a universal region to + /// that universal region. This is useful for member region constraints since + /// we want to suggest a universal region name to capture even if it's technically + /// not equal to the error region. + pub(crate) fn name_regions_for_member_constraint(&self, tcx: TyCtxt<'tcx>, ty: T) -> T where T: TypeFoldable>, { diff --git a/tests/ui/borrowck/alias-liveness/name-region.rs b/tests/ui/borrowck/alias-liveness/name-region.rs new file mode 100644 index 000000000000..9545a9eed2f1 --- /dev/null +++ b/tests/ui/borrowck/alias-liveness/name-region.rs @@ -0,0 +1,13 @@ +// Make sure we don't ICE when trying to name the regions that appear in the alias +// of the type test error. + +trait AnotherTrait { + type Ty2<'a>; +} + +fn test_alias(_: &'static T::Ty2<'_>) { + let _: &'static T::Ty2<'_>; + //~^ ERROR the associated type `::Ty2<'_>` may not live long enough +} + +fn main() {} diff --git a/tests/ui/borrowck/alias-liveness/name-region.stderr b/tests/ui/borrowck/alias-liveness/name-region.stderr new file mode 100644 index 000000000000..9a5dd711c68e --- /dev/null +++ b/tests/ui/borrowck/alias-liveness/name-region.stderr @@ -0,0 +1,14 @@ +error[E0310]: the associated type `::Ty2<'_>` may not live long enough + --> $DIR/name-region.rs:9:12 + | +LL | let _: &'static T::Ty2<'_>; + | ^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `::Ty2<'_>` must be valid for the static lifetime... + | ...so that the type `::Ty2<'_>` will meet its required lifetime bounds + | + = help: consider adding an explicit lifetime bound `::Ty2<'_>: 'static`... + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0310`. From 7e35729bfc2bbc0942ce8929d3c4d28cee7ca040 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 15 Feb 2025 22:39:56 -0800 Subject: [PATCH 14/22] Don't project into `NonNull` when dropping a `Box` --- compiler/rustc_middle/src/mir/tcx.rs | 14 ++- .../rustc_mir_transform/src/elaborate_drop.rs | 30 +++++- .../src/elaborate_drops.rs | 4 + compiler/rustc_mir_transform/src/patch.rs | 8 ++ compiler/rustc_mir_transform/src/shim.rs | 3 + .../mir-opt/box_expr.main.ElaborateDrops.diff | 8 +- ...artial_move.maybe_move.ElaborateDrops.diff | 94 +++++++++++++++++++ tests/mir-opt/box_partial_move.rs | 17 ++++ 8 files changed, 168 insertions(+), 10 deletions(-) create mode 100644 tests/mir-opt/box_partial_move.maybe_move.ElaborateDrops.diff create mode 100644 tests/mir-opt/box_partial_move.rs diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index af23c8b2ea76..862f78d72598 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -86,6 +86,14 @@ impl<'tcx> PlaceTy<'tcx> { } } + pub fn multi_projection_ty( + self, + tcx: TyCtxt<'tcx>, + elems: &[PlaceElem<'tcx>], + ) -> PlaceTy<'tcx> { + elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem)) + } + /// Convenience wrapper around `projection_ty_core` for /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. @@ -167,11 +175,7 @@ impl<'tcx> Place<'tcx> { where D: HasLocalDecls<'tcx>, { - projection - .iter() - .fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, &elem| { - place_ty.projection_ty(tcx, elem) - }) + PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection) } pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx> diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index ed4903017f35..2de55e38052e 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -89,6 +89,7 @@ pub(crate) trait DropElaborator<'a, 'tcx>: fmt::Debug { // Accessors + fn patch_ref(&self) -> &MirPatch<'tcx>; fn patch(&mut self) -> &mut MirPatch<'tcx>; fn body(&self) -> &'a Body<'tcx>; fn tcx(&self) -> TyCtxt<'tcx>; @@ -180,7 +181,14 @@ where { #[instrument(level = "trace", skip(self), ret)] fn place_ty(&self, place: Place<'tcx>) -> Ty<'tcx> { - place.ty(self.elaborator.body(), self.tcx()).ty + if place.local < self.elaborator.body().local_decls.next_index() { + place.ty(self.elaborator.body(), self.tcx()).ty + } else { + // We don't have a slice with all the locals, since some are in the patch. + tcx::PlaceTy::from_ty(self.elaborator.patch_ref().local_ty(place.local)) + .multi_projection_ty(self.elaborator.tcx(), place.projection) + .ty + } } fn tcx(&self) -> TyCtxt<'tcx> { @@ -410,12 +418,26 @@ where let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::ZERO, unique_ty); let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::ZERO, nonnull_ty); - let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::ZERO, ptr_ty); - let interior = self.tcx().mk_place_deref(ptr_place); + let ptr_local = self.new_temp(ptr_ty); + + let interior = self.tcx().mk_place_deref(Place::from(ptr_local)); let interior_path = self.elaborator.deref_subpath(self.path); - self.drop_subpath(interior, interior_path, succ, unwind) + let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind); + + let setup_bbd = BasicBlockData { + statements: vec![self.assign( + Place::from(ptr_local), + Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty), + )], + terminator: Some(Terminator { + kind: TerminatorKind::Goto { target: do_drop_bb }, + source_info: self.source_info, + }), + is_cleanup: unwind.is_cleanup(), + }; + self.elaborator.patch().new_block(setup_bbd) } #[instrument(level = "debug", ret)] diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 2d74fcff415e..ab6aafab446b 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -138,6 +138,10 @@ impl InitializationData<'_, '_> { impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> { type Path = MovePathIndex; + fn patch_ref(&self) -> &MirPatch<'tcx> { + &self.patch + } + fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch } diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index 72cd9c224f64..b4f6fa514a48 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -166,6 +166,14 @@ impl<'tcx> MirPatch<'tcx> { Local::new(index) } + /// Returns the type of a local that's newly-added in the patch. + pub(crate) fn local_ty(&self, local: Local) -> Ty<'tcx> { + let local = local.as_usize(); + assert!(local < self.next_local); + let new_local_idx = self.new_locals.len() - (self.next_local - local); + self.new_locals[new_local_idx].ty + } + pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { let block = BasicBlock::new(self.patch_map.len()); debug!("MirPatch: new_block: {:?}: {:?}", block, data); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index e8d86bad9873..34074a84e28b 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -350,6 +350,9 @@ impl fmt::Debug for DropShimElaborator<'_, '_> { impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { type Path = (); + fn patch_ref(&self) -> &MirPatch<'tcx> { + &self.patch + } fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch } diff --git a/tests/mir-opt/box_expr.main.ElaborateDrops.diff b/tests/mir-opt/box_expr.main.ElaborateDrops.diff index ec40fac2894e..827dc6ac7aef 100644 --- a/tests/mir-opt/box_expr.main.ElaborateDrops.diff +++ b/tests/mir-opt/box_expr.main.ElaborateDrops.diff @@ -12,6 +12,7 @@ let mut _7: std::boxed::Box; + let mut _8: &mut std::boxed::Box; + let mut _9: (); ++ let mut _10: *const S; scope 1 { debug x => _1; } @@ -68,7 +69,7 @@ bb8 (cleanup): { - drop(_5) -> [return: bb9, unwind terminate(cleanup)]; -+ goto -> bb11; ++ goto -> bb12; } bb9 (cleanup): { @@ -82,6 +83,11 @@ + + bb11 (cleanup): { + goto -> bb10; ++ } ++ ++ bb12 (cleanup): { ++ _10 = copy ((_5.0: std::ptr::Unique).0: std::ptr::NonNull) as *const S (Transmute); ++ goto -> bb11; } } diff --git a/tests/mir-opt/box_partial_move.maybe_move.ElaborateDrops.diff b/tests/mir-opt/box_partial_move.maybe_move.ElaborateDrops.diff new file mode 100644 index 000000000000..f090795e8865 --- /dev/null +++ b/tests/mir-opt/box_partial_move.maybe_move.ElaborateDrops.diff @@ -0,0 +1,94 @@ +- // MIR for `maybe_move` before ElaborateDrops ++ // MIR for `maybe_move` after ElaborateDrops + + fn maybe_move(_1: bool, _2: Box) -> Option { + debug cond => _1; + debug thing => _2; + let mut _0: std::option::Option; + let mut _3: bool; + let mut _4: std::string::String; ++ let mut _5: bool; ++ let mut _6: &mut std::boxed::Box; ++ let mut _7: (); ++ let mut _8: &mut std::boxed::Box; ++ let mut _9: (); ++ let mut _10: *const std::string::String; + + bb0: { ++ _5 = const false; ++ _5 = const true; + StorageLive(_3); + _3 = copy _1; + switchInt(move _3) -> [0: bb3, otherwise: bb1]; + } + + bb1: { + StorageLive(_4); ++ _5 = const false; + _4 = move (*_2); + _0 = Option::::Some(move _4); +- drop(_4) -> [return: bb2, unwind: bb6]; ++ goto -> bb2; + } + + bb2: { + StorageDead(_4); + goto -> bb4; + } + + bb3: { + _0 = Option::::None; + goto -> bb4; + } + + bb4: { + StorageDead(_3); +- drop(_2) -> [return: bb5, unwind continue]; ++ goto -> bb14; + } + + bb5: { + return; + } + + bb6 (cleanup): { +- drop(_2) -> [return: bb7, unwind terminate(cleanup)]; ++ goto -> bb7; + } + + bb7 (cleanup): { + resume; ++ } ++ ++ bb8: { ++ goto -> bb5; ++ } ++ ++ bb9: { ++ _6 = &mut _2; ++ _7 = as Drop>::drop(move _6) -> [return: bb8, unwind: bb7]; ++ } ++ ++ bb10 (cleanup): { ++ _8 = &mut _2; ++ _9 = as Drop>::drop(move _8) -> [return: bb7, unwind terminate(cleanup)]; ++ } ++ ++ bb11: { ++ goto -> bb13; ++ } ++ ++ bb12: { ++ drop((*_10)) -> [return: bb9, unwind: bb10]; ++ } ++ ++ bb13: { ++ switchInt(copy _5) -> [0: bb9, otherwise: bb12]; ++ } ++ ++ bb14: { ++ _10 = copy ((_2.0: std::ptr::Unique).0: std::ptr::NonNull) as *const std::string::String (Transmute); ++ goto -> bb11; + } + } + diff --git a/tests/mir-opt/box_partial_move.rs b/tests/mir-opt/box_partial_move.rs new file mode 100644 index 000000000000..5cbd242986f5 --- /dev/null +++ b/tests/mir-opt/box_partial_move.rs @@ -0,0 +1,17 @@ +//@ test-mir-pass: ElaborateDrops +//@ needs-unwind + +#![feature(rustc_attrs, liballoc_internals)] + +// EMIT_MIR box_partial_move.maybe_move.ElaborateDrops.diff +fn maybe_move(cond: bool, thing: Box) -> Option { + // CHECK-LABEL: fn maybe_move( + // CHECK: let mut [[PTR:_[0-9]+]]: *const std::string::String; + // CHECK: [[PTR]] = copy ((_2.0: std::ptr::Unique).0: std::ptr::NonNull) as *const std::string::String (Transmute); + // CHECK: drop((*[[PTR]])) + if cond { Some(*thing) } else { None } +} + +fn main() { + maybe_move(false, Box::new("hello".to_string())); +} From 6bdf3407b4b5356e02afd0bfaca43839789d4a67 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 14 Feb 2025 11:43:18 +0530 Subject: [PATCH 15/22] add docs to cc-detect --- src/bootstrap/src/utils/cc_detect.rs | 31 +++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 45797c1276c5..411ab07bbe14 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -29,6 +29,7 @@ use crate::core::config::TargetSelection; use crate::utils::exec::{BootstrapCommand, command}; use crate::{Build, CLang, GitRepo}; +/// Finds archiver tool for the given target if possible. /// FIXME(onur-ozkan): This logic should be replaced by calling into the `cc` crate. fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option { if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace('-', "_"))) { @@ -58,6 +59,7 @@ fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option cc::Build { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false) @@ -84,6 +86,12 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { cfg } +/// Probes for C and C++ compilers and configures the corresponding entries in the [`Build`] +/// structure. +/// +/// This function determines which targets need a C compiler (and, if needed, a C++ compiler) +/// by combining the primary build target, host targets, and any additional targets. For +/// each target, it calls [`find_target`] to configure the necessary compiler tools. pub fn find(build: &Build) { let targets: HashSet<_> = match build.config.cmd { // We don't need to check cross targets for these commands. @@ -112,6 +120,11 @@ pub fn find(build: &Build) { } } +/// Probes and configures the C and C++ compilers for a single target. +/// +/// This function uses both user-specified configuration (from `config.toml`) and auto-detection +/// logic to determine the correct C/C++ compilers for the target. It also determines the appropriate +/// archiver (`ar`) and sets up additional compilation flags (both handled and unhandled). pub fn find_target(build: &Build, target: TargetSelection) { let mut cfg = new_cc_build(build, target); let config = build.config.target_config.get(&target); @@ -172,6 +185,8 @@ pub fn find_target(build: &Build, target: TargetSelection) { } } +/// Determines the default compiler for a given target and language when not explicitly +/// configured in `config.toml`. fn default_compiler( cfg: &mut cc::Build, compiler: Language, @@ -248,6 +263,12 @@ fn default_compiler( } } +/// Constructs the path to the Android NDK compiler for the given target triple and language. +/// +/// This helper function transform the target triple by converting certain architecture names +/// (for example, translating "arm" to "arm7a"), appends the minimum API level (hardcoded as "21" +/// for NDK r26d), and then constructs the full path based on the provided NDK directory and host +/// platform. pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> PathBuf { let mut triple_iter = triple.split('-'); let triple_translated = if let Some(arch) = triple_iter.next() { @@ -277,7 +298,11 @@ pub(crate) fn ndk_compiler(compiler: Language, triple: &str, ndk: &Path) -> Path ndk.join("toolchains").join("llvm").join("prebuilt").join(host_tag).join("bin").join(compiler) } -/// The target programming language for a native compiler. +/// Representing the target programming language for a native compiler. +/// +/// This enum is used to indicate whether a particular compiler is intended for C or C++. +/// It also provides helper methods for obtaining the standard executable names for GCC and +/// clang-based compilers. #[derive(PartialEq)] pub(crate) enum Language { /// The compiler is targeting C. @@ -287,7 +312,7 @@ pub(crate) enum Language { } impl Language { - /// Obtains the name of a compiler in the GCC collection. + /// Returns the executable name for a GCC compiler corresponding to this language. fn gcc(self) -> &'static str { match self { Language::C => "gcc", @@ -295,7 +320,7 @@ impl Language { } } - /// Obtains the name of a compiler in the clang suite. + /// Returns the executable name for a clang-based compiler corresponding to this language. fn clang(self) -> &'static str { match self { Language::C => "clang", From f6c911ab43226fc6c90ee2bf6c300c4e53566899 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 14 Feb 2025 11:43:34 +0530 Subject: [PATCH 16/22] add unit test for cc-detect --- src/bootstrap/src/utils/cc_detect.rs | 3 + src/bootstrap/src/utils/cc_detect/tests.rs | 254 +++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 src/bootstrap/src/utils/cc_detect/tests.rs diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 411ab07bbe14..1e84a7deff12 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -328,3 +328,6 @@ impl Language { } } } + +#[cfg(test)] +mod tests; diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs new file mode 100644 index 000000000000..006dfe7e5d7b --- /dev/null +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -0,0 +1,254 @@ +use std::path::{Path, PathBuf}; +use std::{env, iter}; + +use super::*; +use crate::core::config::{Target, TargetSelection}; +use crate::{Build, Config, Flags}; + +#[test] +fn test_cc2ar_env_specific() { + let triple = "x86_64-unknown-linux-gnu"; + let key = "AR_x86_64_unknown_linux_gnu"; + env::set_var(key, "custom-ar"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/clang"); + let default_ar = PathBuf::from("default-ar"); + let result = cc2ar(cc, target, default_ar); + env::remove_var(key); + assert_eq!(result, Some(PathBuf::from("custom-ar"))); +} + +#[test] +fn test_cc2ar_musl() { + let triple = "x86_64-unknown-linux-musl"; + env::remove_var("AR_x86_64_unknown_linux_musl"); + env::remove_var("AR"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/clang"); + let default_ar = PathBuf::from("default-ar"); + let result = cc2ar(cc, target, default_ar); + assert_eq!(result, Some(PathBuf::from("ar"))); +} + +#[test] +fn test_cc2ar_openbsd() { + let triple = "x86_64-unknown-openbsd"; + env::remove_var("AR_x86_64_unknown_openbsd"); + env::remove_var("AR"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/cc"); + let default_ar = PathBuf::from("default-ar"); + let result = cc2ar(cc, target, default_ar); + assert_eq!(result, Some(PathBuf::from("ar"))); +} + +#[test] +fn test_cc2ar_vxworks() { + let triple = "armv7-wrs-vxworks"; + env::remove_var("AR_armv7_wrs_vxworks"); + env::remove_var("AR"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/clang"); + let default_ar = PathBuf::from("default-ar"); + let result = cc2ar(cc, target, default_ar); + assert_eq!(result, Some(PathBuf::from("wr-ar"))); +} + +#[test] +fn test_cc2ar_nto_i586() { + let triple = "i586-unknown-nto-something"; + env::remove_var("AR_i586_unknown_nto_something"); + env::remove_var("AR"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/clang"); + let default_ar = PathBuf::from("default-ar"); + let result = cc2ar(cc, target, default_ar); + assert_eq!(result, Some(PathBuf::from("ntox86-ar"))); +} + +#[test] +fn test_cc2ar_nto_aarch64() { + let triple = "aarch64-unknown-nto-something"; + env::remove_var("AR_aarch64_unknown_nto_something"); + env::remove_var("AR"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/clang"); + let default_ar = PathBuf::from("default-ar"); + let result = cc2ar(cc, target, default_ar); + assert_eq!(result, Some(PathBuf::from("ntoaarch64-ar"))); +} + +#[test] +fn test_cc2ar_nto_x86_64() { + let triple = "x86_64-unknown-nto-something"; + env::remove_var("AR_x86_64_unknown_nto_something"); + env::remove_var("AR"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/clang"); + let default_ar = PathBuf::from("default-ar"); + let result = cc2ar(cc, target, default_ar); + assert_eq!(result, Some(PathBuf::from("ntox86_64-ar"))); +} + +#[test] +#[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")] +fn test_cc2ar_nto_unknown() { + let triple = "powerpc-unknown-nto-something"; + env::remove_var("AR_powerpc_unknown_nto_something"); + env::remove_var("AR"); + let target = TargetSelection::from_user(triple); + let cc = Path::new("/usr/bin/clang"); + let default_ar = PathBuf::from("default-ar"); + let _ = cc2ar(cc, target, default_ar); +} + +#[test] +fn test_ndk_compiler_c() { + let ndk_path = PathBuf::from("/ndk"); + let target_triple = "arm-unknown-linux-android"; + let expected_triple_translated = "armv7a-unknown-linux-android"; + let expected_compiler = format!("{}21-{}", expected_triple_translated, Language::C.clang()); + let host_tag = if cfg!(target_os = "macos") { + "darwin-x86_64" + } else if cfg!(target_os = "windows") { + "windows-x86_64" + } else { + "linux-x86_64" + }; + let expected_path = ndk_path + .join("toolchains") + .join("llvm") + .join("prebuilt") + .join(host_tag) + .join("bin") + .join(&expected_compiler); + let result = ndk_compiler(Language::C, target_triple, &ndk_path); + assert_eq!(result, expected_path); +} + +#[test] +fn test_ndk_compiler_cpp() { + let ndk_path = PathBuf::from("/ndk"); + let target_triple = "arm-unknown-linux-android"; + let expected_triple_translated = "armv7a-unknown-linux-android"; + let expected_compiler = + format!("{}21-{}", expected_triple_translated, Language::CPlusPlus.clang()); + let host_tag = if cfg!(target_os = "macos") { + "darwin-x86_64" + } else if cfg!(target_os = "windows") { + "windows-x86_64" + } else { + "linux-x86_64" + }; + let expected_path = ndk_path + .join("toolchains") + .join("llvm") + .join("prebuilt") + .join(host_tag) + .join("bin") + .join(&expected_compiler); + let result = ndk_compiler(Language::CPlusPlus, target_triple, &ndk_path); + assert_eq!(result, expected_path); +} + +#[test] +fn test_language_gcc() { + assert_eq!(Language::C.gcc(), "gcc"); + assert_eq!(Language::CPlusPlus.gcc(), "g++"); +} + +#[test] +fn test_language_clang() { + assert_eq!(Language::C.clang(), "clang"); + assert_eq!(Language::CPlusPlus.clang(), "clang++"); +} + +#[test] +fn test_new_cc_build() { + let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); + let cfg = new_cc_build(&build, target.clone()); + let compiler = cfg.get_compiler(); + assert!(!compiler.path().to_str().unwrap().is_empty(), "Compiler path should not be empty"); +} + +#[test] +fn test_default_compiler_wasi() { + let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let target = TargetSelection::from_user("wasm32-wasi"); + let wasi_sdk = PathBuf::from("/wasi-sdk"); + env::set_var("WASI_SDK_PATH", &wasi_sdk); + let mut cfg = cc::Build::new(); + if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { + let expected = { + let compiler = format!("{}-clang", target.triple); + wasi_sdk.join("bin").join(compiler) + }; + assert_eq!(result, expected); + } else { + panic!( + "default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set" + ); + } + env::remove_var("WASI_SDK_PATH"); +} + +#[test] +fn test_default_compiler_fallback() { + let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); + let mut cfg = cc::Build::new(); + let result = default_compiler(&mut cfg, Language::C, target, &build); + assert!(result.is_none(), "default_compiler should return None for generic targets"); +} + +#[test] +fn test_find_target_with_config() { + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); + let mut target_config = Target::default(); + target_config.cc = Some(PathBuf::from("dummy-cc")); + target_config.cxx = Some(PathBuf::from("dummy-cxx")); + target_config.ar = Some(PathBuf::from("dummy-ar")); + target_config.ranlib = Some(PathBuf::from("dummy-ranlib")); + build.config.target_config.insert(target.clone(), target_config); + find_target(&build, target.clone()); + let binding = build.cc.borrow(); + let cc_tool = binding.get(&target).unwrap(); + assert_eq!(cc_tool.path(), &PathBuf::from("dummy-cc")); + let binding = build.cxx.borrow(); + let cxx_tool = binding.get(&target).unwrap(); + assert_eq!(cxx_tool.path(), &PathBuf::from("dummy-cxx")); + let binding = build.ar.borrow(); + let ar = binding.get(&target).unwrap(); + assert_eq!(ar, &PathBuf::from("dummy-ar")); + let binding = build.ranlib.borrow(); + let ranlib = binding.get(&target).unwrap(); + assert_eq!(ranlib, &PathBuf::from("dummy-ranlib")); +} + +#[test] +fn test_find_target_without_config() { + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); + build.config.target_config.clear(); + find_target(&build, target.clone()); + assert!(build.cc.borrow().contains_key(&target)); + if !target.triple.contains("vxworks") { + assert!(build.cxx.borrow().contains_key(&target)); + } + assert!(build.ar.borrow().contains_key(&target)); +} + +#[test] +fn test_find() { + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu"); + let target2 = TargetSelection::from_user("arm-linux-androideabi"); + build.targets.push(target1.clone()); + build.hosts.push(target2.clone()); + find(&build); + for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.build)) { + assert!(build.cc.borrow().contains_key(t), "CC not set for target {}", t.triple); + } +} From f396a3107507bb1925eba5a429da6adc40a06d61 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 16 Feb 2025 07:49:22 +0000 Subject: [PATCH 17/22] Add an example for std::error::Error --- library/core/src/error.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 33cf2af30b95..69ad7239954a 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -22,6 +22,30 @@ use crate::fmt::{self, Debug, Display, Formatter}; /// accessing that error via [`Error::source()`]. This makes it possible for the /// high-level module to provide its own errors while also revealing some of the /// implementation for debugging. +/// +/// # Example +/// +/// Implementing the `Error` trait only requires that `Debug` and `Display` are implemented too. +/// +/// ``` +/// use std::error::Error; +/// use std::fmt; +/// use std::path::PathBuf; +/// +/// #[derive(Debug)] +/// struct ReadConfigError { +/// path: PathBuf +/// } +/// +/// impl fmt::Display for ReadConfigError { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// let path = self.path.display(); +/// write!(f, "unable to read configuration at {path}") +/// } +/// } +/// +/// impl Error for ReadConfigError {} +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Error")] #[rustc_has_incoherent_inherent_impls] From 8ae3ca98e5c225da22e7ab1a86069098a74cdfe2 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 16 Feb 2025 09:08:24 +0000 Subject: [PATCH 18/22] Fix test that relies on error language --- tests/ui/unpretty/staged-api-invalid-path-108697.rs | 4 ++-- tests/ui/unpretty/staged-api-invalid-path-108697.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/unpretty/staged-api-invalid-path-108697.rs b/tests/ui/unpretty/staged-api-invalid-path-108697.rs index 71bad213576c..8a806b10d9da 100644 --- a/tests/ui/unpretty/staged-api-invalid-path-108697.rs +++ b/tests/ui/unpretty/staged-api-invalid-path-108697.rs @@ -2,8 +2,8 @@ // ICE: tcx.resolutions(()) is not supported for local crate -Zunpretty=mir // on invalid module path with staged_api //@ compile-flags: -Zunpretty=mir -//@ normalize-stderr: "The system cannot find the file specified." -> "No such file or directory" +//@ normalize-stderr: "lol`: .*\(" -> "lol`: $$FILE_NOT_FOUND_MSG (" #![feature(staged_api)] #[path = "lol"] mod foo; -//~^ ERROR couldn't read +//~^ ERROR couldn't read `$DIR/lol` diff --git a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr index e68e19c4dc99..188f4985ded5 100644 --- a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr +++ b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr @@ -1,4 +1,4 @@ -error: couldn't read `$DIR/lol`: No such file or directory (os error 2) +error: couldn't read `$DIR/lol`: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/staged-api-invalid-path-108697.rs:8:1 | LL | mod foo; From 56f8f48e05a0635f28fa293557aa10c0162b8526 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 16 Feb 2025 12:11:25 +0300 Subject: [PATCH 19/22] fix broken `x {doc, build} core` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/doc.rs | 5 +---- src/bootstrap/src/core/builder/mod.rs | 12 ++++++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 479327d63695..84cf99b55402 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -95,7 +95,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").path("library").alias("core") + run.crate_or_deps("sysroot").path("library") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index dedcc139ae19..23bb47dcc586 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -572,10 +572,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.crate_or_deps("sysroot") - .path("library") - .alias("core") - .default_condition(builder.config.docs) + run.crate_or_deps("sysroot").path("library").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index ecec589fc32e..52876c3fb3fd 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -127,10 +127,14 @@ impl RunConfig<'_> { pub fn cargo_crates_in_set(&self) -> Vec { let mut crates = Vec::new(); for krate in &self.paths { - let path = krate.assert_single_path(); - let Some(crate_name) = self.builder.crate_paths.get(&path.path) else { - panic!("missing crate for path {}", path.path.display()) - }; + let path = &krate.assert_single_path().path; + + let crate_name = self + .builder + .crate_paths + .get(path) + .unwrap_or_else(|| panic!("missing crate for path {}", path.display())); + crates.push(crate_name.to_string()); } crates From a6ee2f4af223ff7636c5d55c735fd5bb51c8578f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Sun, 16 Feb 2025 12:21:42 +0100 Subject: [PATCH 20/22] fix musl's CVE-2025-26519 --- src/ci/docker/scripts/musl.sh | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index ece8e6c15c0c..9878bec6fbe8 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -30,6 +30,47 @@ MUSL=musl-1.2.3 # may have been downloaded in a previous run if [ ! -d $MUSL ]; then curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - + + # Apply patches for CVE-2025-26519. At the time of adding these patches no release containing them + # has been published by the musl project, so we just apply them directly on top of the version we + # were distributing already. The patches should be removed once we upgrade to musl >= 1.2.6. + # + # Advisory: https://www.openwall.com/lists/musl/2025/02/13/1 + # + # Patches applied: + # - https://www.openwall.com/lists/musl/2025/02/13/1/1 + # - https://www.openwall.com/lists/musl/2025/02/13/1/2 + # + # ignore-tidy-tab + # ignore-tidy-linelength + patch -p1 -d $MUSL <= 93 || d >= 94) { + c += (0xa1-0x81); + d += 0xa1; +- if (c >= 93 || c>=0xc6-0x81 && d>0x52) ++ if (c > 0xc6-0x81 || c==0xc6-0x81 && d>0x52) + goto ilseq; + if (d-'A'<26) d = d-'A'; + else if (d-'a'<26) d = d-'a'+26; +EOF + patch -p1 -d $MUSL <4) goto ilseq; + *out += k; + *outb -= k; + break; +EOF fi cd $MUSL From 7af46307705f1ab76d3ad50a25cd8137766ea6b3 Mon Sep 17 00:00:00 2001 From: dianne Date: Sun, 16 Feb 2025 19:17:52 -0800 Subject: [PATCH 21/22] add a failing test --- .../auxiliary/migration_lint_macros.rs | 7 +++++++ .../migration_lint.fixed | 5 +++++ .../migration_lint.rs | 5 +++++ .../migration_lint.stderr | 16 +++++++++++++++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs index daa9b7368fd0..b18f87fd5699 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs @@ -9,3 +9,10 @@ macro_rules! mixed_edition_pat { Some(mut $foo) }; } + +#[macro_export] +macro_rules! bind_ref { + ($foo:ident) => { + ref $foo + }; +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed index 0a22e939496e..c81c7d2a87b8 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed @@ -239,4 +239,9 @@ fn main() { assert_type_eq(b, &0u32); assert_type_eq(c, &[0u32]); assert_type_eq(d, 0u32); + + // Test that we use the correct message and suggestion style when pointing inside expansions. + let [migration_lint_macros::bind_ref!(a)] = &[0]; + //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + assert_type_eq(a, &0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs index 7a6f2269d44a..10a23e6f2fa1 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs @@ -239,4 +239,9 @@ fn main() { assert_type_eq(b, &0u32); assert_type_eq(c, &[0u32]); assert_type_eq(d, 0u32); + + // Test that we use the correct message and suggestion style when pointing inside expansions. + let [migration_lint_macros::bind_ref!(a)] = &[0]; + //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + assert_type_eq(a, &0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr index 191800df07a2..33256e8cbb9b 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr @@ -562,5 +562,19 @@ help: make the implied reference patterns explicit LL | let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | + + -error: aborting due to 29 previous errors +error: reference patterns may only be written when the default binding mode is `move` + --> $DIR/migration_lint.rs:244:10 + | +LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ occurs within macro expansion + | + = note: for more information, see +note: matching on a reference type with a non-reference pattern changes the default binding mode + --> $DIR/migration_lint.rs:244:9 + | +LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` + = note: this error originates in the macro `migration_lint_macros::bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 30 previous errors From 82678df0de4369ca79164df93a56733a7538eac1 Mon Sep 17 00:00:00 2001 From: dianne Date: Sun, 16 Feb 2025 19:27:48 -0800 Subject: [PATCH 22/22] bookkeep properly when pointing into macro expansions --- compiler/rustc_hir_typeck/src/pat.rs | 34 ++++++++++--------- .../migration_lint.fixed | 2 +- .../migration_lint.stderr | 6 +++- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7c2a2b3fdf7d..c5c11c2bd253 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2806,31 +2806,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(), }); + let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind { + info.bad_modifiers = true; + // If the user-provided binding modifier doesn't match the default binding mode, we'll + // need to suggest reference patterns, which can affect other bindings. + // For simplicity, we opt to suggest making the pattern fully explicit. + info.suggest_eliding_modes &= + user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not); + "binding modifier" + } else { + info.bad_ref_pats = true; + // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll + // suggest adding them instead, which can affect the types assigned to bindings. + // As such, we opt to suggest making the pattern fully explicit. + info.suggest_eliding_modes = false; + "reference pattern" + }; // Only provide a detailed label if the problematic subpattern isn't from an expansion. // In the case that it's from a macro, we'll add a more detailed note in the emitter. let from_expansion = subpat.span.from_expansion(); let primary_label = if from_expansion { + // We can't suggest eliding modifiers within expansions. + info.suggest_eliding_modes = false; // NB: This wording assumes the only expansions that can produce problematic reference // patterns and bindings are macros. If a desugaring or AST pass is added that can do // so, we may want to inspect the span's source callee or macro backtrace. "occurs within macro expansion".to_owned() } else { - let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind { - info.bad_modifiers |= true; - // If the user-provided binding modifier doesn't match the default binding mode, we'll - // need to suggest reference patterns, which can affect other bindings. - // For simplicity, we opt to suggest making the pattern fully explicit. - info.suggest_eliding_modes &= - user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not); - "binding modifier" - } else { - info.bad_ref_pats |= true; - // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll - // suggest adding them instead, which can affect the types assigned to bindings. - // As such, we opt to suggest making the pattern fully explicit. - info.suggest_eliding_modes = false; - "reference pattern" - }; let dbm_str = match def_br_mutbl { Mutability::Not => "ref", Mutability::Mut => "ref mut", diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed index c81c7d2a87b8..e35896f32ad7 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed @@ -241,7 +241,7 @@ fn main() { assert_type_eq(d, 0u32); // Test that we use the correct message and suggestion style when pointing inside expansions. - let [migration_lint_macros::bind_ref!(a)] = &[0]; + let &[migration_lint_macros::bind_ref!(a)] = &[0]; //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` assert_type_eq(a, &0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr index 33256e8cbb9b..3dd91c86a3b8 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr @@ -562,7 +562,7 @@ help: make the implied reference patterns explicit LL | let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | + + -error: reference patterns may only be written when the default binding mode is `move` +error: binding modifiers may only be written when the default binding mode is `move` --> $DIR/migration_lint.rs:244:10 | LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; @@ -575,6 +575,10 @@ note: matching on a reference type with a non-reference pattern changes the defa LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` = note: this error originates in the macro `migration_lint_macros::bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +help: make the implied reference pattern explicit + | +LL | let &[migration_lint_macros::bind_ref!(a)] = &[0]; + | + error: aborting due to 30 previous errors