From 4e36f46464d6473ca1f2c8612b7aed4ea0141bcf Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 13 Feb 2025 12:40:27 -0800 Subject: [PATCH 01/18] 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 8f48af24557d8..5bf6f143b4f82 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 520b9941ae45d..76afb3b8e20c0 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 6c9c6d0edc235..99c42f3626e7c 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 0d8c3ef906bf0..9ab05ca89d135 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 6a4f84c849cb1..7b920d7a777ca 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 0c6eaf60d0480..974946a7818d7 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 d1b0104c0fa92..94ebd0d2522ee 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 d93069d384edd..f4ac00062d733 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 02/18] 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 47c22834597de..1cc2077d14bd4 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 7718d68aef8e5..b2ad0f4ac3d04 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 11150eafd0b80..7b1e89c6a8e63 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 03/18] 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 4140b004ad13e..1569c26c9de47 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 e478f6c5fc86c..5f95870069dc5 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 9719c13341520..8f4562d07fc4e 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 45e2a466b4df6..1111c2009b3dd 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 ec48b1105ab47..d6d4af8218d31 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 c8dfddf821e68..3a95b940221c2 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(); - } - 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(); + 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() } - (*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 04/18] 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 2650b273a4dbe..761f924844620 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 62165f8a20039..1a640bbde71d7 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 05/18] 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 9e9b3efaf1b14..6f1ea12fc1e06 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 06/18] 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 3936ed057e6e2..99d105a2454a5 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 c779c5f3ed89c..e3b4908f85863 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 07/18] 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 524fdf53d6b7e..e0e688434dce5 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 6611ce30a1b01..d9141eab5919f 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 08/18] 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 300bfa32ecbd6..7552c7b7e808e 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 5d69135057708..624f99335455f 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 25afc315628e3..d1435b55946c1 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 025b51a5cf51a..54b9c9cbfdb0e 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 09/18] 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 d586f913335e0..1078757d09e9d 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 72600225e7a38..2acc4ded5d803 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 17071ff8a5bef6e0f801e7d6b73529d0e1053b81 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 15 Feb 2025 21:49:50 +0000 Subject: [PATCH 10/18] 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 b7e2510e035ac..df79da76bcea6 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 9c19f8b3ad825..54f9e82dbb82d 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 0000000000000..9545a9eed2f13 --- /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 0000000000000..9a5dd711c68e0 --- /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 11/18] 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 af23c8b2ea76d..862f78d725982 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 ed4903017f353..2de55e38052e3 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 2d74fcff415ed..ab6aafab446bb 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 72cd9c224f648..b4f6fa514a487 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 e8d86bad98735..34074a84e28b6 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 ec40fac2894eb..827dc6ac7aefe 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 0000000000000..f090795e88656 --- /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 0000000000000..5cbd242986f52 --- /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 12/18] 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 45797c1276c58..411ab07bbe14a 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 13/18] 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 411ab07bbe14a..1e84a7deff12e 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 0000000000000..006dfe7e5d7b3 --- /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 14/18] 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 33cf2af30b954..69ad7239954ac 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 15/18] 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 71bad213576c7..8a806b10d9da1 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 e68e19c4dc99e..188f4985ded56 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 16/18] 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 479327d63695c..84cf99b55402a 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 dedcc139ae198..23bb47dcc5863 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 ecec589fc32eb..52876c3fb3fd7 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 75195b57db1e44d6c96daac67b3c778135374679 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 13 May 2024 20:32:33 +0200 Subject: [PATCH 17/18] Optimize `Seek::stream_len` impl for `File` It uses the file metadata on Unix with a fallback for files incorrectly reported as zero-sized. It uses `GetFileSizeEx` on Windows. This reduces the number of syscalls needed for determining the file size of an open file from 3 to 1. --- library/std/src/fs.rs | 35 +++++++++++++++++++ library/std/src/io/mod.rs | 24 +++++++------ library/std/src/sys/pal/hermit/fs.rs | 4 +++ library/std/src/sys/pal/solid/fs.rs | 4 +++ library/std/src/sys/pal/unix/fs.rs | 9 +++++ library/std/src/sys/pal/unsupported/fs.rs | 4 +++ library/std/src/sys/pal/wasi/fs.rs | 4 +++ .../std/src/sys/pal/windows/c/bindings.txt | 1 + .../std/src/sys/pal/windows/c/windows_sys.rs | 1 + library/std/src/sys/pal/windows/fs.rs | 8 +++++ 10 files changed, 84 insertions(+), 10 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 83b009c86dc08..0ae4018ca5b40 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1226,9 +1226,38 @@ impl Write for &File { } #[stable(feature = "rust1", since = "1.0.0")] impl Seek for &File { + /// Seek to an offset, in bytes in a file. + /// + /// See [`Seek::seek`] docs for more info. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `lseek64` function on Unix + /// and the `SetFilePointerEx` function on Windows. Note that this [may + /// change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior fn seek(&mut self, pos: SeekFrom) -> io::Result { self.inner.seek(pos) } + + /// Returns the length of this file (in bytes). + /// + /// See [`Seek::stream_len`] docs for more info. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `statx` function on Linux + /// (with fallbacks) and the `GetFileSizeEx` function on Windows. Note that + /// this [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + fn stream_len(&mut self) -> io::Result { + if let Some(result) = self.inner.size() { + return result; + } + io::stream_len_default(self) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1275,6 +1304,9 @@ impl Seek for File { fn seek(&mut self, pos: SeekFrom) -> io::Result { (&*self).seek(pos) } + fn stream_len(&mut self) -> io::Result { + (&*self).stream_len() + } } #[stable(feature = "io_traits_arc", since = "1.73.0")] @@ -1321,6 +1353,9 @@ impl Seek for Arc { fn seek(&mut self, pos: SeekFrom) -> io::Result { (&**self).seek(pos) } + fn stream_len(&mut self) -> io::Result { + (&**self).stream_len() + } } impl OpenOptions { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 980ea1478e084..32a98f2c47aae 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2051,16 +2051,7 @@ pub trait Seek { /// ``` #[unstable(feature = "seek_stream_len", issue = "59359")] fn stream_len(&mut self) -> Result { - let old_pos = self.stream_position()?; - let len = self.seek(SeekFrom::End(0))?; - - // Avoid seeking a third time when we were already at the end of the - // stream. The branch is usually way cheaper than a seek operation. - if old_pos != len { - self.seek(SeekFrom::Start(old_pos))?; - } - - Ok(len) + stream_len_default(self) } /// Returns the current seek position from the start of the stream. @@ -2121,6 +2112,19 @@ pub trait Seek { } } +pub(crate) fn stream_len_default(self_: &mut T) -> Result { + let old_pos = self_.stream_position()?; + let len = self_.seek(SeekFrom::End(0))?; + + // Avoid seeking a third time when we were already at the end of the + // stream. The branch is usually way cheaper than a seek operation. + if old_pos != len { + self_.seek(SeekFrom::Start(old_pos))?; + } + + Ok(len) +} + /// Enumeration of possible methods to seek within an I/O object. /// /// It is used by the [`Seek`] trait. diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index 783623552bb17..2eb659941ab7a 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -425,6 +425,10 @@ impl File { Err(Error::from_raw_os_error(22)) } + pub fn size(&self) -> Option> { + None + } + pub fn duplicate(&self) -> io::Result { Err(Error::from_raw_os_error(22)) } diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index cc424141ea80c..393231c18f931 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -465,6 +465,10 @@ impl File { } } + pub fn size(&self) -> Option> { + None + } + pub fn duplicate(&self) -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 00cfa7a7fcfda..53d394b86e385 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1438,6 +1438,15 @@ impl File { Ok(n as u64) } + pub fn size(&self) -> Option> { + match self.file_attr().map(|attr| attr.size()) { + // Fall back to default implementation if the returned size is 0, + // we might be in a proc mount. + Ok(0) => None, + result => Some(result), + } + } + pub fn duplicate(&self) -> io::Result { self.0.duplicate().map(File) } diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/pal/unsupported/fs.rs index 9585ec24f687d..0d661a87cdc65 100644 --- a/library/std/src/sys/pal/unsupported/fs.rs +++ b/library/std/src/sys/pal/unsupported/fs.rs @@ -258,6 +258,10 @@ impl File { self.0 } + pub fn size(&self) -> io::Result { + self.0 + } + pub fn duplicate(&self) -> io::Result { self.0 } diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index faf3edd5da6ce..dcefeb2b75955 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -517,6 +517,10 @@ impl File { self.fd.seek(pos) } + pub fn size(&self) -> Option> { + None + } + pub fn duplicate(&self) -> io::Result { // https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup unsupported() diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index e2c2163327968..d8ef709f8cf56 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2156,6 +2156,7 @@ GetExitCodeProcess GetFileAttributesW GetFileInformationByHandle GetFileInformationByHandleEx +GetFileSizeEx GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 1d0e89f5d0f0e..489210cc503c5 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -44,6 +44,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, lpfilesize : *mut i64) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE); windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 62d4d727432c3..22622cf27766f 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -631,6 +631,14 @@ impl File { Ok(newpos as u64) } + pub fn size(&self) -> Option> { + let mut result = 0; + Some( + cvt(unsafe { c::GetFileSizeEx(self.handle.as_raw_handle(), &mut result) }) + .map(|_| result as u64), + ) + } + pub fn duplicate(&self) -> io::Result { Ok(Self { handle: self.handle.try_clone()? }) } From a5299856060237676f744c9304f6167148103669 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 9 Jan 2025 10:31:03 +0100 Subject: [PATCH 18/18] Clarify description of `Seek::stream_len` It can only describe the inner workings of the default implementation, other implementations might not be implemented using seeks at all. --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 32a98f2c47aae..7d40094c0c1e9 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2017,7 +2017,7 @@ pub trait Seek { /// Returns the length of this stream (in bytes). /// - /// This method is implemented using up to three seek operations. If this + /// The default implementation uses up to three seek operations. If this /// method returns successfully, the seek position is unchanged (i.e. the /// position before calling this method is the same as afterwards). /// However, if this method returns an error, the seek position is